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/// Declare type and const parameters before `in`. The `Foo<T>` form also accepts type parameters.
7///
8/// # Examples
9/// With a newtype struct:
10/// ```
11/// use impl_more::impl_as_ref;
12///
13/// struct Foo(String);
14/// impl_as_ref!(Foo => String);
15/// let foo = Foo("bar".to_owned());
16/// assert_eq!(foo.as_ref(), "bar");
17/// ```
18///
19/// With a named field struct and type parameters:
20/// ```
21/// use impl_more::impl_as_ref;
22///
23/// struct Foo<T> { inner: T }
24/// impl_as_ref!(Foo<T> => inner: T);
25/// let foo = Foo { inner: "bar".to_owned() };
26/// assert_eq!(foo.as_ref().as_str(), "bar");
27/// ```
28///
29/// With type and const parameters:
30/// ```
31/// struct Array<T, const N: usize>([T; N]);
32/// impl_more::impl_as_ref!(<T, const N: usize> in Array<T, N> => [T; N]);
33/// impl_more::impl_as_mut!(<T, const N: usize> in Array<T, N> => [T; N]);
34///
35/// let mut value = Array([1, 2, 3]);
36/// value.as_mut().reverse();
37/// assert_eq!(value.as_ref(), &[3, 2, 1]);
38/// ```
39#[macro_export]
40macro_rules! impl_as_ref {
41    (<$($generic:ident),+> in $($rest:tt)+) => {
42        $crate::impl_as_ref!(@impl [$($generic),+] $($rest)+);
43    };
44
45    (<const $($rest:tt)+) => {
46        $crate::__impl_more_parse_generics!(@parse impl_as_ref [] [] const $($rest)+);
47    };
48
49    (<$generic:ident, $($rest:tt)+) => {
50        $crate::__impl_more_parse_generics!(@parse impl_as_ref [] [] $generic, $($rest)+);
51    };
52
53    (@impl [$($generic:tt)+] $this:ty => $inner:ty) => {
54        impl <$($generic)+> ::core::convert::AsRef<$inner> for $this {
55            fn as_ref(&self) -> &$inner {
56                &self.0
57            }
58        }
59    };
60
61    (@impl [$($generic:tt)+] $this:ty => $field:ident : $inner:ty) => {
62        impl <$($generic)+> ::core::convert::AsRef<$inner> for $this {
63            fn as_ref(&self) -> &$inner {
64                &self.$field
65            }
66        }
67    };
68
69    ($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
70        impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
71            fn as_ref(&self) -> &$inner {
72                &self.0
73            }
74        }
75    };
76
77    ($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
78        impl $(<$($generic),+>)? ::core::convert::AsRef<$inner> for $this $(<$($generic),+>)? {
79            fn as_ref(&self) -> &$inner {
80                &self.$field
81            }
82        }
83    };
84}
85
86/// Implement [`AsRef`] by forwarding to a field's implementation.
87///
88/// The first argument is the struct to create the impl for and the second is the target type
89/// produced by the field's [`AsRef`] implementation.
90///
91/// Declare type and const parameters before `in`.
92///
93/// # Examples
94/// With a newtype struct:
95/// ```
96/// use impl_more::forward_as_ref;
97///
98/// struct Foo(String);
99/// forward_as_ref!(Foo => str);
100///
101/// let foo = Foo("bar".to_owned());
102/// assert_eq!(foo.as_ref(), "bar");
103/// ```
104///
105/// With a named field struct and type parameters:
106/// ```
107/// use impl_more::forward_as_ref;
108///
109/// struct Foo<T> { inner: Vec<T> }
110/// forward_as_ref!(<T> in Foo<T> => inner: [T]);
111///
112/// let foo = Foo { inner: vec![1, 2, 3] };
113/// assert_eq!(foo.as_ref(), &[1, 2, 3]);
114/// ```
115#[macro_export]
116macro_rules! forward_as_ref {
117    (<$($generic:ident),+> in $($rest:tt)+) => {
118        $crate::forward_as_ref!(@impl [$($generic),+] $($rest)+);
119    };
120
121    (<const $($rest:tt)+) => {
122        $crate::__impl_more_parse_generics!(@parse forward_as_ref [] [] const $($rest)+);
123    };
124
125    (<$generic:ident, $($rest:tt)+) => {
126        $crate::__impl_more_parse_generics!(@parse forward_as_ref [] [] $generic, $($rest)+);
127    };
128
129    (@impl [$($generic:tt)+] $this:ty => $target:ty) => {
130        impl <$($generic)+> ::core::convert::AsRef<$target> for $this {
131            fn as_ref(&self) -> &$target {
132                ::core::convert::AsRef::<$target>::as_ref(&self.0)
133            }
134        }
135    };
136
137    (@impl [$($generic:tt)+] $this:ty => $field:ident : $target:ty) => {
138        impl <$($generic)+> ::core::convert::AsRef<$target> for $this {
139            fn as_ref(&self) -> &$target {
140                ::core::convert::AsRef::<$target>::as_ref(&self.$field)
141            }
142        }
143    };
144
145    ($this:ty => $target:ty) => {
146        impl ::core::convert::AsRef<$target> for $this {
147            fn as_ref(&self) -> &$target {
148                ::core::convert::AsRef::<$target>::as_ref(&self.0)
149            }
150        }
151    };
152
153    ($this:ty => $field:ident : $target:ty) => {
154        impl ::core::convert::AsRef<$target> for $this {
155            fn as_ref(&self) -> &$target {
156                ::core::convert::AsRef::<$target>::as_ref(&self.$field)
157            }
158        }
159    };
160}
161
162/// Implement [`AsMut`] for a struct.
163///
164/// The first argument is that of the struct to create the impl for and the second is the type to
165/// produce a reference for.
166///
167/// Declare type and const parameters before `in`. The `Foo<T>` form also accepts type parameters.
168///
169/// # Examples
170/// With a newtype struct:
171/// ```
172/// use impl_more::{impl_as_ref, impl_as_mut};
173///
174/// struct Foo(String);
175///
176/// impl_as_ref!(Foo => String);
177/// impl_as_mut!(Foo => String);
178///
179/// let mut foo = Foo("bar".to_owned());
180/// foo.as_mut().push('!');
181///
182/// assert_eq!(foo.as_ref(), "bar!");
183/// ```
184///
185/// With a named field struct and type parameters:
186/// ```
187/// use impl_more::{impl_as_ref, impl_as_mut};
188///
189/// struct Foo<T> { inner: T }
190///
191/// impl_as_ref!(Foo<T> => inner: T);
192/// impl_as_mut!(Foo<T> => inner: T);
193///
194/// let mut foo = Foo { inner: "bar".to_owned() };
195/// foo.as_mut().push('!');
196///
197/// assert_eq!(foo.as_ref(), "bar!");
198/// ```
199#[macro_export]
200macro_rules! impl_as_mut {
201    (<$($generic:ident),+> in $($rest:tt)+) => {
202        $crate::impl_as_mut!(@impl [$($generic),+] $($rest)+);
203    };
204
205    (<const $($rest:tt)+) => {
206        $crate::__impl_more_parse_generics!(@parse impl_as_mut [] [] const $($rest)+);
207    };
208
209    (<$generic:ident, $($rest:tt)+) => {
210        $crate::__impl_more_parse_generics!(@parse impl_as_mut [] [] $generic, $($rest)+);
211    };
212
213    (@impl [$($generic:tt)+] $this:ty => $inner:ty) => {
214        impl <$($generic)+> ::core::convert::AsMut<$inner> for $this {
215            fn as_mut(&mut self) -> &mut $inner {
216                &mut self.0
217            }
218        }
219    };
220
221    (@impl [$($generic:tt)+] $this:ty => $field:ident : $inner:ty) => {
222        impl <$($generic)+> ::core::convert::AsMut<$inner> for $this {
223            fn as_mut(&mut self) -> &mut $inner {
224                &mut self.$field
225            }
226        }
227    };
228
229    ($this:ident $(<$($generic:ident),+>)? => $inner:ty) => {
230        impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
231            fn as_mut(&mut self) -> &mut $inner {
232                &mut self.0
233            }
234        }
235    };
236
237    ($this:ident $(<$($generic:ident),+>)? => $field:ident : $inner:ty) => {
238        impl $(<$($generic),+>)? ::core::convert::AsMut<$inner> for $this $(<$($generic),+>)? {
239            fn as_mut(&mut self) -> &mut $inner {
240                &mut self.$field
241            }
242        }
243    };
244}
245
246/// Implement [`AsMut`] by forwarding to a field's implementation.
247///
248/// The first argument is the struct to create the impl for and the second is the target type
249/// produced by the field's [`AsMut`] implementation.
250///
251/// Declare type and const parameters before `in`.
252///
253/// # Examples
254/// With a newtype struct:
255/// ```
256/// use impl_more::forward_as_mut;
257///
258/// struct Foo(String);
259/// forward_as_mut!(Foo => str);
260///
261/// let mut foo = Foo("bar".to_owned());
262/// foo.as_mut().make_ascii_uppercase();
263///
264/// assert_eq!(foo.0, "BAR");
265/// ```
266///
267/// With a named field struct and type parameters:
268/// ```
269/// use impl_more::forward_as_mut;
270///
271/// struct Foo<T> { inner: Vec<T> }
272/// forward_as_mut!(<T> in Foo<T> => inner: [T]);
273///
274/// let mut foo = Foo { inner: vec![1, 2, 3] };
275/// foo.as_mut().reverse();
276///
277/// assert_eq!(foo.inner, [3, 2, 1]);
278/// ```
279#[macro_export]
280macro_rules! forward_as_mut {
281    (<$($generic:ident),+> in $($rest:tt)+) => {
282        $crate::forward_as_mut!(@impl [$($generic),+] $($rest)+);
283    };
284
285    (<const $($rest:tt)+) => {
286        $crate::__impl_more_parse_generics!(@parse forward_as_mut [] [] const $($rest)+);
287    };
288
289    (<$generic:ident, $($rest:tt)+) => {
290        $crate::__impl_more_parse_generics!(@parse forward_as_mut [] [] $generic, $($rest)+);
291    };
292
293    (@impl [$($generic:tt)+] $this:ty => $target:ty) => {
294        impl <$($generic)+> ::core::convert::AsMut<$target> for $this {
295            fn as_mut(&mut self) -> &mut $target {
296                ::core::convert::AsMut::<$target>::as_mut(&mut self.0)
297            }
298        }
299    };
300
301    (@impl [$($generic:tt)+] $this:ty => $field:ident : $target:ty) => {
302        impl <$($generic)+> ::core::convert::AsMut<$target> for $this {
303            fn as_mut(&mut self) -> &mut $target {
304                ::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
305            }
306        }
307    };
308
309    ($this:ty => $target:ty) => {
310        impl ::core::convert::AsMut<$target> for $this {
311            fn as_mut(&mut self) -> &mut $target {
312                ::core::convert::AsMut::<$target>::as_mut(&mut self.0)
313            }
314        }
315    };
316
317    ($this:ty => $field:ident : $target:ty) => {
318        impl ::core::convert::AsMut<$target> for $this {
319            fn as_mut(&mut self) -> &mut $target {
320                ::core::convert::AsMut::<$target>::as_mut(&mut self.$field)
321            }
322        }
323    };
324}
325
326/// Implement [`AsRef`] and [`AsMut`] by forwarding to a field's implementations.
327///
328/// This macro has the same type and const parameter support and format as [`forward_as_ref`].
329///
330/// Declare type and const parameters before `in`.
331///
332/// # Examples
333/// ```
334/// use impl_more::forward_as_ref_and_mut;
335///
336/// struct Foo(String);
337/// forward_as_ref_and_mut!(Foo => str);
338///
339/// let mut foo = Foo("bar".to_owned());
340/// foo.as_mut().make_ascii_uppercase();
341///
342/// assert_eq!(foo.as_ref(), "BAR");
343/// ```
344///
345/// [`forward_as_ref`]: crate::forward_as_ref
346///
347/// With type and const parameters:
348/// ```
349/// struct Array<T, const N: usize>([T; N]);
350/// impl_more::forward_as_ref_and_mut!(<T, const N: usize> in Array<T, N> => [T]);
351///
352/// let mut value = Array([1, 2, 3]);
353/// value.as_mut().reverse();
354/// assert_eq!(value.as_ref(), &[3, 2, 1]);
355/// ```
356#[macro_export]
357macro_rules! forward_as_ref_and_mut {
358    (<$($generic:ident),+> in $($rest:tt)+) => {
359        $crate::forward_as_ref_and_mut!(@impl [$($generic),+] $($rest)+);
360    };
361
362    (<const $($rest:tt)+) => {
363        $crate::__impl_more_parse_generics!(@parse forward_as_ref_and_mut [] [] const $($rest)+);
364    };
365
366    (<$generic:ident, $($rest:tt)+) => {
367        $crate::__impl_more_parse_generics!(@parse forward_as_ref_and_mut [] [] $generic, $($rest)+);
368    };
369
370    (@impl [$($generic:tt)+] $this:ty => $target:ty) => {
371        $crate::forward_as_ref!(@impl [$($generic)+] $this => $target);
372        $crate::forward_as_mut!(@impl [$($generic)+] $this => $target);
373    };
374
375    (@impl [$($generic:tt)+] $this:ty => $field:ident : $target:ty) => {
376        $crate::forward_as_ref!(@impl [$($generic)+] $this => $field: $target);
377        $crate::forward_as_mut!(@impl [$($generic)+] $this => $field: $target);
378    };
379
380    ($this:ty => $target:ty) => {
381        $crate::forward_as_ref!($this => $target);
382        $crate::forward_as_mut!($this => $target);
383    };
384
385    ($this:ty => $field:ident : $target:ty) => {
386        $crate::forward_as_ref!($this => $field: $target);
387        $crate::forward_as_mut!($this => $field: $target);
388    };
389}
390
391#[cfg(test)]
392mod tests {
393    use alloc::{string::String, vec, vec::Vec};
394
395    struct Newtype(String);
396    forward_as_ref!(Newtype => str);
397    forward_as_mut!(Newtype => str);
398
399    struct Generic<T>(Vec<T>);
400    forward_as_ref!(<T> in Generic<T> => [T]);
401    forward_as_mut!(<T> in Generic<T> => [T]);
402
403    struct GenericNamed<T> {
404        inner: Vec<T>,
405    }
406    forward_as_ref_and_mut!(<T> in GenericNamed<T> => inner: [T]);
407
408    static_assertions::assert_impl_all!(Newtype: AsRef<str>, AsMut<str>);
409    static_assertions::assert_impl_all!(Generic<usize>: AsRef<[usize]>, AsMut<[usize]>);
410    static_assertions::assert_impl_all!(GenericNamed<usize>: AsRef<[usize]>, AsMut<[usize]>);
411
412    #[test]
413    fn forwards_newtype() {
414        let mut value = Newtype("hello".into());
415        AsMut::<str>::as_mut(&mut value).make_ascii_uppercase();
416
417        assert_eq!(AsRef::<str>::as_ref(&value), "HELLO");
418    }
419
420    #[test]
421    fn forwards_generic_newtype() {
422        let mut value = Generic(vec![1, 2, 3]);
423        AsMut::<[usize]>::as_mut(&mut value).reverse();
424
425        assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
426    }
427
428    #[test]
429    fn forwards_generic_named_field() {
430        let mut value = GenericNamed {
431            inner: vec![1, 2, 3],
432        };
433        AsMut::<[usize]>::as_mut(&mut value).reverse();
434
435        assert_eq!(AsRef::<[usize]>::as_ref(&value), &[3, 2, 1]);
436    }
437}