Skip to main content

impl_more/
from.rs

1/// Implement [`From`] for a struct.
2///
3/// Declare type and const parameters before `in`.
4///
5/// # Examples
6/// With a newtype struct:
7/// ```
8/// use impl_more::impl_from;
9///
10/// struct Foo(String);
11/// impl_from!(String => Foo);
12///
13/// let foo = Foo::from("bar".to_owned());
14/// ```
15///
16/// With a named field struct with type parameters:
17/// ```
18/// use std::rc::Rc;
19/// use impl_more::impl_from;
20///
21/// struct Foo<T> { inner: Rc<T> }
22/// impl_from!(<T> in Rc<T> => Foo<T> : inner);
23///
24/// let foo = Foo::from(Rc::new("bar".to_owned()));
25/// ```
26///
27/// With type and const parameters:
28/// ```
29/// struct Array<T, const N: usize>([T; N]);
30/// impl_more::impl_from!(<T, const N: usize> in [T; N] => Array<T, N>);
31///
32/// let value = Array::from([1, 2, 3]);
33/// assert_eq!(value.0, [1, 2, 3]);
34/// ```
35#[macro_export]
36macro_rules! impl_from {
37    (<$($generic:ident),+> in $($rest:tt)+) => {
38        $crate::impl_from!(@impl [$($generic),+] $($rest)+);
39    };
40
41    (<const $($rest:tt)+) => {
42        $crate::__impl_more_parse_generics!(@parse impl_from [] [] const $($rest)+);
43    };
44
45    (<$generic:ident, $($rest:tt)+) => {
46        $crate::__impl_more_parse_generics!(@parse impl_from [] [] $generic, $($rest)+);
47    };
48
49    (@impl [$($generic:tt)+] $from:ty => $this:ty $(,)?) => {
50        impl <$($generic)+> ::core::convert::From<$from> for $this {
51            fn from(from: $from) -> Self {
52                Self(from)
53            }
54        }
55    };
56
57    (@impl [$($generic:tt)+] $from:ty => $this:ty : $field:ident $(,)?) => {
58        impl <$($generic)+> ::core::convert::From<$from> for $this {
59            fn from(from: $from) -> Self {
60                Self { $field: from }
61            }
62        }
63    };
64
65    ($from:ty => $this:ty $(,)?) => {
66        impl ::core::convert::From<$from> for $this {
67            fn from(from: $from) -> Self {
68                Self(from)
69            }
70        }
71    };
72
73
74    ($from:ty => $this:ty : $field:ident $(,)?) => {
75        impl ::core::convert::From<$from> for $this {
76            fn from(from: $from) -> Self {
77                Self { $field : from }
78            }
79        }
80    };
81}
82
83/// Implement [`From`] for a primitive.
84///
85/// # Examples
86/// With a newtype struct:
87/// ```
88/// use impl_more::impl_from_for_primitive;
89///
90/// struct Checked(bool);
91/// impl_from_for_primitive!(Checked => bool);
92///
93/// let foo = bool::from(Checked(true));
94/// ```
95#[macro_export]
96macro_rules! impl_from_for_primitive {
97    ($from:ty => $this:ty $(,)?) => {
98        impl ::core::convert::From<$from> for $this {
99            fn from(from: $from) -> $this {
100                <$this as ::core::convert::From<_>>::from(from.0)
101            }
102        }
103    };
104}
105
106/// Implement [`From`] and [`Into`] for a newtype struct.
107///
108/// # Examples
109///
110/// ```
111/// use impl_more::impl_newtype_from_into;
112///
113/// struct Checked(bool);
114/// impl_newtype_from_into!(Checked [<=>] bool);
115///
116/// let foo = Checked::from(true);
117/// assert_eq!(foo.0, true);
118///
119/// let foo = bool::from(Checked(false));
120/// assert_eq!(foo, false);
121/// ```
122#[macro_export]
123macro_rules! impl_newtype_from_into {
124    ($newtype:ty [<=>] $inner:ty $(,)?) => {
125        impl ::core::convert::From<$inner> for $newtype {
126            fn from(from: $inner) -> $newtype {
127                Self(from)
128            }
129        }
130
131        impl ::core::convert::From<$newtype> for $inner {
132            fn from(from: $newtype) -> $inner {
133                from.0
134            }
135        }
136    };
137}
138
139/// Implement [`Into`] for a struct.
140///
141/// Declare type and const parameters before `in`.
142///
143/// # Examples
144/// With a newtype struct:
145/// ```
146/// use impl_more::impl_into;
147///
148/// struct Foo(String);
149///
150/// impl_into!(Foo => String);
151///
152/// let foo = Foo("bar".to_owned());
153/// let foo_str: String = foo.into();
154/// ```
155///
156/// With a named field struct with type parameters:
157/// ```
158/// use std::rc::Rc;
159/// use impl_more::impl_into;
160///
161/// struct Foo<T> { inner: Rc<T> }
162/// impl_into!(<T> in Foo<T> => Rc<T> : inner);
163///
164/// let foo = Foo { inner: Rc::new("bar".to_owned()) };
165/// let _: Rc<String> = foo.into();
166/// ```
167#[macro_export]
168macro_rules! impl_into {
169    (<$($generic:ident),+> in $($rest:tt)+) => {
170        $crate::impl_into!(@impl [$($generic),+] $($rest)+);
171    };
172
173    (<const $($rest:tt)+) => {
174        $crate::__impl_more_parse_generics!(@parse impl_into [] [] const $($rest)+);
175    };
176
177    (<$generic:ident, $($rest:tt)+) => {
178        $crate::__impl_more_parse_generics!(@parse impl_into [] [] $generic, $($rest)+);
179    };
180
181    (@impl [$($generic:tt)+] $this:ty => $inner:ty : $field:ident) => {
182        impl <$($generic)+> ::core::convert::Into<$inner> for $this {
183            fn into(self) -> $inner {
184                self.$field
185            }
186        }
187    };
188
189    (@impl [$($generic:tt)+] $this:ty => $inner:ty) => {
190        impl <$($generic)+> ::core::convert::Into<$inner> for $this {
191            fn into(self) -> $inner {
192                self.0
193            }
194        }
195    };
196
197    ($this:ty => $inner:ty) => {
198        impl ::core::convert::Into<$inner> for $this {
199            fn into(self) -> $inner {
200                self.0
201            }
202        }
203    };
204
205    ($this:ty => $inner:ty : $field:ident) => {
206        impl ::core::convert::Into<$inner> for $this {
207            fn into(self) -> $inner {
208                self.$field
209            }
210        }
211    };
212}
213
214#[cfg(test)]
215mod tests {
216    #![allow(clippy::from_over_into)]
217
218    use alloc::rc::Rc;
219
220    #[test]
221    fn newtype() {
222        struct Foo(usize);
223        impl_from!(usize => Foo);
224        impl_into!(Foo => usize);
225
226        static_assertions::assert_impl_all!(Foo: From<usize>, Into<usize>);
227
228        let foo = Foo::from(42);
229        assert_eq!(foo.0, 42);
230    }
231
232    #[test]
233    fn newtype_primitive() {
234        struct Foo(usize);
235        impl_from!(usize => Foo);
236        impl_from_for_primitive!(Foo => usize);
237
238        static_assertions::assert_impl_all!(Foo: From<usize>);
239        static_assertions::assert_impl_all!(usize: From<Foo>);
240
241        let foo = Foo::from(42);
242        assert_eq!(foo.0, 42);
243    }
244
245    #[test]
246    fn newtype_generic() {
247        struct Foo<T>(Rc<T>);
248        impl_from!(<T> in Rc<T> => Foo<T>);
249        impl_into!(<T> in Foo<T> => Rc<T>);
250
251        let foo = Foo::from(Rc::new(42_usize));
252        assert_eq!(*foo.0, 42);
253    }
254
255    #[test]
256    fn named_field() {
257        struct Foo {
258            inner: usize,
259        }
260        impl_from!(usize => Foo : inner);
261        impl_into!(Foo => usize : inner);
262
263        static_assertions::assert_impl_all!(Foo: From<usize>, Into<usize>);
264
265        let foo = Foo::from(42);
266        assert_eq!(foo.inner, 42);
267
268        struct MultiFoo {
269            small: u8,
270            big: u64,
271        }
272        impl_into!(MultiFoo => u8 : small);
273        impl_into!(MultiFoo => u64 : big);
274
275        static_assertions::assert_impl_all!(MultiFoo: Into<u8>, Into<u64>);
276
277        let foo = MultiFoo { small: 4, big: 42 };
278        assert_eq!(foo.small, 4);
279        assert_eq!(foo.big, 42);
280    }
281
282    #[test]
283    fn named_field_generic() {
284        struct Foo<T> {
285            inner: Rc<T>,
286        }
287        impl_from!(<T> in Rc<T> => Foo<T> : inner);
288        impl_into!(<T> in Foo<T> => Rc<T> : inner);
289
290        let foo = Foo::from(Rc::new(42_usize));
291        assert_eq!(*foo.inner, 42);
292    }
293}