serde_nt 0.1.12

NestedText (de)serialization for serde, powered by nt_syntax
Documentation
# serde_nt

[NestedText](https://nestedtext.org) (de)serialization for [serde].

NestedText is a human-friendly configuration and data format: `key: value`
dictionaries, `- item` lists and `> text` blocks, with no quoting and no
escaping, and with every leaf stored as a string.  This crate maps that data
model onto Rust types through `serde`, in both directions.

- Parses straight into your types, borrowed (`&str`, `Cow<'_, str>`) or owned.
- Writes back with a stable, human-readable layout (2-space indent, `>` blocks
  for multiline values, multiline keys for keys that cannot be written inline).
- Reports errors with the same message text and line numbers as the reference
  NestedText implementation.
- Passes the complete official NestedText test suite (see *Conformance*).

[serde]: https://serde.rs

## Install

```bash
cargo add serde_nt
```

## Usage

```rust
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Conf {
  host: String,
  port: u16,
  debug: bool,
  tag_li: Vec<String>,
}

let text = r#"
host: example.com
port: 8080
debug: no
tag_li:
    - alpha
    - beta
"#;

let conf: Conf = serde_nt::from_str(text)?;
assert_eq!(conf.port, 8080);
assert!(!conf.debug);

let out = serde_nt::to_string(&conf)?;
assert_eq!(serde_nt::from_str::<Conf>(&out)?, conf);
# Ok::<(), serde_nt::Error>(())
```

Public API:

| Item | Purpose |
| --- | --- |
| `from_str::<T>(&str)` | parse NestedText text into `T` |
| `to_string(&T)` | serialize `T` into NestedText text |
| `from_value`, `to_value`, `dumps` | the same two directions over an already-parsed value tree |
| `Error`, `Result` | error type, carries the document error with its line number |

## Type mapping

- Strings map to strings, and are parsed into numbers, booleans, `char` and
  other `FromStr` types on demand; output uses `itoa` / `zmij`.
- `Option<T>`: an empty value is `None`, a present value is `Some`.
- Lists, maps, tuples and structs map to NestedText lists and dictionaries.
- Enums map to a string or to a single-entry dictionary, so both unit and
  data-carrying variants work.
- `#[serde(untagged)]` and `#[serde(borrow)]` are supported; borrowed
  deserialization avoids copying strings.

## Writing rules

- Indent is 2 spaces; multiline values are written as `>` blocks.
- Keys that cannot be written inline (embedded `: `, leading/trailing spaces,
  tabs, newlines) become multiline keys.
- `\r\n` and bare `\r` are normalized to `\n` on write.

## Errors

NestedText has no schema, so every error is a document error and is reported by
line.  Error messages are kept 1:1 with the reference implementation, e.g.
`invalid indentation.`, `duplicate key: name.`, `expected ‘:’, found ‘}’.`,
`extra characters after closing delimiter: ‘b]’.`, and the line numbers agree
with the reference on all official test cases.

## Conformance

The official NestedText test suite
([`nestedtext_tests`](https://github.com/KenKundert/nestedtext_tests)) is part of
this repository and run on every build:

- all 148 cases: 68 invalid documents and 80 valid documents (5 of which load to
  `null` for empty or comment-only input);
- invalid documents: the error message and the line number are compared with the
  reference value of every case;
- valid documents: the parsed result is compared with the reference output, and
  additionally round-tripped through `to_string` back into `from_str`.

```bash
cargo test -p serde_nt
```

## Performance

Measured against [`nested-text`](https://crates.io/crates/nested-text) on
a 200-entry nested dictionary, aarch64 (Apple M-series), release profile, time
and allocations per operation:

| Operation | `serde_nt` | `nested-text` | Allocations |
| --- | --- | --- | --- |
| parse into Rust types | 168 µs borrowed, 220 µs owned | 728 µs | 638 / 2,438 vs 17,682 |
| serialize to text | 153 µs | 489 µs | 4 vs 10,415 |

## Limitations

- Byte arrays are not supported: NestedText has no binary type.
- Dictionary keys must serialize to strings; a list or dictionary used as a key
  is an error.

## License

Apache-2.0.

---

# serde_nt(中文)

[NestedText](https://nestedtext.org) 的 [serde](https://serde.rs) 序列化 /
反序列化。

NestedText 是面向人类的配置与数据格式:`key: value` 字典、`- item` 列表、`> text`
多行块,无引号无转义,叶子一律为字符串。本 crate 通过 `serde` 在该数据模型与
Rust 类型之间双向映射。

- 直接解析到目标类型,支持借用(`&str`、`Cow<'_, str>`)与拥有两种模式。
- 写回布局稳定可读:2 空格缩进、多行值写 `>` 块、无法单行写出的键写多行键。
- 错误文案与行号同官方实现逐字一致。
- 官方 NestedText 测试集全量通过(见「一致性」)。

## 安装

```bash
cargo add serde_nt
```

## 用法

见上方英文示例:`serde_nt::from_str` 解析、`serde_nt::to_string` 写回;
另有 `from_value` / `to_value` / `dumps`,在已解析的值树上做同一组双向转换。

## 类型映射

- 字符串原样;数字、布尔、`char` 及实现了 `FromStr` 的类型按字符串解析,
  输出用 `itoa` / `zmij`。
- `Option<T>`:空值为 `None`,有值为 `Some`。
- 列表、映射、元组、struct 对应 NT 列表与字典。
- 枚举对应字符串或单键字典,单元变体与带数据变体都可用。
- 支持 `#[serde(untagged)]` 与 `#[serde(borrow)]`,借用反序列化零拷贝。

## 写回规则

- 缩进 2 空格;多行值写 `>` 块。
- 不能单行写出的键(含 `: `、首尾空白、制表符、换行)改写为多行键。
- `\r\n` 与裸 `\r` 统一归一为 `\n`。

## 错误

NestedText 无 schema,所有错误都是文档错误并按行报告。文案与官方实现逐字一致,
如 `invalid indentation.`、`duplicate key: name.`、`expected ‘:’, found ‘}’.`、
`extra characters after closing delimiter: ‘b]’.`;官方测试集覆盖的全部用例中行号也一致。

## 一致性

官方 NestedText 测试集
([`nestedtext_tests`](https://github.com/KenKundert/nestedtext_tests))随仓库内置,
每次构建全量跑:

- 148 个用例:68 个非法、80 个合法(其中 5 个空文档/纯注释输入解析为 `null`);
- 非法文档:错误文案与行号逐个同官方真值比对;
- 合法文档:解析结果同官方真值比对,并额外做写回往返(解析 → 写回 → 再解析)。

```bash
cargo test -p serde_nt
```

## 性能

与 [`nested-text`](https://crates.io/crates/nested-text) 对比
(200 条嵌套字典,aarch64 Apple M 系列,release 构建,每次操作耗时与分配次数):

| 操作 | `serde_nt` | `nested-text` | 分配次数 |
| --- | --- | --- | --- |
| 解析为 Rust 类型 | 168 µs(借用)/ 220 µs(拥有) | 728 µs | 638 / 2,438 vs 17,682 |
| 序列化为文本 | 153 µs | 489 µs | 4 vs 10,415 |

## 限制

- 不支持字节数组:NestedText 没有二进制类型。
- 字典键必须序列化为字符串;用列表或字典作键会报错。

## 许可

Apache-2.0。