#[cfg(feature = "serde")]
fn main() {
use qtty::{Kilometer, Meter, Second};
use serde::{Deserialize, Serialize};
use serde_json;
println!("=== Using serde_with_unit Helper ===\n");
println!("1. Basic Usage - Per-Field Control:\n");
#[derive(Serialize, Deserialize, Debug)]
struct SensorData {
#[serde(with = "qtty_core::serde_with_unit")]
max_range: Meter,
current_distance: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
timestamp: Second,
}
let data = SensorData {
max_range: Meter::new(100.0),
current_distance: Meter::new(42.5),
timestamp: Second::new(1702562400.0),
};
let json = serde_json::to_string_pretty(&data).unwrap();
println!("Serialized:\n{}\n", json);
let restored: SensorData = serde_json::from_str(&json).unwrap();
println!("Deserialized successfully!");
println!(" max_range: {}", restored.max_range);
println!(" current_distance: {}", restored.current_distance);
println!(" timestamp: {}\n", restored.timestamp);
println!("2. Self-Documenting API Response:\n");
#[derive(Serialize, Deserialize, Debug)]
struct WeatherReport {
station_id: String,
#[serde(with = "qtty_core::serde_with_unit")]
temperature_celsius: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
wind_speed: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
visibility: Kilometer,
}
let report = WeatherReport {
station_id: "KJFK".to_string(),
temperature_celsius: Meter::new(22.0),
wind_speed: Meter::new(5.5),
visibility: Kilometer::new(10.0),
};
let json = serde_json::to_string_pretty(&report).unwrap();
println!("Weather API Response:\n{}\n", json);
println!("3. Configuration File Format:\n");
#[derive(Serialize, Deserialize, Debug)]
struct RobotConfig {
name: String,
#[serde(with = "qtty_core::serde_with_unit")]
max_speed: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
safe_distance: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
timeout: Second,
calibration_offset: Meter,
}
let config = RobotConfig {
name: "R2D2".to_string(),
max_speed: Meter::new(2.5),
safe_distance: Meter::new(0.5),
timeout: Second::new(30.0),
calibration_offset: Meter::new(0.001),
};
let json = serde_json::to_string_pretty(&config).unwrap();
println!("Robot Configuration:\n{}\n", json);
println!("4. Unit Validation:\n");
#[derive(Serialize, Deserialize, Debug)]
struct SingleValue {
#[serde(with = "qtty_core::serde_with_unit")]
distance: Meter,
}
let valid_json = r#"{"distance": {"value": 100.0, "unit": "m"}}"#;
let data: SingleValue =
serde_json::from_str(valid_json).expect("Should deserialize with matching unit");
println!("✓ Valid JSON with correct unit: {}", data.distance);
let no_unit_json = r#"{"distance": {"value": 50.0}}"#;
let data2: SingleValue =
serde_json::from_str(no_unit_json).expect("Should work without unit field");
println!("✓ Valid JSON without unit field: {}", data2.distance);
let invalid_json = r#"{"distance": {"value": 100.0, "unit": "kg"}}"#;
match serde_json::from_str::<SingleValue>(invalid_json) {
Ok(_) => println!("✗ Unexpected success with wrong unit"),
Err(e) => println!("✓ Correctly rejected wrong unit: {}", e),
}
println!();
println!("5. Collections:\n");
#[derive(Serialize, Deserialize, Debug)]
struct Measurement {
id: u32,
#[serde(with = "qtty_core::serde_with_unit")]
value: Meter,
}
let measurements = vec![
Measurement {
id: 1,
value: Meter::new(10.0),
},
Measurement {
id: 2,
value: Meter::new(20.0),
},
Measurement {
id: 3,
value: Meter::new(30.0),
},
];
let json = serde_json::to_string_pretty(&measurements).unwrap();
println!("Measurement Array:\n{}\n", json);
println!("6. Nested Structures:\n");
#[derive(Serialize, Deserialize, Debug)]
struct Location {
name: String,
coordinates: Coordinates,
}
#[derive(Serialize, Deserialize, Debug)]
struct Coordinates {
#[serde(with = "qtty_core::serde_with_unit")]
x: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
y: Meter,
#[serde(with = "qtty_core::serde_with_unit")]
z: Meter,
}
let location = Location {
name: "Observatory".to_string(),
coordinates: Coordinates {
x: Meter::new(100.0),
y: Meter::new(200.0),
z: Meter::new(50.0),
},
};
let json = serde_json::to_string_pretty(&location).unwrap();
println!("Nested structure:\n{}\n", json);
println!("=== Summary ===\n");
println!("✓ Use #[serde(with = \"qtty_core::serde_with_unit\")] for:");
println!(" • External/public APIs");
println!(" • Configuration files");
println!(" • Self-documenting data");
println!(" • When consumers might not know the units");
println!();
println!("✓ Use default serialization (no attribute) for:");
println!(" • Internal APIs");
println!(" • Performance-critical code");
println!(" • Large datasets");
println!(" • When types provide sufficient documentation");
println!();
println!("✓ Mix both in the same struct as needed!");
}
#[cfg(not(feature = "serde"))]
fn main() {
println!("This example requires the 'serde' feature.");
println!("Run with: cargo run --example serde_with_unit --features serde");
}