Skip to main content

impl_more/
as_ref.rs

1/// Implement [`AsRef`] for a struct.
2///
3/// The first argument is that of the struct to create the impl for and the second is the type to
4/// produce a reference for.
5///
6/// # Examples
7/// With a newtype struct:
8/// ```
9/// use impl_more::impl_as_ref;
10///
11/// struct Foo(String);
12/// impl_as_ref!(Foo => String);
13/// let foo = Foo("bar".to_owned());
14/// assert_eq!(foo.as_ref(), "bar");
15/// ```
16///
17/// With a named field struct and type parameters:
18/// ```
19/// use impl_more::impl_as_ref;
20///
21/// struct Foo<T> { inner: T }
22/// impl_as_ref!(Foo<T> => inner: T);
23/// let foo = Foo { inner: "bar".to_owned() };
24/// assert_eq!(foo.as_ref().as_str(), "bar");
25/// ```
26#[macro_export]
27macro_rules! impl_as_ref {
28    ($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
29        impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
30            fn as_ref(&self) -> &$inner {
31                &self.0
32            }
33        }
34    };
35
36    ($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
37        impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
38            fn as_ref(&self) -> &$inner {
39                &self.$field
40            }
41        }
42    };
43}
44
45/// Implement [`AsRef`] by forwarding to a field's implementation.
46///
47/// The first argument is the struct to create the impl for and the second is the target type
48/// produced by the field's [`AsRef`] implementation.
49///
50/// # Examples
51/// With a newtype struct:
52/// ```
53/// use impl_more::forward_as_ref;
54///
55/// struct Foo(String);
56/// forward_as_ref!(Foo => str);
57///
58/// let foo = Foo("bar".to_owned());
59/// assert_eq!(foo.as_ref(), "bar");
60/// ```
61///
62/// With a named field struct and type parameters:
63/// ```
64/// use impl_more::forward_as_ref;
65///
66/// struct Foo<T> { inner: Vec<T> }
67/// forward_as_ref!(<T> in Foo<T> => inner: [T]);
68///
69/// let foo = Foo { inner: vec![1, 2, 3] };
70/// assert_eq!(foo.as_ref(), &[1, 2, 3]);
71/// ```
72#[macro_export]
73macro_rules! forward_as_ref {
74    (<$($generic:ident),+> in $this:ty => $target:ty) => {
75        impl <$($generic),+> ::core::convert::AsRef<$target> for $this {
76            fn as_ref(&self) -> &$target {
77                ::core::convert::AsRef::<$target>::as_ref(&self.0)
78            }
79        }
80    };
81
82    (<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
83        impl <$($generic),+> ::core::convert::AsRef<$target> for $this {
84            fn as_ref(&self) -> &$target {
85                ::core::convert::AsRef::<$target>::as_ref(&self.$field)
86            }
87        }
88    };
89
90    ($this:ty => $target:ty) => {
91        impl ::core::convert::AsRef<$target> for $this {
92            fn as_ref(&self) -> &$target {
93                ::core::convert::AsRef::<$target>::as_ref(&self.0)
94            }
95        }
96    };
97
98    ($this:ty => $field:ident : $target:ty) => {
99        impl ::core::convert::AsRef<$target> for $this {
100            fn as_ref(&self) -> &$target {
101                ::core::convert::AsRef::<$target>::as_ref(&self.$field)
102            }
103        }
104    };
105}
106
107/// Implement [`AsMut`] for a struct.
108///
109/// The first argument is that of the struct to create the impl for and the second is the type to
110/// produce a reference for.
111///
112/// # Examples
113/// With a newtype struct:
114/// ```
115/// use impl_more::{impl_as_ref, impl_as_mut};
116///
117/// struct Foo(String);
118///
119/// impl_as_ref!(Foo => String);
120/// impl_as_mut!(Foo => String);
121///
122/// let mut foo = Foo("bar".to_owned());
123/// foo.as_mut().push('!');
124///
125/// assert_eq!(foo.as_ref(), "bar!");
126/// ```
127///
128/// With a named field struct and type parameters:
129/// ```
130/// use impl_more::{impl_as_ref, impl_as_mut};
131///
132/// struct Foo<T> { inner: T }
133///
134/// impl_as_ref!(Foo<T> => inner: T);
135/// impl_as_mut!(Foo<T> => inner: T);
136///
137/// let mut foo = Foo { inner: "bar".to_owned() };
138/// foo.as_mut().push('!');
139///
140/// assert_eq!(foo.as_ref(), "bar!");
141/// ```
142#[macro_export]
143macro_rules! impl_as_mut {
144    ($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
145        impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
146            fn as_mut(&mut self) -> &mut $inner {
147                &mut self.0
148            }
149        }
150    };
151
152    ($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
153        impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
154            fn as_mut(&mut self) -> &mut $inner {
155                &mut self.$field
156            }
157        }
158    };
159}
160
161/// Implement [`AsMut`] by forwarding to a field's implementation.
162///
163/// The first argument is the struct to create the impl for and the second is the target type
164/// produced by the field's [`AsMut`] implementation.
165///
166/// # Examples
167/// With a newtype struct:
168/// ```
169/// use impl_more::forward_as_mut;
170///
171/// struct Foo(String);
172/// forward_as_mut!(Foo => str);
173///
174/// let mut foo = Foo("bar".to_owned());
175/// foo.as_mut().make_ascii_uppercase();
176///
177/// assert_eq!(foo.0, "BAR");
178/// ```
179///
180/// With a named field struct and type parameters:
181/// ```
182/// use impl_more::forward_as_mut;
183///
184/// struct Foo<T> { inner: Vec<T> }
185/// forward_as_mut!(<T> in Foo<T> => inner: [T]);
186///
187/// let mut foo = Foo { inner: vec![1, 2, 3] };
188/// foo.as_mut().reverse();
189///
190/// assert_eq!(foo.inner, [3, 2, 1]);
191/// ```
192#[macro_export]
193macro_rules! forward_as_mut {
194    (<$($generic:ident),+> in $this:ty => $target:ty) => {
195        impl <$($generic),+> ::core::convert::AsMut<$target> for $this {
196            fn as_mut(&mut self) -> &mut $target {
197                ::core::convert::AsMut::<$target>::as_mut(&mut self.0)
198            }
199        }
200    };
201
202    (<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
203        impl <$($generic),+> ::core::convert::AsMut<$target> for $this {
204            fn as_mut(&mut self) -> &mut $target {
205                ::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
206            }
207        }
208    };
209
210    ($this:ty => $target:ty) => {
211        impl ::core::convert::AsMut<$target> for $this {
212            fn as_mut(&mut self) -> &mut $target {
213                ::core::convert::AsMut::<$target>::as_mut(&mut self.0)
214            }
215        }
216    };
217
218    ($this:ty => $field:ident : $target:ty) => {
219        impl ::core::convert::AsMut<$target> for $this {
220            fn as_mut(&mut self) -> &mut $target {
221                ::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
222            }
223        }
224    };
225}
226
227/// Implement [`AsRef`] and [`AsMut`] by forwarding to a field's implementations.
228///
229/// This macro has the same type parameter support and format as [`forward_as_ref`].
230///
231/// # Examples
232/// ```
233/// use impl_more::forward_as_ref_and_mut;
234///
235/// struct Foo(String);
236/// forward_as_ref_and_mut!(Foo => str);
237///
238/// let mut foo = Foo("bar".to_owned());
239/// foo.as_mut().make_ascii_uppercase();
240///
241/// assert_eq!(foo.as_ref(), "BAR");
242/// ```
243///
244/// [`forward_as_ref`]: crate::forward_as_ref
245#[macro_export]
246macro_rules! forward_as_ref_and_mut {
247    (<$($generic:ident),+> in $this:ty => $target:ty) => {
248        $crate::forward_as_ref!(<$($generic),+> in $this => $target);
249        $crate::forward_as_mut!(<$($generic),+> in $this => $target);
250    };
251
252    (<$($generic:ident),+> in $this:ty => $field:ident : $target:ty) => {
253        $crate::forward_as_ref!(<$($generic),+> in $this => $field: $target);
254        $crate::forward_as_mut!(<$($generic),+> in $this => $field: $target);
255    };
256
257    ($this:ty => $target:ty) => {
258        $crate::forward_as_ref!($this => $target);
259        $crate::forward_as_mut!($this => $target);
260    };
261
262    ($this:ty => $field:ident : $target:ty) => {
263        $crate::forward_as_ref!($this => $field: $target);
264        $crate::forward_as_mut!($this => $field: $target);
265    };
266}
267
268#[cfg(test)]
269mod tests {
270    use alloc::{string::String, vec, vec::Vec};
271
272    struct Newtype(String);
273    forward_as_ref!(Newtype => str);
274    forward_as_mut!(Newtype => str);
275
276    struct Generic<T>(Vec<T>);
277    forward_as_ref!(<T> in Generic<T> => [T]);
278    forward_as_mut!(<T> in Generic<T> => [T]);
279
280    struct GenericNamed<T> {
281        inner: Vec<T>,
282    }
283    forward_as_ref_and_mut!(<T> in GenericNamed<T> => inner: [T]);
284
285    static_assertions::assert_impl_all!(Newtype: AsRef<str>, AsMut<str>);
286    static_assertions::assert_impl_all!(Generic<usize>: AsRef<[usize]>, AsMut<[usize]>);
287    static_assertions::assert_impl_all!(GenericNamed<usize>: AsRef<[usize]>, AsMut<[usize]>);
288
289    #[test]
290    fn forwards_newtype() {
291        let mut value = Newtype("hello".into());
292        AsMut::<str>::as_mut(&mut value).make_ascii_uppercase();
293
294        assert_eq!(AsRef::<str>::as_ref(&value), "HELLO");
295    }
296
297    #[test]
298    fn forwards_generic_newtype() {
299        let mut value = Generic(vec![1, 2, 3]);
300        AsMut::<[usize]>::as_mut(&mut value).reverse();
301
302        assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
303    }
304
305    #[test]
306    fn forwards_generic_named_field() {
307        let mut value = GenericNamed {
308            inner: vec![1, 2, 3],
309        };
310        AsMut::<[usize]>::as_mut(&mut value).reverse();
311
312        assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
313    }
314}