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 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 V = V;
}
impl<K, V> Map for BTreeMap<K, V> {
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<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")]
#[delegate(Get<X>, target_ref = "deref", generics = "X", where = "X: ?Sized")]
impl<M: ?Sized> Box<M> {
fn deref(&self) -> &M;
}
pub fn main() {
let x: HashMap<&'static str, u32> = [("a", 1)].into();
let my_map: Either<Box<dyn Get<str, V = u32>>, BTreeMap<&'static str, u32>> = Either::Left(Box::new(x));
assert_eq!(my_map.get("a"), Some(&1));
}
§Cross module uses
Modules using delegateable traits should add use <MODULE PATH>::ambassador_impl_<TRAIT NAME>;
where <MODULE PATH>
is the path to the module which used either
delegatable_trait
or delegatable_trait_remote
§Example
mod m{
pub mod m1 {
use ambassador::delegatable_trait;
#[delegatable_trait]
pub trait Shout {
fn shout(&self);
}
}
mod m2 {
use ambassador::Delegate;
use super::m1::{Shout, ambassador_impl_Shout};
#[derive(Delegate)]
#[delegate(Shout)]
struct Wrap<X>(X);
}
}
§Backwards Compatibility
§0.3.x -> 0.4.x
§Creating delegateable traits
Delagatable trait macros ambassador_impl_Trait
are no longer exported at the crate root, and
are instead exported in the module where delegatable_trait
or
delegatable_trait_remote
are used. If these traits are public then upgrading is also
a breaking change for users of your library. The “backward_compatible” is also removed.
§Using delegateable traits
Switching versions does not affect usages of delegateable traits
§0.2.x -> 0.3.x
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: