easy_conv/
lib.rs

1//! Cut down on trivial `impl From<A> for B` boilerplate code.
2
3#[cfg(test)]
4mod test;
5
6/// Implement conversion from `T` to its newtype wrapper.
7///
8/// Also works on types that convert to `T` via `into()`.
9///
10/// The wrapper can either be a newtype struct or a newtype variant of an enum:
11///   - Struct
12///     - Given `struct Foo(T);` and `impl From<U> for T`
13///     - `newtype_wrap!(Foo, T);` implements `T -> Foo(T)`
14///     - `newtype_wrap!(Foo, U);` implements `U -> Foo(T)`
15///   - Enum
16///     - Given `enum Foo{ Bar(T) };` and `impl From<U> for T`
17///     - `newtype_wrap!(Foo, Bar, T);` implements `T -> Foo::Bar(T)`
18///     - `newtype_wrap!(Foo, Bar, U);` implements `U -> Foo::Bar(T)`
19#[macro_export]
20macro_rules! newtype_wrap {
21    ($wrapper: ident, $wrapped: ty) => {
22        impl From<$wrapped> for $wrapper {
23            fn from(val: $wrapped) -> Self {
24                $wrapper(val.into())
25            }
26        }
27    };
28    ($wrapper: ty, $variant: ident, $wrapped: ty) => {
29        impl From<$wrapped> for $wrapper {
30            fn from(val: $wrapped) -> Self {
31                <$wrapper>::$variant(val.into())
32            }
33        }
34    };
35}
36
37/// The same as [`newtype_wrap`], except that the wrapping is implemented on
38/// all types `U` that convert to `T` via `into()`.
39///
40/// Be careful when using this: there may be `U` types that you wish do not receive automatic wrapping.
41/// In such a case, you should use [`newtype_wrap`] on each `U` type separately.
42#[macro_export]
43macro_rules! newtype_wrap_from_any {
44    ($wrapper: ident, $wrapped: ty) => {
45        impl<T> From<T> for $wrapper
46        where
47            T: Into<$wrapped>,
48        {
49            fn from(val: T) -> Self {
50                $wrapper(val.into())
51            }
52        }
53    };
54    ($wrapper: ty, $variant: ident, $wrapped: ty) => {
55        impl<T> From<T> for $wrapper
56        where
57            T: Into<$wrapped>,
58        {
59            fn from(val: T) -> Self {
60                <$wrapper>::$variant(val.into())
61            }
62        }
63    };
64}
65
66/// Implement conversion from `A` to `Z` via `B`, `C`, ...
67///
68/// `B` needs to implement `From<A>`, `C` needs to implement `From<B>`, and so on.
69///
70/// Example: `chained_into!(A, B, C, D, E);` implements `From<A> for E` by
71/// converting `A` to `B`, then `B` to `C`, then `C` to `D`, and finally `D` to `E`.
72#[macro_export]
73macro_rules! chained_into {
74    ($source: ty, $($tail: ty),+) => {
75        chained_into!(@impl $source, chained_into!(@get_target $($tail),+), $($tail),+);
76    };
77    (@impl $source: ty, $target: ty, $($intermediate: ty),*) => {
78        impl From<$source> for $target {
79            fn from(val: $source) -> $target {
80                chained_into!(@next val, $($intermediate),*)
81            }
82        }
83    };
84    (@get_target $target: ty) => {
85        $target
86    };
87    (@get_target $_: ty, $($tail: ty),+) => {
88        chained_into!(@get_target $($tail),+)
89    };
90    (@next $val: expr, $intermediate: ty) => {
91        <$intermediate>::from($val)
92    };
93    (@next $val: expr, $intermediate: ty, $($tail: ty),+) => {
94        chained_into!(@next <$intermediate>::from($val), $($tail),+)
95    };
96}