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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
//! Syntax documentation and common types to describe syntax.
//!
//! ## Basic Types
//!
//! *smallish* syntax is designed to be simple for humans to write,
//! and to get out of the way of its main purpose: writing lists of
//! simple instructions.
//!
//! This informs the most common syntax:
//!
//! * **Lists** are values enclosed in square brackets `[]`, separated
//! by either a comma or newlines.
//!
//! `[0, 1, 2]`
//!
//! When using list-flavored *smallish*, the brackets around the
//! root list are omitted.
//!
//! * **Enumerations** are the variant name followed by arguments,
//! separated by spaces. Tuple variants use the values directly, while
//! struct variants use key-value pairs.
//!
//! `VariantName key=42`
//!
//! * **Comments** begin with `#` and continue until the end of the line.
//!
//! `# this is a comment`
//!
//! For example:
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! enum Instr {
//! UnitVariant,
//! TupleVariant(u8, u8, u8),
//! StructVariant { foo: u8, bar: Vec<u8> },
//! }
//!
//! let r: Vec<Instr> = from_str(Flavor::List, r#"
//! UnitVariant # comments!
//! TupleVariant 0 1 2
//! StructVariant foo=42 bar=[10, 20]
//! "#).unwrap();
//!
//! assert_eq!(r, vec![
//! Instr::UnitVariant,
//! Instr::TupleVariant(0, 1, 2),
//! Instr::StructVariant { foo: 42, bar: vec![10, 20] },
//! ]);
//! ```
//!
//! These are the most important types to get started, but *smallish*
//! supports other types as well:
//!
//! * **Maps and Structs** are enclosed in curly brackets `{}`
//! containing key-value pairs, separated by either a comma or
//! newlines.
//!
//! `{foo = 5, bar = 10}`
//!
//! When using map-flavored *smallish*, the brackets around the
//! root map are omitted.
//!
//! * **Unit Structs** are written as `()`.
//!
//! * **None** is written `none`. This is used to represent [Option::None].
//!
//! * **Booleans** are written as `true` and `false`.
//!
//! * **Integers** are written as strings of digits in decimal, or
//! prefixed by `0x` for hexadecimal, `0o` for octal, and `0b` for
//! binary. They may start with `+` or `-`.
//!
//! `-42`
//!
//! * **Floats** are written as strings of digits in decimal, with a
//! decimal point `.` and optionally either a `+` or `-` in front and
//! an exponent `e` at the end.
//!
//! `6.28e-2`
//!
//! * **Characters** are written enclosed in single-quotes `'`, and
//! support the same escapes as Rust.
//!
//! `'A'`
//!
//! `'\u{2603}'`
//!
//! * **Strings and Bytes** are written enclosed in double-quotes `"`,
//! and bytes are prefixed with `b`. These also support the same
//! escapes as Rust.
//!
//! `"Hello,\nworld!"`
//!
//! `b"\x00\x01"`
//!
//! ## Flavors
//!
//! *smallish* comes in [**Flavors**](crate::Flavor), which change how
//! the root value is represented. Value flavored is the default,
//! while map and list flavored *smallish* simply omit the enclosing
//! braces for that root value.
//!
//! ## Reserved Names
//!
//! Some names, like `true`, `false`, and `none`, are used to
//! represent values directly. If you need to use these names for an
//! enumeration variant or a key name, escape it by prefixing it with
//! `\`.
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! #[serde(rename_all = "snake_case")]
//! enum MyBool { True, False }
//!
//! assert_eq!(MyBool::True, from_str(Flavor::Value, r#"\true"#).unwrap());
//! ```
//!
//! ## Nested Enumerations and Precedence
//!
//! You can use parenthesis `()` to enclose values. This is sometimes
//! necessary to parse a value correctly. For example, enumerations
//! passed as arguments to another enumeration sometimes need
//! parenthesis to group the arguments correctly.
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! enum Arg { Plain, WithValue(u8) }
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! enum Instr { Foo { arg: Arg } }
//!
//! let r: Vec<Instr> = from_str(Flavor::List, r#"
//! Foo arg=Plain
//! Foo arg=(WithValue 42)
//! "#).unwrap();
//!
//! assert_eq!(r, vec![
//! Instr::Foo { arg: Arg::Plain },
//! Instr::Foo { arg: Arg::WithValue(42) },
//! ]);
//! ```
//!
//! ## Using with `serde`
//!
//! There are a few details to be aware of when using *smallish* with
//! `serde`.
//!
//! ### Options
//!
//! Options are written as `none` for [None], and the value itself for
//! [Some].
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! assert_eq!(from_str::<Option<u8>>(Flavor::Value, "none").unwrap(), None);
//! assert_eq!(from_str::<Option<u8>>(Flavor::Value, "20").unwrap(), Some(20));
//! ```
//!
//! ### Newtype Structs and Variants
//!
//! Newtypes are written exactly the same as if the in-between type
//! was not there. In particular, for newtype enumeration variants,
//! this means that variants containing a sequence look like tuple
//! variants, and those containing a struct look like struct
//! variants. Newtype variants containing any other data are treated
//! like tuple variants with one argument.
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! enum E {
//! NewtypeSeq(Vec<u8>),
//! NewtypeStruct(std::ops::Range<u8>),
//! NewtypePlain(u8),
//! }
//!
//! let r: Vec<E> = from_str(Flavor::List, r#"
//! NewtypeSeq 0 1 2
//! NewtypeStruct start=10 end=20
//! NewtypePlain 42
//! "#).unwrap();
//!
//! assert_eq!(r, vec![
//! E::NewtypeSeq(vec![0, 1, 2]),
//! E::NewtypeStruct(std::ops::Range { start: 10, end: 20 }),
//! E::NewtypePlain(42),
//! ]);
//! ```
//!
//! ### Escaped Strings and Bytes
//!
//! Strings and bytes can be borrowed without copy from the document
//! itself, as long as they do not contain any escapes. Strings and
//! bytes with escapes must be first un-escaped into a scratch buffer
//! provided to the deserializer, using
//! e.g. [from_str_escaped](crate::from_str_escaped) or
//! [from_slice_escaped](crate::from_slice_escaped). If this buffer
//! becomes full, the deserialization will fail.
//!
//! You can either increase the size of this buffer, or opt-out of
//! un-escaping by wrapping your string (or bytes) type in
//! [Escaped]. Strings wrapped this way can always be deserialized
//! without a copy, but may contain unhandled escape sequences that
//! you must handle yourself.
//!
//! ```
//! # use smallish::{Flavor, from_str, types::Escaped};
//! let r: Escaped<&str> = from_str(Flavor::Value, r#""hello\n""#).unwrap();
//! assert_eq!(*r, r#"hello\n"#)
//! ```
//!
//! ### Enum Representations and Untagged Variants
//!
//! *smallish* is designed to work with the default, externally-tagged
//! enum representation. However, it is possible to use the other
//! representations by using the bare variant name as the tag.
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! #[serde(tag = "type")]
//! enum E {
//! VariantName { a: u8 },
//! }
//!
//! let r: E = from_str(Flavor::Value, "{type=VariantName, a=42}").unwrap();
//! assert_eq!(r, E::VariantName { a: 42 });
//! ```
//!
//! However, due to ambiguity in the grammar, **alternately-tagged
//! enums, or enums with untagged variants, need special care**. If
//! such enums directly contain other enums, the contained enums will
//! be parsed slightly differently. Specifically,
//!
//! * `Variant` is always parsed as a unit variant.
//!
//! * `Variant k=v [...]` is always parsed as a struct variant, or a
//! newtype variant containing a map or struct.
//!
//! * `Variant v [...]` is always parsed as a tuple variant, or a
//! newtype variant containing a sequence.
//!
//! This means non-container newtype variants, or newtype variants
//! containing an empty container, cannot be parsed with the usual
//! syntax when inside an externally-tagged or untagged enum. This
//! restriction is only for the first level of parsing inside a
//! non-standard enum; deeper levels are not affected.
//!
//! Adjacently-tagged enums do not suffer from this restriction if the
//! tag precedes the content, but you should not rely on this
//! behavior.
//!
//! As a workaround, you can instead represent the contained enums
//! using map syntax.
//!
//! ```
//! # use smallish::{Flavor, from_str};
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! enum SubEnum {
//! Sub(u8),
//! }
//!
//! #[derive(Debug, PartialEq, Eq, serde::Deserialize)]
//! #[serde(tag = "type")]
//! enum E {
//! Tricky { a: SubEnum },
//! }
//!
//! // this fails
//! from_str::<E>(Flavor::Value, "{type=Tricky, a=(Sub 42)}").unwrap_err();
//!
//! // this works
//! let r: E = from_str(Flavor::Value, "{type=Tricky, a={Sub=42}}").unwrap();
//! assert_eq!(r, E::Tricky { a: SubEnum::Sub(42) });
//! ```
use crateEscaped;
/// The internal integer type. Integers outside this range will fail to parse.
pub type Int = i64;
/// The internal float type. Floats outside this range will fail to parse.
pub type Float = f32;
define_enum_with_kind!
// to support error messages
/// Simple (non-compound) values.
/// Parser events.