#[macro_export]
macro_rules! impl_from {
(<$($generic:ident),+> in $from:ty => $this:ty $(,)?) => {
impl <$($generic),+> ::core::convert::From<$from> for $this {
fn from(from: $from) -> Self {
Self(from)
}
}
};
(<$($generic:ident),+> in $from:ty => $this:ty : $field:ident $(,)?) => {
impl <$($generic),+> ::core::convert::From<$from> for $this {
fn from(from: $from) -> Self {
Self { $field: from }
}
}
};
($from:ty => $this:ty $(,)?) => {
impl ::core::convert::From<$from> for $this {
fn from(from: $from) -> Self {
Self(from)
}
}
};
($from:ty => $this:ty : $field:ident $(,)?) => {
impl ::core::convert::From<$from> for $this {
fn from(from: $from) -> Self {
Self { $field : from }
}
}
};
}
#[macro_export]
macro_rules! impl_from_for_primitive {
($this:ty; from $from:ty $(,)?) => {
impl ::core::convert::From<$from> for $this {
fn from(from: $from) -> $this {
<$this as ::core::convert::From<_>>::from(from.0)
}
}
};
}
#[macro_export]
macro_rules! impl_into {
(<$($generic:ident),+> in $this:ty => $inner:ty : $field:ident) => {
impl <$($generic),+> ::core::convert::Into<$inner> for $this {
fn into(self) -> $inner {
self.$field
}
}
};
(<$($generic:ident),+> in $this:ty => $inner:ty) => {
impl <$($generic),+> ::core::convert::Into<$inner> for $this {
fn into(self) -> $inner {
self.0
}
}
};
($this:ty => $inner:ty) => {
impl ::core::convert::Into<$inner> for $this {
fn into(self) -> $inner {
self.0
}
}
};
($this:ty => $inner:ty : $field:ident) => {
impl ::core::convert::Into<$inner> for $this {
fn into(self) -> $inner {
self.$field
}
}
};
}
#[cfg(test)]
mod tests {
#![allow(clippy::from_over_into)]
use alloc::rc::Rc;
#[test]
fn newtype() {
struct Foo(usize);
impl_from!(usize => Foo);
impl_into!(Foo => usize);
static_assertions::assert_impl_all!(Foo: From<usize>, Into<usize>);
let foo = Foo::from(42);
assert_eq!(foo.0, 42);
}
#[test]
fn newtype_primitive() {
struct Foo(usize);
impl_from!(usize => Foo);
impl_from_for_primitive!(usize; from Foo);
static_assertions::assert_impl_all!(Foo: From<usize>);
static_assertions::assert_impl_all!(usize: From<Foo>);
let foo = Foo::from(42);
assert_eq!(foo.0, 42);
}
#[test]
fn newtype_generic() {
struct Foo<T>(Rc<T>);
impl_from!(<T> in Rc<T> => Foo<T>);
impl_into!(<T> in Foo<T> => Rc<T>);
let foo = Foo::from(Rc::new(42_usize));
assert_eq!(*foo.0, 42);
}
#[test]
fn named_field() {
struct Foo {
inner: usize,
}
impl_from!(usize => Foo : inner);
impl_into!(Foo => usize : inner);
static_assertions::assert_impl_all!(Foo: From<usize>, Into<usize>);
let foo = Foo::from(42);
assert_eq!(foo.inner, 42);
struct MultiFoo {
small: u8,
big: u64,
}
impl_into!(MultiFoo => u8 : small);
impl_into!(MultiFoo => u64 : big);
static_assertions::assert_impl_all!(MultiFoo: Into<u8>, Into<u64>);
let foo = MultiFoo { small: 4, big: 42 };
assert_eq!(foo.small, 4);
assert_eq!(foo.big, 42);
}
#[test]
fn named_field_generic() {
struct Foo<T> {
inner: Rc<T>,
}
impl_from!(<T> in Rc<T> => Foo<T> : inner);
impl_into!(<T> in Foo<T> => Rc<T> : inner);
let foo = Foo::from(Rc::new(42_usize));
assert_eq!(*foo.inner, 42);
}
}