#[macro_export]
macro_rules! impl_as_ref {
($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
fn as_ref(&self) -> &$inner {
&self.0
}
}
};
($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
fn as_ref(&self) -> &$inner {
&self.$field
}
}
};
}
#[macro_export]
macro_rules! forward_as_ref {
(<$($generic:ident),+> in $this:ty => $target:ty) => {
impl <$($generic),+> ::core::convert::AsRef<$target> for $this {
fn as_ref(&self) -> &$target {
::core::convert::AsRef::<$target>::as_ref(&self.0)
}
}
};
(<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
impl <$($generic),+> ::core::convert::AsRef<$target> for $this {
fn as_ref(&self) -> &$target {
::core::convert::AsRef::<$target>::as_ref(&self.$field)
}
}
};
($this:ty => $target:ty) => {
impl ::core::convert::AsRef<$target> for $this {
fn as_ref(&self) -> &$target {
::core::convert::AsRef::<$target>::as_ref(&self.0)
}
}
};
($this:ty => $field:ident : $target:ty) => {
impl ::core::convert::AsRef<$target> for $this {
fn as_ref(&self) -> &$target {
::core::convert::AsRef::<$target>::as_ref(&self.$field)
}
}
};
}
#[macro_export]
macro_rules! impl_as_mut {
($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
fn as_mut(&mut self) -> &mut $inner {
&mut self.0
}
}
};
($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
fn as_mut(&mut self) -> &mut $inner {
&mut self.$field
}
}
};
}
#[macro_export]
macro_rules! forward_as_mut {
(<$($generic:ident),+> in $this:ty => $target:ty) => {
impl <$($generic),+> ::core::convert::AsMut<$target> for $this {
fn as_mut(&mut self) -> &mut $target {
::core::convert::AsMut::<$target>::as_mut(&mut self.0)
}
}
};
(<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
impl <$($generic),+> ::core::convert::AsMut<$target> for $this {
fn as_mut(&mut self) -> &mut $target {
::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
}
}
};
($this:ty => $target:ty) => {
impl ::core::convert::AsMut<$target> for $this {
fn as_mut(&mut self) -> &mut $target {
::core::convert::AsMut::<$target>::as_mut(&mut self.0)
}
}
};
($this:ty => $field:ident : $target:ty) => {
impl ::core::convert::AsMut<$target> for $this {
fn as_mut(&mut self) -> &mut $target {
::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
}
}
};
}
#[macro_export]
macro_rules! forward_as_ref_and_mut {
(<$($generic:ident),+> in $this:ty => $target:ty) => {
$crate::forward_as_ref!(<$($generic),+> in $this => $target);
$crate::forward_as_mut!(<$($generic),+> in $this => $target);
};
(<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
$crate::forward_as_ref!(<$($generic),+> in $this => $field: $target);
$crate::forward_as_mut!(<$($generic),+> in $this => $field: $target);
};
($this:ty => $target:ty) => {
$crate::forward_as_ref!($this => $target);
$crate::forward_as_mut!($this => $target);
};
($this:ty => $field:ident : $target:ty) => {
$crate::forward_as_ref!($this => $field: $target);
$crate::forward_as_mut!($this => $field: $target);
};
}
#[cfg(test)]
mod tests {
use alloc::{string::String, vec, vec::Vec};
struct Newtype(String);
forward_as_ref!(Newtype => str);
forward_as_mut!(Newtype => str);
struct Generic<T>(Vec<T>);
forward_as_ref!(<T> in Generic<T> => [T]);
forward_as_mut!(<T> in Generic<T> => [T]);
struct GenericNamed<T> {
inner: Vec<T>,
}
forward_as_ref_and_mut!(<T> in GenericNamed<T> => inner: [T]);
static_assertions::assert_impl_all!(Newtype: AsRef<str>, AsMut<str>);
static_assertions::assert_impl_all!(Generic<usize>: AsRef<[usize]>, AsMut<[usize]>);
static_assertions::assert_impl_all!(GenericNamed<usize>: AsRef<[usize]>, AsMut<[usize]>);
#[test]
fn forwards_newtype() {
let mut value = Newtype("hello".into());
AsMut::<str>::as_mut(&mut value).make_ascii_uppercase();
assert_eq!(AsRef::<str>::as_ref(&value), "HELLO");
}
#[test]
fn forwards_generic_newtype() {
let mut value = Generic(vec![1, 2, 3]);
AsMut::<[usize]>::as_mut(&mut value).reverse();
assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
}
#[test]
fn forwards_generic_named_field() {
let mut value = GenericNamed {
inner: vec![1, 2, 3],
};
AsMut::<[usize]>::as_mut(&mut value).reverse();
assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
}
}