postcard-bindgen-core 0.3.5

A crate to generate bindings for the postcard binary format for other languages than Rust - Core Crate
Documentation
use genco::quote;

use crate::{
    registry::{
        BindingType, EnumType, EnumVariant, EnumVariantType, StructField, StructType,
        TupleStructType, UnitStructType,
    },
    type_info::{ArrayMeta, JsType, NumberMeta, ObjectMeta, OptionalMeta, StringMeta},
    utils::assert_tokens,
};

use super::gen_ser_des_functions;

#[test]
fn test_binding_struct_unit() {
    let binding = BindingType::UnitStruct(UnitStructType { name: "A" });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { }
            const deserialize_A = (d) => ({ })
        ),
    )
}

#[test]
fn test_binding_struct_new_type() {
    let binding = BindingType::TupleStruct(TupleStructType {
        name: "A",
        fields: vec![JsType::Number(NumberMeta::Integer {
            bytes: 1,
            signed: false,
        })],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v[0]) }
            const deserialize_A = (d) => ([d.deserialize_number(U8_BYTES, false)])
        ),
    )
}

#[test]
fn test_binding_struct_tuple_2() {
    let binding = BindingType::TupleStruct(TupleStructType {
        name: "A",
        fields: vec![
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
        ],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v[0]); s.serialize_number(U8_BYTES, false, v[1]) }
            const deserialize_A = (d) => ([d.deserialize_number(U8_BYTES, false), d.deserialize_number(U8_BYTES, false)])
        ),
    )
}

#[test]
fn test_binding_struct_tuple_3() {
    let binding = BindingType::TupleStruct(TupleStructType {
        name: "A",
        fields: vec![
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
        ],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v[0]); s.serialize_number(U8_BYTES, false, v[1]); s.serialize_number(U8_BYTES, false, v[2]) }
            const deserialize_A = (d) => ([d.deserialize_number(U8_BYTES, false), d.deserialize_number(U8_BYTES, false), d.deserialize_number(U8_BYTES, false)])
        ),
    )
}

#[test]
fn test_binding_struct_tuple_different_types() {
    let binding = BindingType::TupleStruct(TupleStructType {
        name: "A",
        fields: vec![
            JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
            JsType::String(StringMeta {}),
            JsType::Optional(OptionalMeta {
                inner: Box::new(JsType::Number(NumberMeta::Integer {
                    bytes: 1,
                    signed: false,
                })),
            }),
            JsType::Array(ArrayMeta {
                items_type: Box::new(JsType::Number(NumberMeta::Integer {
                    bytes: 1,
                    signed: false,
                })),
                length: None,
            }),
            JsType::Object(ObjectMeta { name: "A" }),
        ],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v[0]); s.serialize_string(v[1]); if (v[2] !== undefined) { s.serialize_number(U32_BYTES, false, 1); s.serialize_number(U8_BYTES, false, v[2]) } else { s.serialize_number(U32_BYTES, false, 0) }; s.serialize_array((s, v) => s.serialize_number(U8_BYTES, false, v), v[3]); serialize_A(s, v[4]) }
            const deserialize_A = (d) => ([d.deserialize_number(U8_BYTES, false), d.deserialize_string(), (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U8_BYTES, false), d.deserialize_array(() => d.deserialize_number(U8_BYTES, false)), deserialize_A(d)])
        ),
    )
}

#[test]
fn test_binding_struct() {
    let binding = BindingType::Struct(StructType {
        name: "A",
        fields: vec![StructField {
            name: "a",
            js_type: JsType::Number(NumberMeta::Integer {
                bytes: 1,
                signed: false,
            }),
        }],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v.a) }
            const deserialize_A = (d) => ({ a: d.deserialize_number(U8_BYTES, false) })
        ),
    );
}

