#struct #convert #macro

macro struct-convert

Auto Convert between structs

7 releases (stable)

Uses new Rust 2021

1.2.3 Nov 1, 2022
1.2.2 Oct 19, 2022
1.0.1 Sep 7, 2022
0.1.1 Sep 7, 2022

#425 in Rust patterns

MIT license

20KB
307 lines

Struct Convert

Auto Covnert between structs.

Example

A simple struct convert.

use struct_convert::Convert;

#[derive(Debug, Default, PartialEq)]
struct B {
    bid: String,
    num: String,
    name: String,
}

#[derive(Debug, Default, PartialEq)]
struct C {
    cid: Option<String>,
    num: String,
    name: String,
}

#[derive(Debug, Default, Clone, Convert, PartialEq)]
#[convert(into = "B")]
#[convert(into = "C")]
struct A {
    #[convert_field(class = "B", rename = "bid", to_string)]
    #[convert_field(class = "C", rename = "cid", custom_fn = "wrap_id")]
    id: i64,

    #[convert_field(to_string)]
    num: i64,

    #[convert_field(unwrap)]
    name: Option<String>,
}

fn wrap_id(a: &A) -> Option<String> {
    Some(a.id.to_string())
}

fn main() {
    let a = A {
        id: 2,
        num: 1,
        name: Some("Jack".to_string()),
    };
    let b: B = a.clone().into();
    debug_assert_eq!(
        B {
            num: "1".to_string(),
            bid: 2.to_string(),
            name: "Jack".to_string(),
        },
        b
    );

    let c: C = a.into();
    debug_assert_eq!(
        C {
            num: "1".to_string(),
            cid: Some("2".into()),
            name: "Jack".to_string(),
        },
        c
    );
}

Inner stuct convert.

use struct_convert::Convert;

#[derive(Debug, Default, PartialEq)]
struct BInner {
    name: String,
}

#[derive(Debug, Default, PartialEq)]
struct B {
    bid: i64,
    inner: BInner,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "B")]
struct A {
    #[convert_field(rename = "bid")]
    id: i64,

    inner: AInner,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "BInner")]
struct AInner {
    name: String,
}

fn main() {
    let a = A {
        id: 2,
        inner: AInner {
            name: String::from("AInner"),
        },
    };
    let b: B = a.into();
    debug_assert_eq!(
        B {
            bid: 2,
            inner: BInner {
                name: String::from("AInner")
            },
        },
        b
    );
}

Option field convert.

use struct_convert::Convert;

#[derive(Debug, Default, PartialEq)]
struct BInner {
    name: String,
}

#[derive(Debug, Default, PartialEq)]
struct B {
    name: String,
    name2: String,
    opt_str: Option<String>,
    opt_str2: Option<String>,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "B")]
struct A {
    #[convert_field(unwrap)]
    name: Option<String>,

    #[convert_field(unwrap)]
    name2: Option<String>,

    #[convert_field(option)]
    opt_str: String,

    #[convert_field(option)]
    opt_str2: Option<String>,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "BInner")]
struct AInner {
    name: String,
}

fn main() {
    let a = A {
        name: Some("Jack".to_string()),
        opt_str: String::from("str"),
        opt_str2: Some(String::from("Option")),
        name2: None,
    };
    let b: B = a.into();
    debug_assert_eq!(
        B {
            name: "Jack".to_string(),
            opt_str: Some(String::from("str")),
            opt_str2: Some(String::from("Option")),
            name2: "".to_string()
        },
        b
    );
}

Ignore Some fileds.

use struct_convert::Convert;

#[derive(Debug, Default, PartialEq)]
struct B {
    num: String,
    name: String,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "B")]
struct A {
    #[convert_field(ignore)]
    id: i64,

    #[convert_field(to_string)]
    num: i64,

    #[convert_field(unwrap)]
    name: Option<String>,
}

fn main() {
    let a = A {
        id: 2,
        num: 1,
        name: Some("Jack".to_string()),
    };
    let b: B = a.into();
    debug_assert_eq!(
        B {
            num: "1".to_string(),
            name: "Jack".to_string(),
        },
        b
    );
}

convert B from A

use struct_convert::Convert;

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(from = "AInner")]
struct BInner {
    name: String,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(from = "A")]
struct B {

    #[convert_field(rename = "id")]
    bid: i64,

    #[convert_field(to_string)]
    num: String,

    #[convert_field(unwrap)]
    name: String,

    inner: BInner,

    #[convert_field(wrap)]
    opt_str: Option<String>,

    opt_str2: Option<String>
}

#[derive(Debug, Default,  PartialEq)]
struct A {
    ignore_f: i64,
    id: i64,
    num: i64,
    name: Option<String>,
    inner: AInner,
    opt_str: String,
    opt_str2: Option<String>,
}


#[derive(Debug, Default, PartialEq)]
struct AInner {
    name: String,
}

fn main() {
    let a = A {
        id: 2,
        num: 1,
        name: Some("Jack".to_string()),
        inner: AInner {
            name: String::from("AInner"),
        },
        opt_str: String::from("str"),
        opt_str2: Some(String::from("Option")),
        ignore_f: 1,
    };
    let b: B = a.into();
    debug_assert_eq!(
        B {
            num: "1".to_string(),
            bid: 2,
            name: "Jack".to_string(),
            inner: BInner {
                name: String::from("AInner")
            },
            opt_str: Some(String::from("str")),
            opt_str2: Some(String::from("Option"))
        },
        b
    );
}

Convert with custom function.

use struct_convert::Convert;

#[derive(Debug, Default, PartialEq)]
struct B {
    bid: i64,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(into = "B")]
struct A {
    #[convert_field(rename = "bid", custom_fn = "str_to_i64")]
    id_str: String,
}

#[derive(Debug, Default, Convert, PartialEq)]
#[convert(from = "B")]
struct C {
    #[convert_field(rename = "bid", custom_fn = "to_point")]
    point: Point,
}

#[derive(Debug, Default, PartialEq)]
struct Point(i64, i64);

fn str_to_i64(a: &A) -> i64 {
    a.id_str.parse().unwrap()
}

fn to_point(b: &B) -> Point {
  Point(b.bid, b.bid)
}

fn main() {
    let a = A { id_str: "4".into() };
    let b: B = a.into();
    debug_assert_eq!(B { bid: 4 }, b);
    let c: C = b.into();
    debug_assert_eq!(C { point: Point(4, 4) }, c);

}

More examples look here.

Welcome PR.

Dependencies

~0.6–1MB
~23K SLoC