#[delegate]Expand description
Derives trait on a new-type struct or enum, invoking it on its inner type.
§Example
#[delegate(derive(AsString))]
enum Name {
First(FirstName),
Last(LastName),
}
#[delegate(derive(AsString))]
struct FirstName(String);
#[delegate]
struct LastName(String);
#[delegate(for(LastName))]
trait AsString {
fn into_string(self) -> String;
fn as_str(&self) -> &str;
fn as_mut_str(&mut self) -> &mut String;
}
impl AsString for String {
fn into_string(self) -> Self {
self
}
fn as_str(&self) -> &str {
self.as_str()
}
fn as_mut_str(&mut self) -> &mut Self {
self
}
}
let mut name = Name::First(FirstName("John".into()));
assert_eq!(name.as_str(), "John");
name.as_mut_str().push_str("ny");
assert_eq!(name.as_str(), "Johnny");
assert_eq!(name.into_string(), "Johnny");§Generics
In some cases, a trait or a type requires additional generic parameters to
implement delegation. For this case, macro provides for<..> and where
syntax for #[delegate(derive(..))] and #[delegate(for(..))] attribute
arguments. Specified generics will replace existing, provided by the
trait/type definition. To remove generics when all types are known use
for<>.
#[delegate]
trait AsInner<T: ?Sized> {
fn as_inner(&self) -> &T;
}
impl AsInner<str> for String {
fn as_inner(&self) -> &str {
self
}
}
#[delegate(derive(for<> AsInner<str>))]
struct FirstName(String);
#[delegate(derive(
for<I> AsInner<str>
where
I: AsInner<str> + 'static;
))]
struct NickName<I>(I);
let first = FirstName("John".into());
assert_eq!(first.as_inner(), "John");
let last = NickName::<FirstName>(first);
assert_eq!(last.as_inner(), "John");§External types
Because the both sides of the delegation should be marked with the
#[delegate] attribute, it’s impossible to make external type delegatable.
To handle this, the macro provides the #[delegate(as = my::Def)]
attribute argument for struct fields and enum variants. It uses the provided
type as known declaration of some external type. Provided type should be
crate-local, and marked with the #[delegate] macro, and to provide an
infallible conversion from external type (including reference-to-reference
one).
#[delegate]
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
#[delegate(derive(AsStr))]
enum EitherDef {
Left(String),
Right(String),
}
impl<'a> From<&'a mut Either<String, String>> for &'a mut EitherDef {
fn from(t: &'a mut Either<String, String>) -> Self {
#[expect(unsafe_code, reason = "macro expansion")]
unsafe {
&mut *(t as *mut Either<String, String> as *mut EitherDef)
}
}
}
impl<'a> From<&'a Either<String, String>> for &'a EitherDef {
fn from(t: &'a Either<String, String>) -> Self {
#[expect(unsafe_code, reason = "macro expansion")]
unsafe {
&*(t as *const Either<String, String> as *const EitherDef)
}
}
}
impl From<Either<String, String>> for EitherDef {
fn from(t: Either<String, String>) -> Self {
match t {
Either::Left(t) => EitherDef::Left(t),
Either::Right(t) => EitherDef::Right(t),
}
}
}
#[delegate(derive(AsStr))]
struct EitherString(#[delegate(as = EitherDef)] Either<String, String>);
let left = EitherString(Either::Left("left".to_string()));
let right = EitherString(Either::Right("right".to_string()));
assert_eq!(left.as_str(), "left");
assert_eq!(right.as_str(), "right");§External traits
Because the both sides of the delegation should be marked with the
#[delegate] attribute, it’s impossible to make an external trait
delegatable. To handle this, the macro provides the
#[delegate(as = my::Def)] attribute argument for traits. It uses the
provided trait as known declaration of some external trait. With this
argument, the macro will generate a wrapper type implementing the external
trait on it, with the name of the expanded “declaration” trait. By using
this wrapper type in #[delegate(derive(ext::Trait as my::TraitDef))]
argument, you can delegate external trait to your type.
#[delegate(as = AsRef)]
trait AsRefDef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
#[delegate]
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
#[delegate(as = AsStr)]
trait AsStrDef {
fn as_str(&self) -> &str;
}
#[delegate(derive(
for<> AsRef<str> as AsRefDef;
AsStr as AsStrDef;
))]
enum Name {
First(String),
}
let name = Name::First("John".to_string());
assert_eq!(name.as_ref(), "John");
assert_eq!(name.as_str(), "John");§Limitations
- Both struct/enum and trait should be marked with
#[delegate]macro attribute. - Struct or enum variant should contain only single field.
- Trait methods must have an untyped receiver.
- Supertraits or
Selftrait/method bounds except marker traits likeSized,SendorSyncare not supported yet. - Associated types/constants are not supported yet.
- Lifetimes in methods are limited to be early-bounded in some cases (see rust-lang/rust#87803).
Selftype is limited to be used in methods return types.