Crate ambassador
source · [−]Expand description
Ambassador - Delegate trait implementations via procedural macros
Delegating the implementation of traits to enum variants or fields of a struct normally requires a lot of boilerplate code. Ambassador is an attempt to eliminate that boilerplate by deriving the delegating trait implementation via procedural macros.
The minimum supported Rust version is 1.53.0.
See individual macro documentation for detailed instructions.
This is one example combining a large number of features:
extern crate ambassador;
use std::collections::{HashMap, BTreeMap};
use std::borrow::Borrow;
use std::cmp::{Eq, Ord};
use std::hash::{Hash, BuildHasher};
use std::ops::Deref;
use ambassador::{delegatable_trait, delegate_remote, delegate_to_remote_methods, Delegate};
#[delegatable_trait]
pub trait Map {
type K;
type V;
}
#[delegatable_trait]
pub trait Get<Q: ?Sized>: Map {
fn get(&self, k: &Q) -> Option<&Self::V>;
}
impl<K, V, S> Map for HashMap<K, V, S> {
type K = K;
type V = V;
}
impl<K, V> Map for BTreeMap<K, V> {
type K = K;
type V = V;
}
// No automatic where clause provided for target = "self"
#[delegate_remote]
#[delegate(Get<X>, target = "self", generics = "X", where = "K: Hash + Eq + Borrow<X>, S: BuildHasher, X: Hash + Eq + ?Sized")]
struct HashMap<K, V, S>();
#[delegate_remote]
#[delegate(Get<X>, target = "self", generics = "X", where = "K: Ord + Borrow<X>, X: Ord + ?Sized")]
struct BTreeMap<K, V>();
#[derive(Delegate)]
#[delegate(Map)]
#[delegate(Get<X>, generics = "X", where = "X: ?Sized, B: Map<K=A::K, V=A::V>")] //auto where clause misses required on super trait
pub enum Either<A, B> {
Left(A),
Right(B),
}
#[delegate_to_remote_methods]
#[delegate(Map, target_ref = "deref")]
impl<M: ?Sized + Map> Map for Box<M> {
fn deref(&self) -> &M;
}
fn takes_map(_m: &impl Map<K = &'static str, V = u32>) { }
pub fn main() {
let my_map: Either<HashMap<&'static str, u32>, BTreeMap<&'static str, u32>> = Either::Left([("a", 1)].into());
assert_eq!(my_map.get("a"), Some(&1));
let boxed: Box<dyn Map<K = &'static str, V = u32>> = Box::new(my_map);
takes_map(&boxed);
}
Backwards Compatibility
Since delegateable traits from one crate can be used in anther crate backwards compatibility of switching to 0.3.x depends on the use case
Self Contained Crate
Switching to 0.3.x should just work, in this case it safe to disable the “backward_compatible” feature
Library with public delegatable traits
Make sure use the “backward_compatible” feature (enabled by default), this makes sure users of your library using an older version of ambassador aren’t affected by the upgrade
Users of a library with public delegatable traits
Try to use the same version of ambassador as the library you’re using
Attribute Macros
Make a trait available for delegation
Make an existing trait that lives outside you crate available for delegation.
Make an existing type that lives outside you crate delegate traits to it’s members
Delegate the implementation of a trait to a type’s methods by adding #[delegate_to_methods]
and its associated attribute #[delegate(Trait)]
to the relevant impl block
Delegate the implementation of a trait to methods on a type that are defined elsewhere.
Derive Macros
Delegate the implementation of a trait to a struct field/enum variants by adding #[derive(Delegate)]
and its associated attribute #[delegate(Trait)]
to it: