char_str 0.0.2

Compact owned string types forked from lean_string for Ruff and ty.
Documentation
// from: https://github.com/ParkMyCar/compact_str/blob/193d13eaa5a92b3c39c2f7289dc44c95f37c80d1/compact_str/src/features/serde.rs
#![cfg(feature = "serde")]

use char_str::{CharStr, CharString};
use proptest::property_test;
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
struct PersonString {
    name: String,
    phones: Vec<String>,
    address: Option<String>,
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
struct PersonCharString {
    name: CharString,
    phones: Vec<CharString>,
    address: Option<CharString>,
}

#[test]
fn test_roundtrip() {
    let name = "Ferris the Crab";
    let phones = ["1-800-111-1111", "2-222-222-2222"];
    let address = Some("123 Sesame Street");

    let std = PersonString {
        name: name.to_string(),
        phones: phones.iter().map(|s| s.to_string()).collect(),
        address: address.as_ref().map(|s| s.to_string()),
    };
    let compact = PersonCharString {
        name: name.into(),
        phones: phones.iter().map(|s| CharString::from(*s)).collect(),
        address: address.as_ref().map(|s| CharString::from(*s)),
    };

    let std_json = serde_json::to_string(&std).unwrap();
    let compact_json = serde_json::to_string(&compact).unwrap();

    // the serialized forms should be the same
    assert_eq!(std_json, compact_json);

    let std_de_compact: PersonString = serde_json::from_str(&compact_json).unwrap();
    let compact_de_std: PersonCharString = serde_json::from_str(&std_json).unwrap();

    // we should be able to deserailze from the opposite, serialized, source
    assert_eq!(std_de_compact, std);
    assert_eq!(compact_de_std, compact);
}

#[test]
fn char_str_roundtrip() {
    let value = CharStr::from("a frozen string longer than the inline limit");
    let serialized = serde_json::to_string(&value).unwrap();
    let deserialized: CharStr = serde_json::from_str(&serialized).unwrap();

    assert_eq!(deserialized, value);
}

#[property_test]
#[cfg_attr(miri, ignore)]
fn proptest_roundtrip(name: String, phones: Vec<String>, address: Option<String>) {
    let std =
        PersonString { name: name.clone(), phones: phones.to_vec(), address: address.clone() };
    let compact = PersonCharString {
        name: name.into(),
        phones: phones.iter().map(CharString::from).collect(),
        address: address.map(CharString::from),
    };

    let std_json = serde_json::to_string(&std).unwrap();
    let compact_json = serde_json::to_string(&compact).unwrap();

    // the serialized forms should be the same
    assert_eq!(std_json, compact_json);

    let std_de_compact: PersonString = serde_json::from_str(&compact_json).unwrap();
    let compact_de_std: PersonCharString = serde_json::from_str(&std_json).unwrap();

    // we should be able to deserailze from the opposite, serialized, source
    assert_eq!(std_de_compact, std);
    assert_eq!(compact_de_std, compact);
}