#serde-json #json #serialization #json-format #serde

no-std serde_json_pythonic

包含Pythonic JSON格式化器的serde_json_pythonic分支

1个不稳定版本

0.1.2 2023年7月1日
0.1.1 2023年6月27日
0.1.0 2023年6月27日

#1468 in 编码

Download history 2419/week @ 2024-03-16 3203/week @ 2024-03-23 1970/week @ 2024-03-30 2503/week @ 2024-04-06 2255/week @ 2024-04-13 1886/week @ 2024-04-20 2203/week @ 2024-04-27 1604/week @ 2024-05-04 2114/week @ 2024-05-11 2142/week @ 2024-05-18 2093/week @ 2024-05-25 2457/week @ 2024-06-01 2777/week @ 2024-06-08 4144/week @ 2024-06-15 4543/week @ 2024-06-22 1999/week @ 2024-06-29

13,804 每月下载量
30 个crate中(2个直接使用)使用

MIT/Apache

525KB
12K SLoC

serde_json_pythonic

serde_json分支,包含一个Pythonic JSON格式化器,它模仿Python中json.dumps()函数的输出。

虽然在不修改serde_json的情况下创建这样的格式化器是可能的,但它仅在启用std功能时才有效,因为在no_std模式下,serde_json不公开格式化器实现所需的类型。此分支使此类格式化器内置,并在no_std下可用。


lib.rs:

Serde JSON

JSON是一种无处不在的开放标准格式,它使用人类可读的文本来传输由键值对组成的数据对象。

{
    "name": "John Doe",
    "age": 43,
    "address": {
        "street": "10 Downing Street",
        "city": "London"
    },
    "phones": [
        "+44 1234567",
        "+44 2345678"
    ]
}

在Rust中,你可能需要以以下三种常见方式处理JSON数据。

  • 作为文本数据。一个未经处理的JSON数据字符串,你可能从HTTP端点接收、从文件中读取或准备发送到远程服务器。
  • 作为无类型或松散类型的表示。你可能想要在传递之前检查一些JSON数据是否有效,但不知道它包含的结构。或者你想要执行非常基本的操作,如在一个特定的位置插入一个键。
  • 作为强类型的Rust数据结构。当你期望所有或大部分数据都符合特定的结构,并且想要在没有JSON松散特性的干扰下完成实际工作。

Serde JSON提供了一种高效、灵活、安全的方法来在不同表示之间转换数据。

操作无类型的JSON值

任何有效的JSON数据都可以以下递归枚举表示来操作。此数据结构为serde_json_pythonic::Value

#
enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

可以通过 serde_json_pythonic::from_str 函数将 JSON 数据解析为 serde_json_pythonic::Value 类型。此外,还有 from_slice 用于从字节切片 &[u8] 解析和 from_reader 用于从任何类似文件或 TCP 流的 io::Read 对象解析。

use serde_json_pythonic::{Result, Value};

fn untyped_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into serde_json_pythonic::Value.
    let v: Value = serde_json_pythonic::from_str(data)?;

    // Access parts of the data by indexing with square brackets.
    println!("Please call {} at the number {}", v["name"], v["phones"][0]);

    Ok(())
}
#

类似于 v["name"] 的方括号索引结果是该索引处的数据引用,因此类型为 &Value。JSON 地图可以使用字符串键索引,而 JSON 数组可以使用整数键索引。如果数据的类型不适合用于索引的类型,或者映射中不包含要索引的键,或者向量的索引超出范围,则返回的元素是 Value::Null

当打印 Value 时,它将以 JSON 字符串的形式打印出来。因此,在上述代码中,输出看起来像 Please call "John Doe" at the number "+44 1234567"。引号出现是因为 v["name"] 是一个 &Value,它包含一个 JSON 字符串,其 JSON 表示为 "John Doe"。要打印不带引号的普通字符串,涉及将 JSON 字符串转换为 Rust 字符串,使用 as_str() 或避免在下一节中描述的 Value 的使用。

Value 表示对于非常基本的任务来说足够了,但如果是更重要的任务,则可能很繁琐。错误处理实现起来很繁琐,例如,想象一下尝试检测输入数据中未知字段的存在。当您犯错时,编译器无法帮助您,例如,想象一下在一个使用几十次的地方将 v["name"] 错误地拼写成 v["nmae"]

