1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Reader and writer for the 1C:Enterprise bracket format: `{1,"text",{nested,list}}`.
//!
//! Input is anything implementing [`std::io::Read`]; the result is a [`Node`] tree.
//! The API is built on the standard conversion traits:
//!
//! ```
//! use one_brackets::Node;
//!
//! # fn main() -> one_brackets::Result<()> {
//! let node: Node = "\u{feff}{2,c2f34349-b1e0-4060-8abf-3c59f38ac69f,\"ок\"}".parse()?;
//! assert_eq!(node.try_get(0)?.try_i64()?, 2);
//! assert!(node[1].as_guid().is_some());
//! assert_eq!(node[2].as_quoted(), Some("ок"));
//!
//! // Writing uses the platform layout.
//! let text: String = (&node).into();
//! assert_eq!(text, "{2,c2f34349-b1e0-4060-8abf-3c59f38ac69f,\"ок\"}");
//!
//! // Any `Read` source: file, socket, decompressed stream.
//! let node = Node::from_reader(std::io::Cursor::new(b"{1,{}}"))?;
//! assert_eq!(node, Node::list([Node::from(1), Node::list([])]));
//!
//! // Edit in place and write back: untouched parts keep their text.
//! let mut node: Node = "{1,\"old\",{2}}".parse()?;
//! *node.try_get_path_mut(&[2, 0])? = Node::from(3);
//! node[1] = Node::string("new");
//! assert_eq!(node.to_string(), "{1,\"new\",\r\n{3}\r\n}");
//!
//! // Errors carry a position.
//! let err = Node::try_from("{1,\n{2").unwrap_err();
//! assert_eq!(
//! err.to_string(),
//! "unexpected end of input at line 2, column 3: list opened at line 2, column 1 is not closed",
//! );
//! # Ok(())
//! # }
//! ```
//!
//! Map your own types with `impl TryFrom<&Node>` using the `try_*` accessors.
//! They return an [`AccessError`] that names the expected type and points at the node:
//!
//! ```
//! use one_brackets::{AccessError, Node};
//!
//! #[derive(Debug)]
//! struct FormatVersion { major: u32, build: u64 }
//!
//! impl TryFrom<&Node> for FormatVersion {
//! type Error = AccessError;
//!
//! fn try_from(node: &Node) -> Result<Self, AccessError> {
//! Ok(FormatVersion {
//! major: node.try_get_path(&[0, 0])?.try_parse()?,
//! build: node.try_get_path(&[0, 2, 0])?.try_parse()?,
//! })
//! }
//! }
//!
//! let node: Node = "{\r\n{216,0,\r\n{x,0}\r\n}\r\n}".parse().unwrap();
//! let err = FormatVersion::try_from(&node).unwrap_err();
//! assert_eq!(
//! err.to_string(),
//! "expected u64, found value `x` at line 3, column 2: invalid digit found in string",
//! );
//! ```
//!
//! Parsing problems are reported as [`ParseError`], structure problems as [`AccessError`];
//! [`Error`] wraps both, so `?` works for either in one function.
//!
//! With the `serde` feature user types map to lists by field order:
//! see `from_node`, `to_node`, `Rest`, `Counted` and `atom`.
//!
//! # Performance
//!
//! Every string and value is a separate `String` and every list a `Vec`, so most of
//! the parsing time of large files (event logs, big forms) goes to the memory allocator.
//! The library does not pick an allocator; the application can switch to
//! [mimalloc](https://crates.io/crates/mimalloc), which works on Windows, Linux and macOS.
//! In the crate's measurements it made parsing 1.5–2.7 times faster on Windows,
//! whose system allocator is the slowest, and 1.2–1.5 times faster on Linux (glibc):
//!
//! ```toml
//! [dependencies]
//! mimalloc = "0.1"
//! ```
//!
//! ```ignore
//! #[global_allocator]
//! static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
//! ```
//!
//! For large inputs prefer [`Values`] over parsing one huge list: it keeps only
//! the current record in memory. `cargo bench` measures reading and writing speed.
/// Runs the README examples as doctests; some of them need the `serde` feature.
;
/// The Russian README carries the same examples.
;
pub use ;
pub use SerializeError;
pub use ;
pub use ;
pub use Values;
pub use ;
pub use ;