impl_more/
from.rs

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