1个不稳定版本

0.1.0 2023年12月2日

#2626 in 解析器实现

MIT/Apache

76KB
1K SLoC

ndjson-stream

ndjson-stream 提供了多种NDJSON解析器,这些解析器接受数据块,并在读取更多内容之前处理这些块,从而实现流式使用。解析器接受多种输入,这些输入表示字节切片,例如 Vec<u8>&strndjson-stream 使用 serde_json crate 来解析单独的行。

高级示例

以下我们将查看迭代器接口。最基本的形式可以用 from_iter 实例化。我们必须提供一个数据块的迭代器,并获取解析NDJSON记录的迭代器。实际上,确切的返回类型是 Result,它可能包含JSON错误,例如一行不是有效的JSON或不符合输出类型的模式。

以下示例演示了正常路径和解析错误。

use serde::Deserialize;

#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Person {
    name: String,
    age: u16
}

let data_blocks = vec![
    "{\"name\":\"Alice\",\"age\":25}\n",
    "{\"this\":\"is\",\"not\":\"valid\"}\n",
    "{\"name\":\"Bob\",",
    "\"age\":35}\r\n"
];

let mut ndjson_iter = ndjson_stream::from_iter::<Person, _>(data_blocks);

assert_eq!(ndjson_iter.next().unwrap().unwrap(), Person { name: "Alice".into(), age: 25 });
assert!(ndjson_iter.next().unwrap().is_err());
assert_eq!(ndjson_iter.next().unwrap().unwrap(), Person { name: "Bob".into(), age: 35 });
assert!(ndjson_iter.next().is_none());

配置

有几种配置选项可用于控制解析器在特定情况下的行为。

以下示例中,我们构建了一个忽略空行的NDJSON迭代器。也就是说,它不会为仅由空白组成的任何行生成输出记录,而不是尝试解析它并引发JSON错误。

use ndjson_stream::config::{EmptyLineHandling, NdjsonConfig};
use serde::Deserialize;

#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Person {
    name: String,
    age: u16
}

let data_blocks = vec![
    "{\"name\":\"Charlie\",\"age\":32}\n",
    "   \n",
    "{\"name\":\"Dolores\",\"age\":41}\n"
];
let config = NdjsonConfig::default().with_empty_line_handling(EmptyLineHandling::IgnoreBlank);

let mut ndjson_iter = ndjson_stream::from_iter_with_config::<Person, _>(data_blocks, config);

assert_eq!(ndjson_iter.next().unwrap().unwrap(), Person { name: "Charlie".into(), age: 32 });
assert_eq!(ndjson_iter.next().unwrap().unwrap(), Person { name: "Dolores".into(), age: 41 });
assert!(ndjson_iter.next().is_none());

可靠性

除了普通接口外,每个接口还有一个不可靠的对应版本。"不可靠"在此上下文中指的是输入数据源 - 在上面的示例中是 data_blocks 的迭代器。不可靠的解析器接受返回包含某些错误类型的 Result 的数据源,并将潜在的读取错误传递给用户。

以下示例中使用了不可靠的迭代器。

use ndjson_stream::fallible::FallibleNdjsonError;
use serde::Deserialize;

#[derive(Debug, Deserialize, Eq, PartialEq)]
struct Person {
    name: String,
    age: u16
}

let data_blocks = vec![
    Ok("{\"name\":\"Eve\",\"age\":22}\n"),
    Err("error"),
    Ok("{\"invalid\":json}\n")
];

let mut ndjson_iter = ndjson_stream::from_fallible_iter::<Person, _>(data_blocks);

assert_eq!(ndjson_iter.next().unwrap().unwrap(), Person { name: "Eve".into(), age: 22 });
assert!(matches!(ndjson_iter.next(), Some(Err(FallibleNdjsonError::InputError("error")))));
assert!(matches!(ndjson_iter.next(), Some(Err(FallibleNdjsonError::JsonError(_)))));
assert!(ndjson_iter.next().is_none());

有关如何使用 ndjson-stream crate 的更多信息,请参阅 crate 文档

依赖项

~0.7–1.6MB
~36K SLoC