use std::{convert::Infallible, num::TryFromIntError}; use derive_try_from::TryFrom; #[derive(TryFrom, PartialEq, Debug)] #[try_from_self(V1 = "Rect1", V2 = "v2::Rect2", Error = "Error")] struct Rect { #[try_from_self(V2(skip))] tag: String, x: i32, #[try_from_self(V1(try_map = "try_some"), V2(skip))] y: Option, z: i32, #[try_from_self(map = "|foo: Foo<_>| foo.0")] width: Foo, #[try_from_self(try_map = "try_some")] height: Option, #[try_from_self( V1( try_map = "|vec: Vec| vec.into_iter().map(|val| val.try_into()).collect::, _>>()" ), V2(skip) )] colors: Vec, } fn try_some(opt: Option) -> Result { opt.ok_or(Error::Missing) } #[derive(PartialEq, Debug)] struct Foo(T); #[allow(dead_code)] #[derive(PartialEq, Debug)] struct Rect1 { tag: String, x: i32, y: i32, z: i64, width: i32, height: i32, colors: Vec, } #[allow(dead_code)] mod v2 { #[derive(PartialEq, Debug)] pub(super) struct Rect2 { pub(super) x: i32, pub(super) z: i128, pub(super) width: i32, pub(super) height: i32, } } #[derive(Debug)] enum Error { TryFromInt, Missing, } impl From for Error { fn from(value: Infallible) -> Self { match value {} } } impl From for Error { fn from(_: TryFromIntError) -> Self { Self::TryFromInt } } #[test] fn try_from_self_struct_1() { let rect = Rect { tag: "foo".into(), x: 1, y: Some(2), z: 3, width: Foo(4), height: Some(5), colors: vec![6, 7, 8], }; let rect1 = Rect1 { tag: "foo".into(), x: 1, y: 2, z: 3, width: 4, height: 5, colors: vec![6, 7, 8], }; assert_eq!(Rect1::try_from(rect).unwrap(), rect1); } #[test] fn try_from_self_struct_2() { let rect = Rect { tag: "".into(), x: 1, y: None, z: 3, width: Foo(4), height: Some(5), colors: vec![], }; let rect2 = v2::Rect2 { x: 1, z: 3, width: 4, height: 5, }; assert_eq!(v2::Rect2::try_from(rect).unwrap(), rect2); }