use nextjson::formats::Format;
use nextjson::{from_str, nextdecode, nextencode, NsonDeserialize, NsonSerialize};
#[derive(Clone, Debug, PartialEq, NsonSerialize, NsonDeserialize)]
struct Record {
id: u64,
active: bool,
score: f64,
name: String,
tags: Vec<String>,
samples: Vec<i64>,
}
#[derive(Clone, Debug, PartialEq, NsonSerialize, NsonDeserialize)]
struct IntRecord {
id: u64,
count: i64,
name: String,
tags: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, NsonSerialize, NsonDeserialize)]
struct UintRecord {
id: u64,
count: u64,
name: String,
tags: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, NsonSerialize, NsonDeserialize)]
struct Doc<T> {
records: Vec<T>,
}
#[derive(Clone, Debug, PartialEq, NsonSerialize, NsonDeserialize)]
struct FlatRow {
id: u64,
active: bool,
score: f64,
name: String,
}
fn records() -> Vec<Record> {
(0..128)
.map(|index| Record {
id: index,
active: index % 3 != 0,
score: index as f64 * 1.25 - 17.5,
name: format!("record-{index:04}"),
tags: vec![
"json".into(),
"zero-copy".into(),
format!("group-{}", index % 8),
],
samples: (0..16).map(|sample| index as i64 * 31 - sample).collect(),
})
.collect()
}
fn main() -> nextjson::Result<()> {
let data = records();
let doc = Doc {
records: data.clone(),
};
let ints: Vec<IntRecord> = data
.iter()
.map(|r| IntRecord {
id: r.id,
count: r.id as i64 * 7 - 3,
name: r.name.clone(),
tags: r.tags.clone(),
})
.collect();
let uints: Vec<UintRecord> = ints
.iter()
.map(|r| UintRecord {
id: r.id,
count: r.count.max(0) as u64,
name: r.name.clone(),
tags: r.tags.clone(),
})
.collect();
let rows: Vec<FlatRow> = (0..128)
.map(|i| FlatRow {
id: i,
active: i % 2 == 0,
score: i as f64 * 0.5,
name: format!("row-{i:04}"),
})
.collect();
println!("{:<10} {:>10} round-trip", "format", "size(B)");
println!("{}", "-".repeat(44));
macro_rules! bench_full {
($($mod:ident),* $(,)?) => {
$(
let bytes = nextjson::formats::$mod.encode(&data)?;
let back: Vec<Record> = nextjson::formats::$mod.decode(&bytes)?;
println!(
"{:<10} {:>10} {}",
<nextjson::formats::$mod as Format>::NAME,
bytes.len(),
if back == data { "ok" } else { "MISMATCH" }
);
)*
};
}
bench_full!(Json, Json5, Hjson, Yaml, Ron, Sexpr, Cbor, MsgPack, Pickle);
macro_rules! bench_doc {
($($mod:ident),* $(,)?) => {
$(
let bytes = nextjson::formats::$mod.encode(&doc)?;
let back: Doc<Record> = nextjson::formats::$mod.decode(&bytes)?;
println!(
"{:<10} {:>10} {}",
<nextjson::formats::$mod as Format>::NAME,
bytes.len(),
if back == doc { "ok" } else { "MISMATCH" }
);
)*
};
}
bench_doc!(Toml, Bson);
let b = nextjson::formats::Bencode.encode(&ints)?;
let back: Vec<IntRecord> = nextjson::formats::Bencode.decode(&b)?;
println!(
"{:<10} {:>10} {}",
<nextjson::formats::Bencode as Format>::NAME,
b.len(),
if back == ints { "ok" } else { "MISMATCH" }
);
let b = nextjson::formats::Postcard.encode(&uints)?;
let back: Vec<UintRecord> = nextjson::formats::Postcard.decode(&b)?;
println!(
"{:<10} {:>10} {}",
<nextjson::formats::Postcard as Format>::NAME,
b.len(),
if back == uints { "ok" } else { "MISMATCH" }
);
let b = nextjson::formats::Csv.encode(&rows)?;
let back: Vec<FlatRow> = nextjson::formats::Csv.decode(&b)?;
println!(
"{:<10} {:>10} {}",
<nextjson::formats::Csv as Format>::NAME,
b.len(),
if back == rows { "ok" } else { "MISMATCH" }
);
println!("\n== 跨格式转码链(不构造中间类型) ==");
let json_bytes = nextjson::formats::Json.encode(&data)?;
let msgpack = nextjson::formats::transcode(
&json_bytes,
nextjson::formats::Json,
nextjson::formats::MsgPack,
)?;
let cbor = nextjson::formats::transcode(
&msgpack,
nextjson::formats::MsgPack,
nextjson::formats::Cbor,
)?;
let json_again =
nextjson::formats::transcode(&cbor, nextjson::formats::Cbor, nextjson::formats::Json)?;
let first: Vec<Record> = nextjson::formats::Json.decode(&json_bytes)?;
let last: Vec<Record> = nextjson::formats::Json.decode(&json_again)?;
println!(
"json {:<6} -> msgpack {:<6} -> cbor {:<6} -> json {:<6} data_equal = {}",
json_bytes.len(),
msgpack.len(),
cbor.len(),
json_again.len(),
first == last
);
println!("\n== 体积对比(同一条 128 条记录数据集) ==");
let sizes = [
("json", nextjson::formats::Json.encode(&data)?.len()),
("cbor", nextjson::formats::Cbor.encode(&data)?.len()),
("msgpack", nextjson::formats::MsgPack.encode(&data)?.len()),
("pickle", nextjson::formats::Pickle.encode(&data)?.len()),
];
let base = sizes[0].1 as f64;
for (name, size) in sizes {
println!(
" {name:<8} {size:>8} B ({:.1}% of json)",
size as f64 / base * 100.0
);
}
assert_eq!(nextdecode::<Vec<Record>>(&nextencode(&data)?)?, data);
let one: Record =
from_str(r#"{"id":1,"active":true,"score":1.25,"name":"r","tags":[],"samples":[]}"#)?;
println!("\n单条 JSON 解析: id = {}", one.id);
Ok(())
}