将 JSON 解析为强类型数据结构

Serde 提供了一种强大的方法,可以将 JSON 数据自动映射到 Rust 数据结构中。

use serde::{Deserialize, Serialize};
use serde_json_pythonic::Result;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

fn typed_example() -> Result<()> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }"#;

    // Parse the string of data into a Person object. This is exactly the
    // same function as the one that produced serde_json_pythonic::Value above, but
    // now we are asking it for a Person as output.
    let p: Person = serde_json_pythonic::from_str(data)?;

    // Do things just like with any other Rust data structure.
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    Ok(())
}
#

这与之前的 serde_json_pythonic::from_str 函数相同,但这次我们将返回值赋给一个 Person 类型的变量,这样 Serde 将自动将输入数据解释为 Person,如果布局不符合 Person 预期的外观,则产生有信息的错误消息。

任何实现了Serde的Deserialize特质的类型都可以通过这种方式反序列化。这包括Rust标准库中的内置类型,如Vec<T>HashMap<K, V>,以及任何带有#[derive(Deserialize)]注解的结构体或枚举。

一旦我们有了类型为Personp,我们的IDE和Rust编译器可以帮助我们正确使用它,就像它们对任何其他Rust代码所做的那样。IDE可以自动完成字段名以防止输入错误,这在serde_json_pythonic::Value表示中是不可能的。并且Rust编译器可以检查当我们编写p.phones[0]时,p.phones保证是一个Vec<String>,所以对其索引是有意义的,并生成一个String

构建JSON值

Serde JSON提供了一个json!,用于使用非常自然的JSON语法构建serde_json_pythonic::Value对象。

use serde_json_pythonic::json;

fn main() {
    // The type of `john` is `serde_json_pythonic::Value`
    let john = json!({
        "name": "John Doe",
        "age": 43,
        "phones": [
            "+44 1234567",
            "+44 2345678"
        ]
    });

    println!("first phone number: {}", john["phones"][0]);

    // Convert to a string of JSON and print it out
    println!("{}", john.to_string());
}

Value::to_string()函数将一个serde_json_pythonic::Value转换为一个JSON文本的String

关于json!宏的一个有趣之处是,变量和表达式可以直接在构建JSON值时插入。Serde将在编译时检查您插入的值是否能够表示为JSON。

#
#
let full_name = "John Doe";
let age_last_year = 42;

// The type of `john` is `serde_json_pythonic::Value`
let john = json!({
    "name": full_name,
    "age": age_last_year + 1,
    "phones": [
        format!("+44 {}", random_phone())
    ]
});

这非常方便,但我们又回到了之前Value的问题:如果出错,IDE和Rust编译器无法帮助我们。Serde JSON提供了将强类型数据结构序列化为JSON文本的更好方式。

通过序列化数据结构创建JSON

可以通过serde_json_pythonic::to_string将数据结构转换为JSON字符串。还有一个serde_json_pythonic::to_vec,它将序列化为一个Vec<u8>,以及serde_json_pythonic::to_writer,它将序列化为任何io::Write,例如文件或TCP流。

use serde::{Deserialize, Serialize};
use serde_json_pythonic::Result;

#[derive(Serialize, Deserialize)]
struct Address {
    street: String,
    city: String,
}

fn print_an_address() -> Result<()> {
    // Some data structure.
    let address = Address {
        street: "10 Downing Street".to_owned(),
        city: "London".to_owned(),
    };

    // Serialize it to a JSON string.
    let j = serde_json_pythonic::to_string(&address)?;

    // Print, write to a file, or send to an HTTP server.
    println!("{}", j);

    Ok(())
}
#

任何实现了 Serde 的 Serialize 特性的类型都可以用这种方式序列化。这包括 Rust 标准库中的内置类型,如 Vec<T>HashMap<K, V>,以及任何带有 #[derive(Serialize)] 注解的结构体或枚举。

无标准库支持

只要有内存分配器,就可以在不使用 Rust 标准库的情况下使用 serde_json_pythonic。禁用默认的 "std" 功能并启用 "alloc" 功能。

[dependencies]
serde_json_pythonic = { version = "1.0", default-features = false, features = ["alloc"] }

关于没有内存分配器的 Serde JSON 支持,请参阅 serde-json-core 包。

依赖关系

~155–590KB
~12K SLoC