#[macro_export]
macro_rules! impl_deref {
(<$($generic:ident),+> in $this:ty => $target:ty) => {
impl <$($generic),+> ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
};
(<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
impl <$($generic),+> ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
};
($this:ty => $target:ty) => {
impl ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
};
($this:ty => $field:ident : $target:ty) => {
impl ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
};
}
#[macro_export]
macro_rules! impl_deref_mut {
(<$($generic:ident),+> in $this:ty) => {
impl <$($generic),+> ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
(<$($generic:ident),+> in $this:ty => $field:ident) => {
impl <$($generic),+> ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
($this:ty) => {
impl ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
($this:ty => $field:ident) => {
impl ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
}
#[macro_export]
macro_rules! impl_deref_and_mut {
(<$($generic:ident),+> in $this:ty => $target:ty) => {
impl <$($generic),+> ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl <$($generic),+> ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
(<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
impl <$($generic),+> ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
impl <$($generic),+> ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
($this:ty => $target:ty) => {
impl ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
($this:ty => $field:ident : $target:ty) => {
impl ::core::ops::Deref for $this {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
impl ::core::ops::DerefMut for $this {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
}
#[macro_export]
macro_rules! forward_deref_and_mut {
($ty:ty => $target:ty) => {
impl ::core::ops::Deref for $ty {
type Target = $target;
fn deref(&self) -> &Self::Target {
::core::ops::Deref::deref(&self.0)
}
}
impl ::core::ops::DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
::core::ops::DerefMut::deref_mut(&mut self.0)
}
}
};
($ty:ty => ref $target:ty) => {
impl<'__impl_more_a> ::core::ops::Deref for $ty {
type Target = $target;
fn deref(&self) -> &Self::Target {
::core::ops::Deref::deref(&self.0)
}
}
impl<'__impl_more_a> ::core::ops::DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
::core::ops::DerefMut::deref_mut(&mut self.0)
}
}
};
($ty:ty => $field:ident : $target:ty) => {
impl ::core::ops::Deref for $ty {
type Target = $target;
fn deref(&self) -> &Self::Target {
::core::ops::Deref::deref(&self.$field)
}
}
impl ::core::ops::DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
::core::ops::DerefMut::deref_mut(&mut self.$field)
}
}
};
($ty:ty => $field:ident : ref $target:ty) => {
impl<'__impl_more_a> ::core::ops::Deref for $ty {
type Target = $target;
fn deref(&self) -> &Self::Target {
::core::ops::Deref::deref(&self.$field)
}
}
impl<'__impl_more_a> ::core::ops::DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
::core::ops::DerefMut::deref_mut(&mut self.$field)
}
}
};
}
#[cfg(test)]
mod tests {
#![allow(dead_code)]
use alloc::{borrow::ToOwned as _, string::String};
use core::ops::{Deref, DerefMut};
fn accepts_string_slice(_: &str) {}
fn accepts_mut_string_slice(_: &mut str) {}
struct Foo1(String);
impl_deref_and_mut!(Foo1 => String);
static_assertions::assert_impl_all!(
Foo1:
Deref<Target = String>,
DerefMut<Target = String>,
);
struct Foo2(String);
forward_deref_and_mut!(Foo2 => ref str);
static_assertions::assert_impl_all!(
Foo2:
Deref,
DerefMut,
);
struct SingleGeneric<T>(T);
impl_deref!(<T> in SingleGeneric<T> => T);
impl_deref_mut!(<T> in SingleGeneric<T>);
static_assertions::assert_impl_all!(
SingleGeneric<usize>:
Deref<Target = usize>,
DerefMut<Target = usize>,
);
struct SingleGenericCombined<T>(T);
impl_deref_and_mut!(<T> in SingleGenericCombined<T> => T);
static_assertions::assert_impl_all!(
SingleGenericCombined<usize>:
Deref<Target = usize>,
DerefMut<Target = usize>,
);
struct DoubleGeneric<T, U> {
t: T,
_u: U,
}
impl_deref!(<T, U> in DoubleGeneric<T, U> => t: T);
impl_deref_mut!(<T, U> in DoubleGeneric<T, U> => t);
static_assertions::assert_impl_all!(
DoubleGeneric<usize, u32>:
Deref<Target = usize>,
DerefMut<Target = usize>,
);
struct DoubleGenericCombined<T, U> {
t: T,
_u: U,
}
impl_deref_and_mut!(<T, U> in DoubleGenericCombined<T, U> => t: T);
static_assertions::assert_impl_all!(
DoubleGenericCombined<usize, u32>:
Deref<Target = usize>,
DerefMut<Target = usize>,
);
#[test]
fn foo2_impls() {
let mut foo = Foo2("".to_owned());
accepts_string_slice(&foo);
accepts_mut_string_slice(&mut foo);
}
struct Foo3 {
msg: String,
}
forward_deref_and_mut!(Foo3 => msg: ref str);
static_assertions::assert_impl_all!(
Foo3:
Deref,
DerefMut,
);
#[test]
fn foo3_impls() {
let mut foo = Foo3 { msg: "".to_owned() };
accepts_string_slice(&foo);
accepts_mut_string_slice(&mut foo);
}
}