derive_convert 0.3.0

Derives 'impl (Try)From for Self' and 'impl (Try)From<Self>'
Documentation
use std::{convert::Infallible, num::TryFromIntError};

use derive_convert::Convert;

#[derive(Convert, 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<i32>,
    z: i32,
    #[try_from_self(map = "|foo: Foo<_>| foo.0")]
    width: Foo<i32>,
    #[try_from_self(try_map = "try_some")]
    height: Option<i32>,
    #[try_from_self(
        V1(
            try_map = "|vec: Vec<i64>| vec.into_iter().map(|val| val.try_into()).collect::<Result<Vec<i32>, _>>()"
        ),
        V2(skip)
    )]
    colors: Vec<i64>,
}

fn try_some<T>(opt: Option<T>) -> Result<T, Error> {
    opt.ok_or(Error::Missing)
}

#[derive(PartialEq, Debug)]
struct Foo<T>(T);

#[allow(dead_code)]
#[derive(PartialEq, Debug)]
struct Rect1 {
    tag: String,
    x: i32,
    y: i32,
    z: i64,
    width: i32,
    height: i32,
    colors: Vec<i32>,
}

#[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<Infallible> for Error {
    fn from(value: Infallible) -> Self {
        match value {}
    }
}

impl From<TryFromIntError> 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);
}