#[test]
fn test_binding_struct_different_types() {
    let binding = BindingType::Struct(StructType {
        name: "A",
        fields: vec![
            StructField {
                name: "a",
                js_type: JsType::Number(NumberMeta::Integer {
                    bytes: 1,
                    signed: false,
                }),
            },
            StructField {
                name: "b",
                js_type: JsType::String(StringMeta {}),
            },
            StructField {
                name: "c",
                js_type: JsType::Optional(OptionalMeta {
                    inner: Box::new(JsType::Number(NumberMeta::Integer {
                        bytes: 1,
                        signed: false,
                    })),
                }),
            },
            StructField {
                name: "d",
                js_type: JsType::Array(ArrayMeta {
                    items_type: Box::new(JsType::Number(NumberMeta::Integer {
                        bytes: 1,
                        signed: false,
                    })),
                    length: None,
                }),
            },
            StructField {
                name: "e",
                js_type: JsType::Object(ObjectMeta { name: "A" }),
            },
        ],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { s.serialize_number(U8_BYTES, false, v.a); s.serialize_string(v.b); if (v.c !== undefined) { s.serialize_number(U32_BYTES, false, 1); s.serialize_number(U8_BYTES, false, v.c) } else { s.serialize_number(U32_BYTES, false, 0) }; s.serialize_array((s, v) => s.serialize_number(U8_BYTES, false, v), v.d); serialize_A(s, v.e) }
            const deserialize_A = (d) => ({ a: d.deserialize_number(U8_BYTES, false), b: d.deserialize_string(), c: (d.deserialize_number(U32_BYTES, false) === 0) ? undefined : d.deserialize_number(U8_BYTES, false), d: d.deserialize_array(() => d.deserialize_number(U8_BYTES, false)), e: deserialize_A(d) })
        ),
    );
}

#[test]
fn test_binding_enum() {
    let binding = BindingType::Enum(EnumType {
        name: "A",
        variants: vec![
            EnumVariant {
                index: 0,
                name: "A",
                inner_type: EnumVariantType::Empty,
            },
            EnumVariant {
                index: 1,
                name: "B",
                inner_type: EnumVariantType::NewType(vec![StructField {
                    name: "a",
                    js_type: JsType::Number(NumberMeta::Integer {
                        bytes: 1,
                        signed: false,
                    }),
                }]),
            },
            EnumVariant {
                index: 2,
                name: "C",
                inner_type: EnumVariantType::Tuple(vec![JsType::Number(NumberMeta::Integer {
                    bytes: 1,
                    signed: false,
                })]),
            },
            EnumVariant {
                index: 3,
                name: "D",
                inner_type: EnumVariantType::Tuple(vec![
                    JsType::Number(NumberMeta::Integer {
                        bytes: 1,
                        signed: false,
                    }),
                    JsType::Number(NumberMeta::Integer {
                        bytes: 1,
                        signed: false,
                    }),
                ]),
            },
        ],
    });

    assert_tokens(
        gen_ser_des_functions(vec![binding]),
        quote!(
            const serialize_A = (s, v) => { switch (v.tag) { case "A": s.serialize_number(U32_BYTES, false, 0); break; case "B": s.serialize_number(U32_BYTES, false, 1); s.serialize_number(U8_BYTES, false, v.value.a); break; case "C": s.serialize_number(U32_BYTES, false, 2); s.serialize_number(U8_BYTES, false, v.value); break; case "D": s.serialize_number(U32_BYTES, false, 3); s.serialize_number(U8_BYTES, false, v.value[0]); s.serialize_number(U8_BYTES, false, v.value[1]); break } }
            const deserialize_A = (d) => { switch (d.deserialize_number(U32_BYTES, false)) { case 0: return { tag: "A" }; case 1: return { tag: "B" , value: { a: d.deserialize_number(U8_BYTES, false) } }; case 2: return { tag: "C" , value: d.deserialize_number(U8_BYTES, false) }; case 3: return { tag: "D" , value: [d.deserialize_number(U8_BYTES, false), d.deserialize_number(U8_BYTES, false)] }; default: throw "variant not implemented" } }
        ),
    )
}