1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
//!
//! # Ambassador - Delegate trait implementations via procedural macros
//!
//! <!-- Crates version -->
//! <a href="https://crates.io/crates/ambassador">
//! <img src="https://img.shields.io/crates/v/ambassador.svg?style=flat-square"
//! alt="Crates.io version" />
//! </a>
//! <!-- docs.rs docs -->
//! <a href="https://docs.rs/ambassador">
//! <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
//! alt="docs.rs docs" />
//! </a>
//!
//! <br/>
//!
//!
//! 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::hash::{Hash, BuildHasher};
//! use std::cmp::{Eq, Ord};
//! use std::borrow::Borrow;
//! use ambassador::{delegatable_trait, delegate_remote, 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),
//! }
//!
//!
//! 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));
//! }
//! ```
//!
//! # 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
extern crate proc_macro;
mod derive;
mod register;
mod util;
use proc_macro::TokenStream;
use quote::quote;
use crate::register::build_register_trait;
///Delegate the implementation of a trait to a struct field/enum variants by adding `#[derive(Delegate)]` and its associated attribute `#[delegate(Trait)]` to it:
///
/// ```
/// use ambassador::{Delegate, delegatable_trait};
///
/// #[delegatable_trait]
/// pub trait Shout {
/// fn shout(&self, input: &str) -> String;
/// }
///
/// pub struct Cat;
///
/// impl Shout for Cat {
/// fn shout(&self, input: &str) -> String {
/// format!("{} - meow!", input)
/// }
/// }
///
/// #[derive(Delegate)] // <-------
/// #[delegate(Shout)] // <-------- Delegate implementation of Shout to struct field
/// pub struct WrappedCat(Cat);
/// ```
///
///#### `#[delegate(..., target = "foo")]` - `target` key
///
/// For structs with multiple fields, the field that should act as delegation target can be specified via the `target` key:
///
/// ```
/// # use ambassador::{Delegate, delegatable_trait};
/// # #[delegatable_trait]
/// # pub trait Shout {
/// # fn shout(&self, input: &str) -> String;
/// # }
/// # pub struct Cat;
/// #
/// # impl Shout for Cat {
/// # fn shout(&self, input: &str) -> String {
/// # format!("{} - meow!", input)
/// # }
/// # }
///
/// #[derive(Delegate)]
/// #[delegate(Shout, target = "foo")] // <-------- Delegate implementation of Shout to struct field .foo
/// pub struct WrappedCats {
/// foo: Cat,
/// bar: Cat,
/// }
/// ```
/// This also works for tuple structs with multiple fields, by using their index as a target key:
///
/// ```
/// # use ambassador::{Delegate, delegatable_trait};
/// # #[delegatable_trait]
/// # pub trait Shout {
/// # fn shout(&self, input: &str) -> String;
/// # }
/// # pub struct Cat;
/// #
/// # impl Shout for Cat {
/// # fn shout(&self, input: &str) -> String {
/// # format!("{} - meow!", input)
/// # }
/// # }
///
/// #[derive(Delegate)]
/// #[delegate(Shout, target = "1")] // <-------- Delegate implementation of Shout to second field
/// pub struct WrappedCats(Cat, Cat);
/// ```
///
/// #### `#[delegate(..., target = "self")]` - `target="self"`
/// Types that implement all the methods of a trait without implementing the trait itself,
/// can be made to implement that trait by setting `target="self"`.
/// This doesn't work for traits with associated types and constants, and requires the where clause to be added explicitly (see `where` key).
/// If the type doesn't actually implement the methods (possibly due to an incomplete `where` clause) this can cause a `[unconditional_recursion]` error.
///
/// A possible use case of this is when refactoring some methods of a public type into a trait,
/// the type still needs to implement the methods outside the trait for semver reasons,
/// and using this feature reduces the boilderplate of implementing the trait with the same methods.
///
///
/// ```
/// # use ambassador::{Delegate, delegatable_trait};
/// # #[delegatable_trait]
/// # pub trait Shout {
/// # fn shout(&self, input: &str) -> String;
/// # }
/// #[derive(Delegate)]
/// #[delegate(Shout, target="self")]
/// pub struct Cat;
///
/// impl Cat {
/// fn shout(&self, input: &str) -> String {
/// format!("{} - meow!", input)
/// }
/// }
/// ```
///
/// #### `#[delegate(..., where = "A: Debug")]` - `where` key
///
/// To make a delegation apply only for certain generic bounds, similar to a [native where clause](https://doc.rust-lang.org/stable/rust-by-example/generics/where.html), you can specify a `where` attribute:
///
/// A where clause is automatically applied that makes sure the target field implements the trait being delegated
/// ```
/// # use ambassador::{Delegate, delegatable_trait};
/// # #[delegatable_trait]
/// # pub trait Shout {
/// # fn shout(&self, input: &str) -> String;
/// # }
/// use std::fmt::Debug;
///
/// #[derive(Delegate)]
/// #[delegate(Shout, where = "A: Debug")] // <---- Delegate implementation of Shout to .foo field if foo field implements Debug
/// // "A: Shout" is automatically added
/// pub struct WrappedFoo<A> {
/// foo: A,
/// }
/// ```
///
///
/// #### `#[delegate(Shout<X>, generics = "X")]` - trait generics
///
/// We can also delegate traits with generics.
/// The type parameters listed in the `generics` key are treated as fully generic.
/// The automatically added where clause ensures they are valid for the inner type being delegated to.
/// Explict where clauses to further refine these types can be added as normal.
///
/// ```
/// use ambassador::{delegatable_trait, Delegate};
/// use std::fmt::Display;
///
/// #[delegatable_trait]
/// pub trait Shout<T> {
/// fn shout(&self, input: T) -> String;
/// }
///
/// pub struct Cat;
///
/// impl<T: Display> Shout<T> for Cat {
/// fn shout(&self, input: T) -> String {
/// format!("{} - meow!", input)
/// }
/// }
///
/// #[derive(Delegate)]
/// #[delegate(Shout<X>, generics = "X")] // <-------- `X` is fully generic
/// // The automatic where clause ensures X: Display
/// // We could also use #[delegate(Shout<& 'a str>, generics = "'a")] to only delegate for &str
/// pub struct WrappedCat(Cat);
/// ```
#[proc_macro_derive(Delegate, attributes(delegate))]
pub fn delegate_macro(input: TokenStream) -> TokenStream {
derive::delegate_macro(input)
}
/// Make an existing type that lives outside you crate delegate traits to it's members
///
/// This can be done by copy-pasting it's definition into your code under this attribute.
///
/// If the type is a struct, not all the fields have to be public, only the ones being delegated to.
///
/// ```
/// use ambassador::{delegate_remote, delegatable_trait};
///
/// #[delegatable_trait]
/// pub trait Shout {
/// fn shout(&self, input: &str) -> String;
/// }
///
/// pub struct Cat;
///
/// impl Shout for Cat {
/// fn shout(&self, input: &str) -> String {
/// format!("{} - meow!", input)
/// }
/// }
///
/// mod wrapped {
/// pub struct WrappedAnimals<A, B> {
/// pub foo: A,
/// pub bar: B,
/// baz: u32, // private field
/// }
/// }
///
/// use wrapped::*;
///
/// #[delegate_remote]
/// #[delegate(Shout, target = "bar")]
/// struct WrappedAnimals<A, B> {
/// foo: A,
/// bar: B,
/// // We don't even have to include baz since we don't delegate to it
/// }
/// ```
#[proc_macro_attribute]
pub fn delegate_remote(_attr: TokenStream, input: TokenStream) -> TokenStream {
derive::delegate_macro(input)
}
/// Make a trait available for delegation
///
/// This also makes your trait delegatable in other crates:
///
/// ```
/// use ambassador::delegatable_trait;
///
/// #[delegatable_trait] // <-------
/// pub trait Shout {
/// fn shout(&self, input: &str) -> String;
/// }
/// ```
#[proc_macro_attribute]
pub fn delegatable_trait(_attr: TokenStream, item: TokenStream) -> TokenStream {
let original_item: syn::ItemTrait = syn::parse(item).unwrap();
let register_trait = build_register_trait(&original_item);
let expanded = quote! {
#original_item
#register_trait
};
TokenStream::from(expanded)
}
/// Make an existing trait that lives outside you crate available for delegation.
///
/// This can be done by copy-pasting the existing traits signature into your code under this attribute
///
/// ```
/// use ambassador::{Delegate, delegatable_trait_remote};
/// use std::fmt::Display;
///
/// #[delegatable_trait_remote]
/// trait Display {
/// fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>;
/// }
///
/// struct Cat;
///
/// impl Display for Cat {
/// fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>{
/// f.write_str("Cat")
/// }
/// }
///
/// #[derive(Delegate)]
/// #[delegate(Display)] // <-------- Delegate implementation of Display to struct field
/// pub struct WrappedCat(Cat);
/// ```
#[proc_macro_attribute]
pub fn delegatable_trait_remote(_attr: TokenStream, item: TokenStream) -> TokenStream {
let original_item: syn::ItemTrait = syn::parse(item).unwrap();
let register_trait = build_register_trait(&original_item);
let expanded = quote! {
#register_trait
};
TokenStream::from(expanded)
}