Skip to content

Instantly share code, notes, and snippets.

@andreivasiliu
Last active June 22, 2019 20:46
Show Gist options
  • Save andreivasiliu/db5fe3090df9530a476a1ac2cd244bfd to your computer and use it in GitHub Desktop.
Save andreivasiliu/db5fe3090df9530a476a1ac2cd244bfd to your computer and use it in GitHub Desktop.
Multi-Loader/Provider
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();
}
// -- 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());
}
// -- 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