Last active
June 22, 2019 20:46
-
-
Save andreivasiliu/db5fe3090df9530a476a1ac2cd244bfd to your computer and use it in GitHub Desktop.
Multi-Loader/Provider
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Loader<D, V> { | |
dns: D, | |
vma: V, | |
} | |
fn new_loader() -> Loader<(), ()> { | |
Loader { | |
dns: (), | |
vma: (), | |
} | |
} | |
impl<V> Loader<(), V> { | |
fn with_dns(self) -> Loader<DNSResolver, V> { | |
Loader { | |
dns: DNSResolver { stuff: () }, | |
vma: self.vma, | |
} | |
} | |
} | |
struct DNSResolver { | |
stuff: () | |
} | |
impl<V> DNS for Loader<DNSResolver, V> { | |
fn resolve_ips(&self, _domain: &str) { | |
self.dns.stuff | |
} | |
} | |
trait OMC { | |
} | |
trait VMA { | |
} | |
trait DNS { | |
fn resolve_ips(&self, domain: &str); | |
} | |
// Add Cache | |
struct Website<L> { | |
name: String, | |
loader: L, | |
} | |
impl<L> Website<L> | |
where | |
L: DNS | |
{ | |
fn ips(self) { | |
self.loader.resolve_ips(&self.name) | |
} | |
} | |
fn main() { | |
let loader = new_loader().with_dns(); | |
let website = Website { name: "hello.".into(), loader }; | |
website.ips(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- common lib | |
trait Provider<T> { | |
fn provide(&self) -> &T; | |
fn provide_mut(&mut self) -> &mut T; | |
} | |
// -- 3rd party traits | |
struct IPs; | |
trait DNS { | |
fn resolve_dns(&self, domain: &str) -> IPs; | |
} | |
trait VMA { | |
fn resolve_vma(&self, ip: IPs) -> (); | |
} | |
// -- 3rd party possible implementations | |
struct StandardVMA; | |
impl VMA for StandardVMA { | |
fn resolve_vma(&self, ip: IPs) -> () { | |
() | |
} | |
} | |
struct StandardDNS; | |
impl DNS for StandardDNS { | |
fn resolve_dns(&self, _domain: &str) -> IPs { | |
IPs { } | |
} | |
} | |
struct MockDNS; | |
impl DNS for MockDNS { | |
fn resolve_dns(&self, _domain: &str) -> IPs { | |
IPs { } | |
} | |
} | |
// -- 3rd party utility stuff | |
trait DnsVmaCombiner<T, D, V> { | |
fn resolve_vma_from_dns(&self, _domain: &str) -> (); | |
} | |
impl<D: DNS, V: VMA, T: Provider<D> + Provider<V>> DnsVmaCombiner<T, D, V> for T | |
{ | |
fn resolve_vma_from_dns(&self, domain: &str) -> () { | |
let ips = Provider::<D>::provide(self).resolve_dns(domain); | |
Provider::<V>::provide(self).resolve_vma(ips) | |
} | |
} | |
// -- custom user-made provider | |
// Auto-generate the below traits with: | |
// #[derive(Provider)] | |
// #[provide(vma: VMA, dns: DNS)] | |
struct MyProvider { | |
vma: StandardVMA, | |
dns: StandardDNS, | |
} | |
impl Provider<StandardVMA> for MyProvider { | |
fn provide(&self) -> &StandardVMA { | |
&self.vma | |
} | |
fn provide_mut(&mut self) -> &mut StandardVMA { | |
&mut self.vma | |
} | |
} | |
impl Provider<StandardDNS> for MyProvider { | |
fn provide(&self) -> &StandardDNS { | |
&self.dns | |
} | |
fn provide_mut(&mut self) -> &mut StandardDNS { | |
&mut self.dns | |
} | |
} | |
fn main() { | |
// User instantiates whatever providers it wants: | |
#[cfg(not(test))] | |
let dns = StandardDNS { }; // or ::new() with whatever runtime parameters the provider needs here | |
#[cfg(test)] | |
let dns = MockDNS { }; | |
let vma = StandardVMA { }; | |
// Combines them into a single object: | |
let provider = MyProvider { vma, dns }; | |
// The traits have to be brought into scope (if not already) | |
// use ::DnsVmaCombiner; | |
// Can be used directly: | |
let () = DnsVmaCombiner::<MyProvider, StandardDNS, StandardVMA>::resolve_vma_from_dns(&provider, "domain"); | |
// Can be used by glue objects like Website<P: Provider> | |
// let website = Website::with_provider("domain", provider); | |
// println("{}: {}", website.name(), website.ips()); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- common lib | |
trait Provider<T> { | |
fn provide(&self) -> &T; | |
fn provide_mut(&mut self) -> &mut T; | |
} | |
// -- 3rd party traits | |
#[derive(Debug)] | |
struct IPs; | |
trait DNS { | |
fn resolve_dns(&self, domain: &str) -> IPs; | |
} | |
trait VMA { | |
fn resolve_vma(&self, ip: IPs) -> (); | |
} | |
// -- 3rd party possible implementations | |
struct StandardVMA; | |
impl VMA for StandardVMA { | |
fn resolve_vma(&self, _ip: IPs) -> () { | |
() | |
} | |
} | |
struct StandardDNS; | |
impl DNS for StandardDNS { | |
fn resolve_dns(&self, _domain: &str) -> IPs { | |
IPs { } | |
} | |
} | |
#[cfg(test)] | |
struct MockDNS; | |
#[cfg(test)] | |
impl DNS for MockDNS { | |
fn resolve_dns(&self, _domain: &str) -> IPs { | |
IPs { } | |
} | |
} | |
// -- 3rd party utility stuff | |
trait DnsVmaCombiner<T, D, V> { | |
fn resolve_vma_from_dns(&self, _domain: &str) -> (); | |
} | |
impl<D, V, T> DnsVmaCombiner<T, D, V> for T | |
where | |
T: Provider<D> + Provider<V>, | |
D: DNS, V: VMA, | |
{ | |
fn resolve_vma_from_dns(&self, domain: &str) -> () { | |
let ips = Provider::<D>::provide(self).resolve_dns(domain); | |
Provider::<V>::provide(self).resolve_vma(ips) | |
} | |
} | |
// -- glue objects | |
struct Website<P, D> { | |
name: String, | |
provider: P, | |
_dns: std::marker::PhantomData<D>, | |
} | |
impl<P, D> Website<P, D> | |
where | |
D: DNS, | |
P: Provider<D>, | |
{ | |
fn ips(&self) -> IPs { | |
self.provider.provide().resolve_dns(&self.name) | |
} | |
} | |
// -- custom user-made provider | |
// Auto-generate the below traits with: | |
// #[derive(Provider)] | |
// #[provide(vma: VMA, dns: DNS)] | |
struct MyProvider { | |
vma: StandardVMA, | |
dns: StandardDNS, | |
} | |
impl Provider<StandardVMA> for MyProvider { | |
fn provide(&self) -> &StandardVMA { | |
&self.vma | |
} | |
fn provide_mut(&mut self) -> &mut StandardVMA { | |
&mut self.vma | |
} | |
} | |
impl Provider<StandardDNS> for MyProvider { | |
fn provide(&self) -> &StandardDNS { | |
&self.dns | |
} | |
fn provide_mut(&mut self) -> &mut StandardDNS { | |
&mut self.dns | |
} | |
} | |
fn main() { | |
// User instantiates whatever providers it wants: | |
#[cfg(not(test))] | |
let dns = StandardDNS { }; // or ::new() with whatever runtime parameters the provider needs here | |
#[cfg(test)] | |
let dns = MockDNS { }; | |
let vma = StandardVMA { }; | |
// Combines them into a single object: | |
let provider = MyProvider { vma, dns }; | |
// The traits have to be brought into scope (if not already) | |
// use ::DnsVmaCombiner; | |
// Can be used directly: | |
// let () = provider.resolve_vma_from_dns("domain"); // oh no! doesn't work! :( | |
let () = DnsVmaCombiner::<MyProvider, StandardDNS, StandardVMA>::resolve_vma_from_dns(&provider, "domain"); | |
// Can be used by glue objects like Website<P: Provider> | |
let website = Website { | |
name: "domain".to_owned(), | |
provider, | |
_dns: std::marker::PhantomData::default(), | |
}; | |
println!("{}: {:?}", website.name, website.ips()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment