#![allow(clippy::unwrap_used)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::cast_precision_loss)]
use nulid::Nulid;
use serde::{Deserialize, Serialize};
fn main() -> Result<(), Box<dyn core::error::Error>> {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct User {
id: Nulid,
name: String,
email: String,
created_at: Nulid,
}
#[derive(Debug, Serialize, Deserialize)]
struct Database {
users: Vec<User>,
total_count: usize,
}
println!("NULID Serde Integration Example");
println!("================================\n");
println!("1. Creating a User struct with NULID fields...");
let user = User {
id: Nulid::new()?,
name: "Alice Johnson".to_string(),
email: "alice@example.com".to_string(),
created_at: Nulid::new()?,
};
let user_id = user.id;
let created_at = user.created_at;
println!(" User ID: {user_id}");
println!(" Created At: {created_at}");
println!();
println!("2. Serializing to JSON...");
let json = serde_json::to_string_pretty(&user)?;
println!(" JSON:\n{json}");
println!();
println!("3. Deserializing from JSON...");
let deserialized: User = serde_json::from_str(&json)?;
let deser_id = deserialized.id;
println!(" Deserialized User ID: {deser_id}");
let match_result = if user == deserialized { "ok" } else { "FAIL" };
println!(" Match: {match_result}");
println!();
println!("4. Working with collections...");
let mut users = Vec::new();
for i in 0..3 {
users.push(User {
id: Nulid::new()?,
name: format!("User {}", i + 1),
email: format!("user{}@example.com", i + 1),
created_at: Nulid::new()?,
});
}
let db = Database {
total_count: users.len(),
users,
};
let db_json = serde_json::to_string_pretty(&db)?;
println!(" Database JSON:\n{db_json}");
println!();
println!("5. Deserializing database...");
let deserialized_db: Database = serde_json::from_str(&db_json)?;
let total_count = deserialized_db.total_count;
println!(" Total users: {total_count}");
for (i, user_item) in deserialized_db.users.iter().enumerate() {
let idx = i + 1;
let name = &user_item.name;
let id = user_item.id;
println!(" [{idx}] {name} - {id}");
}
println!();
println!("6. MessagePack serialization...");
let msgpack_bytes = rmp_serde::to_vec(&user)?;
let bytes_len = msgpack_bytes.len();
println!(" MessagePack size: {bytes_len} bytes");
let msgpack_user: User = rmp_serde::from_slice(&msgpack_bytes)?;
let msgpack_id = msgpack_user.id;
println!(" Deserialized ID: {msgpack_id}");
let match_result = if user.id == msgpack_user.id {
"ok"
} else {
"FAIL"
};
println!(" Match: {match_result}");
println!();
println!("7. TOML serialization...");
let toml_str = toml::to_string_pretty(&user)?;
println!(" TOML:\n{toml_str}");
match toml::from_str::<User>(&toml_str) {
Ok(toml_user) => {
let toml_match = if user == toml_user { "ok" } else { "FAIL" };
println!(" Deserialized successfully");
println!(" Match: {toml_match}");
}
Err(e) => {
println!(" Note: TOML deserialization has known issues with some types");
println!(" Error details: {e}");
println!(" Serialization to TOML works, deserialization skipped");
}
}
println!();
println!("8. Sorting NULIDs maintains order after serialization...");
let mut nulids = [
Nulid::new()?,
Nulid::new()?,
Nulid::new()?,
Nulid::new()?,
Nulid::new()?,
];
nulids.sort();
println!(" Sorted NULIDs:");
for (i, id) in nulids.iter().enumerate() {
let idx = i + 1;
println!(" [{idx}] {id}");
}
println!();
let json_ids: Vec<String> = nulids
.iter()
.filter_map(|id| serde_json::to_string(id).ok())
.collect();
let mut json_ids_sorted = json_ids.clone();
json_ids_sorted.sort();
let order_maintained = if json_ids == json_ids_sorted {
"ok"
} else {
"FAIL"
};
println!(" JSON serialized strings maintain sort order: {order_maintained}");
println!();
println!("9. Bincode binary serialization...");
let bincode_encoded = bincode::serde::encode_to_vec(user.id, bincode::config::standard())?;
let bincode_size = bincode_encoded.len();
println!(" Bincode size: {bincode_size} bytes");
let (bincode_decoded, _): (Nulid, usize) =
bincode::serde::decode_from_slice(&bincode_encoded, bincode::config::standard())?;
let bincode_match = if user.id == bincode_decoded {
"ok"
} else {
"FAIL"
};
println!(" Deserialized ID: {bincode_decoded}");
println!(" Match: {bincode_match}");
println!();
println!("10. Size comparison across formats...");
let test_nulid = Nulid::new()?;
let json_bytes = serde_json::to_string(&test_nulid)?.len();
let msgpack_bytes = rmp_serde::to_vec(&test_nulid)?.len();
let bincode_bytes =
bincode::serde::encode_to_vec(test_nulid, bincode::config::standard())?.len();
println!(" JSON: {json_bytes} bytes");
println!(" MessagePack: {msgpack_bytes} bytes");
println!(" Bincode: {bincode_bytes} bytes (most compact)");
println!();
println!("11. Bincode with multiple NULIDs...");
let nulid_vec = vec![Nulid::new()?, Nulid::new()?, Nulid::new()?];
let vec_encoded = bincode::serde::encode_to_vec(&nulid_vec, bincode::config::standard())?;
let vec_size = vec_encoded.len();
let avg_size = vec_size as f64 / nulid_vec.len() as f64;
println!(" Serialized 3 NULIDs: {vec_size} bytes");
println!(" Average per NULID: {avg_size:.1} bytes");
let (vec_decoded, _): (Vec<Nulid>, usize) =
bincode::serde::decode_from_slice(&vec_encoded, bincode::config::standard())?;
let vec_match = if nulid_vec == vec_decoded {
"ok"
} else {
"FAIL"
};
println!(" Round-trip match: {vec_match}");
println!();
println!("All serde examples completed successfully!");
Ok(())
}
#[cfg(not(feature = "serde"))]
fn main() {
eprintln!("This example requires the 'serde' feature.");
eprintln!("Run with: cargo run --example serde_example --features serde");
core::process::exit(1);
}