Rust JSON处理库sonic-rs的使用:高性能JSON解析与序列化,支持UTF-8和字节流高效转换
Rust JSON处理库sonic-rs的使用:高性能JSON解析与序列化,支持UTF-8和字节流高效转换
sonic-rs是一个基于SIMD的快速Rust JSON库。它参考了其他开源库如sonic_cpp、serde_json、sonic、simdjson和rust-std等。
快速使用sonic-rs
在Cargo.toml中添加依赖:
[dependencies]
sonic-rs = "0.3"
特性
- 支持将JSON序列化为Rust结构体,类似于
serde_json
和serde
- 为无类型的
sonic_rs::Value
解析/序列化JSON,可修改 - 以极高性能从JSON中获取特定字段
- 将JSON作为惰性数组或对象迭代器使用
- 默认支持
LazyValue
、Number
和RawNumber
(类似于Golang的JsonNumber
) - 默认情况下浮点解析精度与Rust标准库一致
使用示例
将JSON序列化为Rust类型
use sonic_rs::{Deserialize, Serialize};
// 或者使用 serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
age: u8,
phones: Vec<String>,
}
fn main() {
let data = r#"{
"name": "Xiaoming",
"age": 18,
"phones": [
"+123456"
]
}"#;
let p: Person = sonic_rs::from_str(data).unwrap();
assert_eq!(p.age, 18);
assert_eq!(p.name, "Xiaoming");
let out = sonic_rs::to_string_pretty(&p).unwrap();
assert_eq!(out, data);
}
从JSON中获取字段
use sonic_rs::JsonValueTrait;
use sonic_rs::{get, get_unchecked, pointer};
fn main() {
let path = pointer!["a", "b", "c", 1];
let json = r#"
{"u": 123, "a": {"b" : {"c": [null, "found"]}}}
"#;
let target = unsafe { get_unchecked(json, &path).unwrap() };
assert_eq!(target.as_raw_str(), r#""found""#);
assert_eq!(target.as_str().unwrap(), "found");
let target = get(json, &path);
assert_eq!(target.as_str().unwrap(), "found");
assert_eq!(target.unwrap().as_raw_str(), r#""found""#);
let path = pointer!["a", "b", "c", "d"];
let json = r#"
{"u": 123, "a": {"b" : {"c": [null, "found"]}}}
"#;
// 从JSON中未找到
let target = get(json, &path);
assert!(target.is_err());
}
解析和序列化为无类型Value
use sonic_rs::{from_str, json};
use sonic_rs::JsonValueMutTrait;
use sonic_rs::{pointer, JsonValueTrait, Value};
fn main() {
let json = r#"{
"name": "Xiaoming",
"obj": {},
"arr": [],
"age": 18,
"address": {
"city": "Beijing"
},
"phones": [
"+123456"
]
}"#;
let mut root: Value = from_str(json).unwrap();
// 从value中获取键
let age = root.get("age").as_i64();
assert_eq!(age.unwrap_or_default(), 18);
// 通过索引获取
let first = root["phones"][0].as_str().unwrap();
assert_eq!(first, "+123456");
// 通过指针获取
let phones = root.pointer(&pointer!["phones", 0]);
assert_eq!(phones.as_str().unwrap(), "+123456");
// 转换为可变对象
let obj = root.as_object_mut().unwrap();
obj.insert(&"inserted", true);
assert!(obj.contains_key(&"inserted"));
let mut object = json!({ "A": 65, "B": 66, "C": 67 });
*object.get_mut("A").unwrap() = json!({
"code": 123,
"success": false,
"payload": {}
});
let mut val = json!(["A", "B", "C"]);
*val.get_mut(2).unwrap() = json!("D");
// 序列化
assert_eq!(serde_json::to_string(&val).unwrap(), r#"["A","B","D"]"#);
}
JSON迭代器
use bytes::Bytes;
use faststr::FastStr;
use sonic_rs::JsonValueTrait;
use sonic_rs::{to_array_iter, to_object_iter_unchecked};
fn main() {
let json = Bytes::from(r#"[1, 2, 3, 4, 5, 6]"#);
let iter = to_array_iter(&json);
for (i, v) in iter.enumerate() {
assert_eq!(i + 1, v.as_u64().unwrap() as usize);
}
let json = Bytes::from(r#"[1, 2, 3, 4, 5, 6"#);
let iter = to_array_iter(&json);
for elem in iter {
// 对每个元素执行操作
// 当JSON无效时处理错误
if elem.is_err() {
assert_eq!(
elem.err().unwrap().to_string(),
"Expected this character to be either a ',' or a ']' while parsing at line 1 column 17"
);
}
}
let json = FastStr::from(r#"{"a": null, "b":[1, 2, 3]}"#);
let iter = unsafe { to_object_iter_unchecked(&json) };
for ret in iter {
// 处理错误
if ret.is_err() {
println!("{}", ret.unwrap_err());
return;
}
let (k, v) = ret.unwrap();
if k == "a" {
assert!(v.is_null());
} else if k == "b" {
let iter = to_array_iter(v.as_raw_str());
for (i, v) in iter.enumerate() {
assert_eq!(i + 1, v.as_u64().unwrap() as usize);
}
}
}
}
完整示例
下面是一个更完整的示例,展示了sonic-rs的更多功能:
use sonic_rs::{
Deserialize, Serialize, from_str, to_string, to_string_pretty,
json, pointer, JsonValueTrait, Value, LazyValue, Number
};
// 定义用户结构体
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
is_active: bool,
roles: Vec<String>,
metadata: Value, // 无类型元数据
balance: Number, // 精确数字处理
}
fn main() {
// 1. 从字符串解析JSON到结构体
let json_data = r#"{
"id": 12345,
"name": "Alice",
"email": "alice@example.com",
"is_active": true,
"roles": ["admin", "user"],
"metadata": {
"preferences": {
"theme": "dark",
"notifications": true
}
},
"balance": "1234.5678"
}"#;
let user: User = from_str(json_data).unwrap();
println!("解析后的用户: {:?}", user);
// 2. 结构体序列化为紧凑JSON
let compact_json = to_string(&user).unwrap();
println!("紧凑JSON:\n{}", compact_json);
// 3. 结构体序列化为格式化JSON
let pretty_json = to_string_pretty(&user).unwrap();
println!("格式化JSON:\n{}", pretty_json);
// 4. 解析为无类型Value并修改
let mut value: Value = from_str(json_data).unwrap();
value["name"] = json!("Bob");
value["roles"].as_array_mut().unwrap().push(json!("editor"));
value["metadata"]["preferences"]["theme"] = json!("light");
// 5. 使用指针访问嵌套字段
let theme = value.pointer(&pointer!["metadata", "preferences", "theme"]);
println!("主题: {}", theme.as_str().unwrap());
// 6. 使用LazyValue进行惰性解析
let lazy: LazyValue = sonic_rs::from_str(json_data).unwrap();
let roles = lazy.pointer(&pointer!["roles"]).as_array().unwrap();
println!("角色数量: {}", roles.len());
// 7. 处理精确数字
let balance = user.balance.as_f64().unwrap();
println!("余额: {:.4}", balance);
// 8. 构建新的JSON对象
let new_data = json!({
"user": value,
"timestamp": 1680000000,
"tags": ["rust", "json", "performance"]
});
println!("新构建的JSON:\n{}", to_string_pretty(&new_data).unwrap());
}
这个完整示例展示了sonic-rs的主要功能:
- 将JSON解析为强类型Rust结构体
- 将结构体序列化为紧凑和格式化的JSON字符串
- 将JSON解析为可修改的无类型Value
- 修改Value中的嵌套字段
- 使用JSON指针访问特定字段
- 使用LazyValue进行惰性解析
- 处理精确数字而不丢失精度
- 动态构建新的JSON对象
sonic-rs提供了高性能的JSON处理能力,特别适合需要快速解析和序列化大型JSON数据的场景。通过SIMD加速和精心优化的算法,它在处理JSON数据时能提供比标准库更快的性能。
1 回复
Rust JSON处理库sonic-rs的使用:高性能JSON解析与序列化
简介
sonic-rs 是一个高性能的 Rust JSON 处理库,专注于快速解析和序列化 JSON 数据。它特别优化了对 UTF-8 和字节流的处理,适合需要高性能 JSON 操作的场景。
主要特性
- 高性能的 JSON 解析和序列化
- 支持 UTF-8 和字节流的高效转换
- 符合 JSON 标准
- 提供友好的 API 接口
安装
在 Cargo.toml 中添加依赖:
[dependencies]
sonic-rs = "0.1"
基本用法
解析 JSON
use sonic_rs::{from_str, JsonValue};
fn main() {
let json_str = r#"{"name": "Alice", "age": 25, "is_student": true}"#;
// 解析为 JsonValue
let value: JsonValue = from_str(json_str).unwrap();
println!("Name: {}", value["name"].as_str().unwrap());
println!("Age: {}", value["age"].as_u64().unwrap());
// 解析为自定义结构体
#[derive(Debug, serde::Deserialize)]
struct Person {
name: String,
age: u8,
is_student: bool,
}
let person: Person = from_str(json_str).unwrap();
println!("{:?}", person);
}
序列化为 JSON
use sonic_rs::{to_string, to_string_pretty};
#[derive(serde::Serialize)]
struct User {
id: u64,
username: String,
active: bool,
}
fn main() {
let user = User {
id: 1,
username: "sonic_user".to_string(),
active: true,
};
// 紧凑格式
let json_str = to_string(&user).unwrap();
println!("{}", json_str);
// 美化格式
let pretty_json = to_string_pretty(&user).unwrap();
println!("{}", pretty_json);
}
字节流处理
use sonic_rs::{from_slice, to_vec};
fn main() {
// 从字节切片解析
let bytes = br#"{"key": "value"}"#;
let value: JsonValue = from_slice(bytes).unwrap();
println!("{}", value["key"].as_str().unwrap());
// 序列化为字节向量
let data = vec!["a", "b", "c"];
let json_bytes = to_vec(&data).unwrap();
println!("{:?}", json_bytes);
}
高级用法
流式解析大文件
use sonic_rs::{Deserializer, JsonValue};
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("large_file.json")?;
let mut deserializer = Deserializer::from_reader(file);
// 流式处理数组元素
while let Some(value) = deserializer.next_value::<JsonValue>()? {
// 处理每个值
println!("Got value: {}", value);
}
Ok(())
}
自定义序列化
use sonic_rs::to_string;
use serde::Serialize;
#[derive(Serialize)]
struct Custom {
#[serde(rename = "userId")]
id: u64,
#[serde(skip_serializing_if = "Option::is_none")]
name: Option<String>,
}
fn main() {
let data = Custom {
id: 123,
name: None,
};
let json = to_string(&data).unwrap();
println!("{}", json); // 输出: {"userId":123}
}
性能提示
- 对于重复使用的 JSON 数据,考虑使用
LazyValue
进行惰性解析 - 处理大文件时使用流式解析器
- 预分配缓冲区可以提高序列化性能
注意事项
- 确保输入是有效的 UTF-8 编码(除非使用字节接口)
- 错误处理很重要,生产代码中应该妥善处理所有可能的错误
- 对于特别大的 JSON 文档,考虑使用流式处理以避免内存问题
sonic-rs 是 Rust 生态中一个强大的 JSON 处理工具,特别适合性能敏感的应用场景。
完整示例代码
下面是一个综合使用 sonic-rs 的完整示例,展示了从解析到序列化的完整流程:
use sonic_rs::{from_str, to_string, to_string_pretty, JsonValue};
use serde::{Deserialize, Serialize};
// 自定义数据结构
#[derive(Debug, Serialize, Deserialize)]
struct Employee {
id: u32,
name: String,
department: String,
skills: Vec<String>,
#[serde(default)]
is_manager: bool,
}
fn main() {
// 示例JSON字符串
let json_str = r#"
{
"id": 1001,
"name": "John Doe",
"department": "Engineering",
"skills": ["Rust", "Python", "JavaScript"],
"is_manager": true
}"#;
// 1. 解析为JsonValue
let json_value: JsonValue = from_str(json_str).unwrap();
println!("Employee name: {}", json_value["name"].as_str().unwrap());
println!("First skill: {}", json_value["skills"][0].as_str().unwrap());
// 2. 解析为自定义结构体
let employee: Employee = from_str(json_str).unwrap();
println!("Parsed employee: {:?}", employee);
// 3. 修改并重新序列化
let mut employee = employee;
employee.skills.push("Go".to_string());
employee.is_manager = false;
// 紧凑格式序列化
let compact_json = to_string(&employee).unwrap();
println!("Compact JSON:\n{}", compact_json);
// 美化格式序列化
let pretty_json = to_string_pretty(&employee).unwrap();
println!("Pretty JSON:\n{}", pretty_json);
// 4. 处理字节流
let bytes = compact_json.as_bytes();
let parsed_back: Employee = sonic_rs::from_slice(bytes).unwrap();
println!("Parsed back from bytes: {:?}", parsed_back);
}
这个完整示例展示了:
- 从JSON字符串解析为JsonValue
- 从JSON字符串解析为自定义结构体
- 修改数据后重新序列化为JSON(紧凑和美化格式)
- 处理JSON字节流
所有操作都使用了sonic-rs提供的高性能API,适合生产环境使用。