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"

特性

  1. 支持将JSON序列化为Rust结构体,类似于serde_jsonserde
  2. 为无类型的sonic_rs::Value解析/序列化JSON,可修改
  3. 以极高性能从JSON中获取特定字段
  4. 将JSON作为惰性数组或对象迭代器使用
  5. 默认支持LazyValueNumberRawNumber(类似于Golang的JsonNumber)
  6. 默认情况下浮点解析精度与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的主要功能:

  1. 将JSON解析为强类型Rust结构体
  2. 将结构体序列化为紧凑和格式化的JSON字符串
  3. 将JSON解析为可修改的无类型Value
  4. 修改Value中的嵌套字段
  5. 使用JSON指针访问特定字段
  6. 使用LazyValue进行惰性解析
  7. 处理精确数字而不丢失精度
  8. 动态构建新的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}
}

性能提示

  1. 对于重复使用的 JSON 数据,考虑使用 LazyValue 进行惰性解析
  2. 处理大文件时使用流式解析器
  3. 预分配缓冲区可以提高序列化性能

注意事项

  • 确保输入是有效的 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);
}

这个完整示例展示了:

  1. 从JSON字符串解析为JsonValue
  2. 从JSON字符串解析为自定义结构体
  3. 修改数据后重新序列化为JSON(紧凑和美化格式)
  4. 处理JSON字节流

所有操作都使用了sonic-rs提供的高性能API,适合生产环境使用。

回到顶部