newtypes 0.4.0

Macros that ease the implementation of the Newtype pattern
Documentation
/*
 * SPDX-FileCopyrightText: 2025 CTRLback SCCL.
 * SPDX-License-Identifier: MIT
 */

use newtypes::{newtype, newtype_array, newtype_from, newtype_struct, newtype_unit};
use serde::{Deserialize, Serialize};

newtype!(UserId, u32; Serialize, Deserialize);
newtype_from!(UserId, u32);

newtype_unit!(Weight, f32; Serialize, Deserialize);
newtype_from!(Weight, f32);

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct UserData {
    uid: UserId,
    uname: String,
    weight: Weight,
}

#[test]
fn test_extra_derive() {
    let str_user_data = r#"
    {
        "uid": 42,
        "uname": "john",
        "weight": 77.75
    }
    "#;

    let user_data: UserData = serde_json::from_str(str_user_data).unwrap();

    assert_eq!(
        UserData {
            uid: UserId(42),
            uname: String::from("john"),
            weight: Weight(77.75),
        },
        user_data
    );
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Payload {
    pub label: String,
    pub value: u32,
}
newtype_struct!(Tagged, Payload; Serialize, Deserialize);

#[test]
fn test_newtype_struct_serde_roundtrip() {
    let t = Tagged(Payload {
        label: "answer".into(),
        value: 42,
    });
    let json = serde_json::to_string(&t).unwrap();
    let parsed: Tagged = serde_json::from_str(&json).unwrap();
    assert_eq!(t, parsed);
}

newtype_array!(MacAddr, u8, 6; Serialize, Deserialize);

#[test]
fn test_newtype_array_serde_roundtrip() {
    let m = MacAddr([0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe]);
    let json = serde_json::to_string(&m).unwrap();
    assert_eq!("[222,173,190,239,202,254]", json);
    let parsed: MacAddr = serde_json::from_str(&json).unwrap();
    assert_eq!(m, parsed);
}