Skip to main content

cbor_edn/
lib.rs

1//! # Processing CBOR Diagnostic Notation (EDN)
2//!
3//! This crate provides tools to interconvert CBOR data between its binary and its diagnostic form,
4//! and can manipulate the diagnostic representation.
5//!
6//! ## What this works with
7//!
8//! [CBOR] is a self-describing data format that is compact and efficient to use; think JSON but
9//! binary. As a binary format, it is not human readable, but there exists a Diagnostic Notation
10//! for it called [EDN] (which is currently [being revised]). CBOR can express all information of
11//! JSON and more, and the diagnostic notation extends JSON. As examples, the compact binary data
12//! (represented in hex in the first line) is equivalent to the diagnostic notation in the 2nd
13//! line:
14//!
15//! ```text
16//! 83 01 02 62 68 69
17//! [1, 2, "hi"]
18//! ```
19//!
20//! [CBOR]: https://cbor.io/
21//! [EDN]: https://datatracker.ietf.org/doc/html/rfc8610#appendix-G
22//! [being revised]: https://www.ietf.org/archive/id/draft-ietf-cbor-edn-literals-15.html
23//!
24//! ## API Overview
25//!
26//! The main entry points to this crate are:
27//!
28//! * [`StandaloneItem`] can parse both CBOR and diagnostic notation.
29//! * [`Sequence`] can parse multiple concatenated CBOR items (called [CBOR sequences]).
30//!
31//! In all cases, the library preserves loaded data through serialization back into the original
32//! format:
33//!
34//! 1. Choices that are exclusive to EDN are preserved when saving as EDN.
35//!
36//!    This includes whether a byte string is shown as ASCII or hexadecimal, comments, optional
37//!    commas, and even spaces.
38//!
39//! 2. Choices that mainly exist in CBOR.
40//!
41//!    This includes whether a list is encoded in definite length or indefinite length, and in how
42//!    many bytes short numbers are encoded.
43//!
44//! Converting between the format is, of course, preserving the CBOR information content, but
45//! generally loses aspects such as comments or trailing zeros in decimal numbers.
46//!
47//! Beyond converting CBOR to EDN and vice versa, this crate can also be used to manipulate CBOR,
48//! e. g. to provide explanatory comments around items or to use more specialized representations.
49//! Handling those usually involves a single [`Item`], which is distinct from a [`StandaloneItem`]
50//! in that any space or comments around it are part of the surrounding structure (which means that
51//! it is not sensible to parse EDN into a single [`Item`] because even an innocent line break at
52//! the end of the EDN would throw the parser off).
53//!
54//! [CBOR sequences]: https://www.rfc-editor.org/rfc/rfc8742.html
55//!
56//! ### Example usage
57//!
58//! This example shows how to convert EDN into CBOR and back to EDN.
59//!
60//! ```
61//! # use cbor_edn::StandaloneItem;
62//! // Ingest CBOR Diagnostic Notation.
63//! let input: &str  = &r#"[1, 2, "x"]"#;
64//! let parsed = StandaloneItem::parse(input).unwrap();
65//! // Emit it as CBOR.
66//! let cbor = parsed.to_cbor().unwrap();
67//!
68//! // Parse the CBOR
69//! let parsed = StandaloneItem::from_cbor(&cbor).unwrap();
70//! let edn = parsed.serialize();
71//! assert_eq!(edn.as_str(), input);
72//! ```
73//!
74//! The library can perform various [transformations][Transformation], most of which affect the EDN
75//! representation to explore the trade-offs between readabiliy and staying close to what is sent
76//! on the wire:
77//!
78//! ```
79//! # use cbor_edn::{StandaloneItem, Transformation};
80//! let input = &[0x84, 0xd8, 0x36, 0x50, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81//!     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x01, 0x02, 0x03, 0x58, 0x27, 0x68, 0x65,
82//!     0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
83//!     0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
84//!     0x65, 0x65, 0x65, 0x65, 0x6c, 0x6c, 0x6f, 0x58, 0x27, 0x77, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
85//!     0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
86//!     0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
87//!     0x72, 0x6c, 0x64];
88//! let mut diagnostic = StandaloneItem::from_cbor(input).unwrap();
89//!
90//! Transformation::new().pretty().apply_to(&mut diagnostic);
91//!
92//! assert_eq!(diagnostic.serialize().as_str(), r#"[
93//!     IP'fe80::1',
94//!     [1, 2, 3],
95//!     'heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeello',
96//!     'wooooooooooooooooooooooooooooooooooorld'
97//! ]
98//! "#);
99//! ```
100//!
101//! Note that the precise output may change as the heuristics around how to best represent what
102//! may change.
103//!
104//! More fine-grained transformations can be done using methods on the [`StandaloneItem`] and
105//! [`Sequence`], including through the [`Transformable`] trait.
106//!
107//! ## Implementation remarks
108//!
109//! The parser used by this crate is a PEG (Parsing Expression Grammer) parser built from the ABNF
110//! used in the [EDN specification].
111//!
112//! The types' data model is oriented more towards EDN than towards CBOR, as that has richer
113//! information and is generally needed for tasks such as annotation or delayed processing of
114//! application oriented literals.
115//!
116//! Parsed values are expected to round-trip to identical representations when serialized. Most
117//! manipulations of the values will ensure that their serialization output can also be
118//! round-tripped from the internal format to the EDN serialization and back into the internal
119//! format, but this can not be provided by all. (For example, removing all optional commas
120//! while retaining comments would make the previous distinction between whether a comment was
121//! before or after a comma indistinguishable).
122//!
123//! Correct parsing does not guarantee that the value can also be encoded into CBOR. While there
124//! are aspects that could be handled at parsing time and are not (eg. tag numbers exceeding the
125//! encodable number space), there are cases that can not be handled by a library without further
126//! context or privileges (eg. the e'' application oriented literal that needs application context,
127//! or the ref'' application oriented literal that defers to relative files, accessing which can
128//! involve file or network access). Consequentially, conversion to CBOR through the various
129//! `.to_cbor()` methods is inherently fallible, while `.serialize()`ing into EDN is not.
130//!
131//! [EDN specification]: https://www.ietf.org/archive/id/draft-ietf-cbor-edn-literals-15.html
132//!
133//! ## Completeness
134//!
135//! Known limitations are:
136//!
137//! * Support for inspecting and constructing CBOR items is incomplete. The most common types can
138//!   be constructed; contructing or inspecting more exotic items is possible through parsing
139//!   hand-crafted EDN/CBOR and using the generated serializations, respectively.
140//!
141//! * Options for attaching comments and space are limited and immature:
142//!
143//!   * [`Item::with_comment()`] & [`StandaloneItem::set_comment`] can be used to add comments, but
144//!     mainly produce [top-level items][StandaloneItem]. Deeper items are not configurable that
145//!     way, as the comments don't live in the item but its container.
146//!
147//!   * Comments can be added to items through visitors such as [`Item::visit_map_elements`]; both
148//!     the success and the error path of a visiting function can set comments around a tag.
149//!
150//!   * Replacing an item with hand-crafted EDN (possibly from serialized item) is always an
151//!     option.
152//!
153//! * Indenting EDN works for the easy cases, but more exotic cases such as overflowing the limited
154//!   width, long keys, or hash comments, easily disrupt the visual result.
155//!
156//! ## Security
157//!
158//! This library does not access network or file system in any surprising ways and does not
159//! endanger memory safety on its own. The main threat in using it is not resource bound: even
160//! without packed CBOR, heavy nesting can easily overflow the stack, and the float conversions are
161//! costly in time. Unless resource usage per user is limited, it is recommended to limit untrusted
162//! user input to the length of repeated `{` characters that do not yet overflow the stack.
163//!
164//! The crate has not been audited internally or externally. As the
165//! [licenses](https://spdx.org/licenses/MIT.html)
166//! [state](https://spdx.org/licenses/Apache-2.0.html), the software is provided "as is".
167//!
168//! ## CLI application
169//!
170//! Some functionality is available through a binary included with this crate:
171//!
172//! <!-- See https://github.com/assert-rs/snapbox/issues/172 -->
173//! ```console
174//! $ echo "[1, 2, 'x', ip'2001:db1::/64']" | cbor-edn diag2diag
175//! [1, 2, 'x', ip'2001:db1::/64']
176//! ```
177#![forbid(unsafe_code)]
178
179use std::borrow::Cow;
180
181mod visitor;
182use visitor::{
183    ApplicationLiteralsVisitor, ArrayElementVisitor, ProcessResult, TagVisitor, Visitor,
184};
185
186pub mod application;
187pub mod error;
188mod float;
189mod space;
190mod transform;
191mod transformable;
192use space::{Comment, SDetails, MS, MSC, S, SOC};
193pub use transform::Transformation;
194pub use transformable::Transformable;
195mod number;
196use number::{Number, NumberParts, NumberValue, Sign};
197mod string;
198use string::{CborString, PreprocessedStringComponent, String1e};
199
200#[cfg(test)]
201mod tests;
202
203use error::*;
204
205const U8MAX: u64 = u8::MAX as _;
206const U16MAX: u64 = u16::MAX as _;
207const U32MAX: u64 = u32::MAX as _;
208
209/// A CBOR Item, including any space and comments surrounding it in a serialization.
210///
211/// This is typically parsed either from EDN or from CBOR:
212///
213/// ```
214/// # use cbor_edn::*;
215/// let from_edn = StandaloneItem::parse("{1: {2: {3: null}}}").unwrap();
216/// let mut from_cbor = StandaloneItem::from_cbor(
217///     &[0xa1, 0x01, 0xa1, 0x02, 0xa1, 0x03, 0xf6]
218/// ).unwrap();
219/// ```
220///
221/// … and then manipulated:
222///
223/// ```
224/// # use cbor_edn::*;
225/// # let mut from_cbor = StandaloneItem::from_cbor(
226/// #     &[0xa1, 0x01, 0xa1, 0x02, 0xa1, 0x03, 0xf6]
227/// # ).unwrap();
228/// // No spaces when we don't need them.
229/// from_cbor.set_delimiters(DelimiterPolicy::DiscardAll);
230/// ```
231///
232/// … and then serialized:
233///
234/// ```
235/// # use cbor_edn::*;
236/// # let from_edn = StandaloneItem::parse("{1: {2: {3: null}}}").unwrap();
237/// # let mut from_cbor = StandaloneItem::from_cbor(
238/// #     &[0xa1, 0x01, 0xa1, 0x02, 0xa1, 0x03, 0xf6]
239/// # ).unwrap();
240/// # from_cbor.set_delimiters(DelimiterPolicy::DiscardAll);
241/// assert_eq!(from_cbor.serialize(), "{1:{2:{3:null}}}");
242/// assert_eq!(from_cbor.to_cbor().unwrap(), from_edn.to_cbor().unwrap());
243/// ```
244#[derive(Debug, Clone, PartialEq)]
245pub struct StandaloneItem<'a>(S<'a>, Item<'a>, S<'a>);
246
247/// A CBOR Item.
248///
249/// This represents an inner item as is contained in a CBOR array, map, tag, but also in a
250/// [`Sequence`], or a [`StandaloneItem`] (to which it is identical in CBOR, but the standalone
251/// item also describes any comments or space before or after the top-level item).
252///
253/// It is mainly found in deeper interaction with CBOR items, for example:
254///
255/// ```
256/// # use cbor_edn::*;
257/// let my_map = StandaloneItem::parse(r#"{1: "one", 2: "two"}"#).unwrap();
258/// let my_toplevel: &Item = my_map.item();
259/// for (key, value) in my_toplevel.get_map_items().unwrap() {
260///     let key: &Item = key;
261///     println!("Mapping {} to {}", key.serialize(), value.serialize());
262/// }
263/// ```
264///
265/// By virtue of EDN's expressiveness, this type is capable not
266/// only of expressing any well-formed CBOR, but also to preserve encoding details that are not
267/// preferred (eg. a small integer encoded in more bytes than necessary). Some transformations on
268/// the EDN may lose such details; components that perform a translation such as recoding `(_
269/// h'18', h'6402')` into `<<100, 2>>` have a choice to either not perform the translation or to
270/// discard some encoding details.
271#[derive(Debug, Clone, PartialEq)]
272pub struct Item<'a>(InnerItem<'a>);
273
274/// # Conversion between the in-memory format and serializations
275impl<'a> StandaloneItem<'a> {
276    /// Ingests CBOR Diagnostic Notation (EDN) representing a single CBOR item
277    ///
278    /// Note that this will only return syntactic errors. Content errors that make it impossible to
279    /// produce this as CBOR, such as non-matching encoding indicators or unknown application
280    /// oriented literals, are not reported.
281    pub fn parse(s: &'a str) -> Result<Self, ParseError> {
282        cbordiagnostic::one_item(s).map_err(ParseError)
283    }
284
285    /// Produce an EDN String from the item
286    pub fn serialize(&self) -> String {
287        Unparse::serialize(self)
288    }
289
290    /// Parse a complete CBOR item.
291    ///
292    /// Providing excessive data results in an error.
293    pub fn from_cbor(cbor: &[u8]) -> Result<Self, CborError> {
294        Ok(Self(S::default(), Item::from_cbor(cbor)?, S::default()))
295    }
296
297    /// Parse a complete CBOR item.
298    ///
299    /// Any remaining byts are returned as part of the result.
300    pub fn from_cbor_with_rest(cbor: &[u8]) -> Result<(Self, &[u8]), CborError> {
301        let (item, rest) = Item::from_cbor_with_rest(cbor)?;
302        Ok((Self(S::default(), item, S::default()), rest))
303    }
304
305    /// Parses a CBOR item, allowing incomplete items.
306    ///
307    /// If at the end of the data there is an incomplete CBOR item, rather than producing an error,
308    /// this produces ellipses wherever there is incomplete data.
309    ///
310    /// ```
311    /// # use cbor_edn::StandaloneItem;
312    /// let from_cbor = StandaloneItem::from_cbor_possibly_incomplete(
313    ///     &[0x82, 0x65, 0x61, 0x62, 0x63]
314    /// ).unwrap();
315    /// assert_eq!(from_cbor.serialize(), r#"["abc" + ..., ...]"#);
316    /// ```
317    pub fn from_cbor_possibly_incomplete(cbor: &[u8]) -> Result<Self, CborError> {
318        let (item, rest) = Item::from_cbor_with_rest_possibly_erroneous(cbor)?;
319        match rest {
320            Err(e) => {
321                if !e.is_out_of_data() {
322                    return Err(e);
323                }
324            }
325            Ok(rest) => {
326                if !rest.is_empty() {
327                    return Err(CborError::invalid("Data after item"));
328                };
329            }
330        }
331        Ok(Self(S::default(), item, S::default()))
332    }
333
334    /// Encode into a binary CBOR representation
335    pub fn to_cbor(&self) -> Result<Vec<u8>, InconsistentEdn> {
336        Ok(Unparse::to_cbor(self)?.collect())
337    }
338}
339
340/// # Helpers for conversion between standalone and bare items
341impl<'a> StandaloneItem<'a> {
342    /// Discards the comments and space around the single item, returning only the item itself.
343    pub fn into_item(self) -> Item<'a> {
344        self.1
345    }
346
347    /// Accesses the single item.
348    pub fn item(&self) -> &Item<'a> {
349        &self.1
350    }
351
352    /// Mutably accesses the single item.
353    pub fn item_mut(&mut self) -> &mut Item<'a> {
354        &mut self.1
355    }
356
357    fn inner(&self) -> &InnerItem<'a> {
358        self.1.inner()
359    }
360
361    /// Clone the item, turning any [`Cow::Borrowed`] into owned versions, which can then satisfy
362    /// any lifetime.
363    pub fn cloned<'any>(&self) -> StandaloneItem<'any> {
364        StandaloneItem(self.0.cloned(), self.1.cloned(), self.2.cloned())
365    }
366}
367
368/// # Conversion between the in-memory format and serializations
369///
370/// Note that unlike [`StandaloneItem`], this does not provide EDN parsing: Any standalone EDN CBOR
371/// item may contain outer blank space or comments, which can only be represented in a
372/// [`StandaloneItem`].
373impl<'a> Item<'a> {
374    /// Produce an EDN String from the item
375    pub fn serialize(&self) -> String {
376        Unparse::serialize(self)
377    }
378
379    /// Parse a complete CBOR item.
380    ///
381    /// Providing excessive data results in an error.
382    pub fn from_cbor(cbor: &[u8]) -> Result<Self, CborError> {
383        match Self::from_cbor_with_rest(cbor) {
384            Ok((s, &[])) => Ok(s),
385            Ok(_) => Err(CborError::invalid("Data after item")),
386            Err(e) => Err(e),
387        }
388    }
389
390    /// Parse a complete CBOR item.
391    ///
392    /// Any remaining byts are returned as part of the result.
393    pub fn from_cbor_with_rest(cbor: &[u8]) -> Result<(Self, &[u8]), CborError> {
394        match Self::from_cbor_with_rest_possibly_erroneous(cbor) {
395            Err(e) => Err(e),
396            Ok((_, Err(e))) => Err(e),
397            Ok((s, Ok(rest))) => Ok((s, rest)),
398        }
399    }
400
401    /// Parse a CBOR item, allowing interior errors.
402    ///
403    /// If something could be decoded, it is returned as successful; any interior error is
404    /// indicated:
405    ///
406    /// a) in the item itself (as an ellipsis, possibly with a comment), and
407    /// b) in the place of the "rest" value, for then it is impossible to continue parsing.
408    fn from_cbor_with_rest_possibly_erroneous(
409        cbor: &[u8],
410    ) -> Result<(Self, Result<&[u8], CborError>), CborError> {
411        let (major, argument, spec, tail) = process_cbor_major_argument(cbor)?;
412
413        let mut return_tail = Ok(tail);
414
415        let mut s = match (major, argument, spec) {
416            (Major::Unsigned, Some(argument), spec) => Self::new_integer_decimal_with_spec(
417                argument,
418                spec.or_none_if_default_for_arg(argument),
419            ),
420            (Major::Negative, Some(argument), spec) => Self::new_integer_decimal_with_spec(
421                -1i128 - i128::from(argument),
422                spec.or_none_if_default_for_arg(argument),
423            ),
424            (Major::FloatSimple, Some(n @ 0..=19), Spec::S_i) => {
425                Simple::Numeric(Box::new(Self::new_integer_decimal(n).into())).into()
426            }
427            (Major::FloatSimple, Some(20), Spec::S_i) => Simple::False.into(),
428            (Major::FloatSimple, Some(21), Spec::S_i) => Simple::True.into(),
429            (Major::FloatSimple, Some(22), Spec::S_i) => Simple::Null.into(),
430            (Major::FloatSimple, Some(23), Spec::S_i) => Simple::Undefined.into(),
431            (Major::FloatSimple, Some(n @ 32..=255), Spec::S_0) => {
432                Simple::Numeric(Box::new(Self::new_integer_decimal(n).into())).into()
433            }
434            // 0..=31 in S_0 or 24..=31 in S_i
435            (Major::FloatSimple, _, Spec::S_i | Spec::S_0) => {
436                return Err(CborError::invalid(
437                    "erroneous representation of simple value",
438                ))
439            }
440            (Major::FloatSimple, Some(0x7c00), Spec::S_1) => {
441                Number(Cow::from("Infinity")).with_spec(Some(Spec::S_1))
442            }
443            (Major::FloatSimple, Some(0xfc00), Spec::S_1) => {
444                Number(Cow::from("-Infinity")).with_spec(Some(Spec::S_1))
445            }
446            (Major::FloatSimple, Some(0x7e00), Spec::S_1) => {
447                Number(Cow::from("NaN")).with_spec(Some(Spec::S_1))
448            }
449            (Major::FloatSimple, Some(n), Spec::S_1) => {
450                let f =
451                    float::f16_bits_to_f64(n.try_into().expect("Range limited by construction"));
452                Number::new_float(f).with_spec(Some(Spec::S_1))
453            }
454            (Major::FloatSimple, Some(n), Spec::S_2) => {
455                let n: u32 = n.try_into().expect("Range limited by construction");
456                let f = f64::from(f32::from_bits(n));
457                Number::new_float(f).with_spec(Some(Spec::S_2))
458            }
459            (Major::FloatSimple, Some(n), Spec::S_3) => {
460                let f = f64::from_bits(n);
461                Number::new_float(f).with_spec(Some(Spec::S_3))
462            }
463            (Major::FloatSimple, None, _ /* S_ not written for exhaustiveness */)
464            | (Major::FloatSimple, _ /* None not written for exhaustiveness */, Spec::S_) => {
465                return Err(CborError::invalid(
466                    "Break code only expected at end of indefinte length items",
467                ))
468            }
469            (Major::Tagged, Some(n), s) => {
470                // FIXME this is recursing on the stack rather than on the heap
471                let (item, new_tail) = StandaloneItem::from_cbor_with_rest(tail)?;
472                return_tail = Ok(new_tail);
473                item.tagged_with_spec(n, s.or_none_if_default_for_arg(n))
474            }
475            (Major::Unsigned | Major::Negative | Major::Tagged, None, _) => {
476                return Err(CborError::invalid(
477                    "Integer/Tag with indefinite length encoding is not well-formed",
478                ))
479            }
480            (Major::ByteString, Some(n), spec) => {
481                let data = n.try_into().ok().and_then(|n| tail.get(..n));
482                match data {
483                    Some(d) => {
484                        return_tail = Ok(&tail[d.len()..]);
485                        Self::new_bytes_hex_with_spec(d, spec.or_none_if_default_for_arg(n))
486                    }
487                    None => {
488                        let error = CborError::out_of_data("Announced bytes unavailable");
489                        let ellipsis = Item::error_ellipsis(&error);
490                        return_tail = Err(error);
491                        let mut item =
492                            Self::new_bytes_hex_with_spec(tail, spec.or_none_if_default_for_arg(n));
493                        item.push_string_concatenation(ellipsis);
494                        item
495                    }
496                }
497            }
498            (Major::TextString, Some(n), spec) => {
499                let data = n.try_into().ok().and_then(|n| tail.get(..n));
500                match data {
501                    Some(d) => {
502                        let data = core::str::from_utf8(d)
503                            .map_err(|_| CborError::invalid("Text string must be valid UTF-8"))?;
504                        return_tail = Ok(&tail[data.len()..]);
505                        Self::new_text_with_spec(data, spec.or_none_if_default_for_arg(n))
506                    }
507                    None => {
508                        let error =
509                            CborError::out_of_data("Announced bytes unavailable in text string");
510                        let ellipsis = Item::error_ellipsis(&error);
511                        return_tail = Err(error);
512
513                        let tail_str = match core::str::from_utf8(tail) {
514                            Ok(d) => d,
515                            Err(e) => core::str::from_utf8(&tail[..e.valid_up_to()]).unwrap(),
516                        };
517                        let mut item =
518                            Self::new_text_with_spec(tail_str, spec.or_none_if_default_for_arg(n));
519                        item.push_string_concatenation(ellipsis);
520                        item
521                    }
522                }
523            }
524            // Indefinite length items won't try to emit ellipses, anticipating that those need
525            // changes with the next draft update anyway.
526            (
527                Major::ByteString | Major::TextString,
528                None,
529                _, /* S_ not written for exhaustiveness */
530            ) => {
531                let mut items = vec![];
532                while return_tail.as_ref().is_ok_and(|t| t.first() != Some(&0xff)) {
533                    let (inner_major, argument, spec, new_tail) =
534                        process_cbor_major_argument(return_tail.unwrap())?;
535                    let Some(argument) = argument.and_then(|a| usize::try_from(a).ok()) else {
536                        // This could be CborError::out_of_data, but with the length announced
537                        // exceeding a usize, this is highly unrealistic.
538                        return Err(CborError::invalid(
539                            "Indefinite length strings can only contain definite lengths and must fit in data",
540                        ));
541                    };
542                    if inner_major != major {
543                        return Err(CborError::invalid(
544                            "Indefinite length strings can only contain matching items",
545                        ));
546                    }
547                    if new_tail.len() < argument {
548                        return Err(CborError::out_of_data(
549                            "Announced bytes unavailable inside indefinite length byte string",
550                        ));
551                    }
552                    // with split_at_checked, we could combine the checkinto the split
553                    let (item_data, new_tail) = new_tail.split_at(argument);
554                    return_tail = Ok(new_tail);
555                    items.push(match major {
556                        Major::ByteString => {
557                            CborString::new_bytes_hex_with_spec(item_data, Some(spec))
558                        }
559                        Major::TextString => CborString::new_text_with_spec(
560                            core::str::from_utf8(item_data).map_err(|_| {
561                                CborError::invalid("Text string must be valid UTF-8")
562                            })?,
563                            Some(spec),
564                        ),
565                        _ => unreachable!(),
566                    });
567                }
568                if return_tail.as_ref().unwrap().is_empty() {
569                    return Err(CborError::out_of_data(
570                        "Indefinite length byte string terminated after item",
571                    ));
572                }
573                return_tail = Ok(&return_tail.as_ref().unwrap()[1..]);
574
575                let mut items = items.drain(..);
576                if let Some(first_item) = items.next() {
577                    InnerItem::StreamString(
578                        Default::default(),
579                        NonemptyMscVec::new(first_item, items),
580                    )
581                    .into()
582                } else {
583                    todo!()
584                }
585            }
586            (Major::Array, mut length, spec) => {
587                // FIXME this is recursing on the stack rather than on the heap
588                let mut items = vec![];
589                let spec = match length {
590                    Some(l) => spec.or_none_if_default_for_arg(l),
591                    None => Some(spec), // which is always indefinite length
592                };
593                while length != Some(0)
594                    && return_tail.as_ref().is_ok_and(|t| t.first() != Some(&0xff))
595                {
596                    match Self::from_cbor_with_rest_possibly_erroneous(return_tail.unwrap()) {
597                        Ok((item, Ok(new_tail))) => {
598                            items.push(item);
599                            return_tail = Ok(new_tail);
600                        }
601                        Ok((item, Err(e))) => {
602                            items.push(item);
603                            return_tail = Err(e);
604                        }
605                        Err(e) => {
606                            return_tail = Err(e);
607                            // Break before decreasing N: We don't emit the fully
608                            // unparsable item because it will be subsumed in the ellipsis that
609                            // represents the rest of the items, but that requires that that
610                            // ellipsis is really emitted, and it wouldn't be if there are no items
611                            // left.
612                            break;
613                        }
614                    };
615                    if let Some(ref mut n) = &mut length {
616                        *n -= 1;
617                    }
618                }
619                if length.is_none() {
620                    if let Ok(t) = return_tail.as_ref() {
621                        if t.is_empty() {
622                            return_tail = Err(CborError::out_of_data(
623                                "Indefinite length array terminated after item",
624                            ));
625                        } else {
626                            return_tail = Ok(&t[1..]);
627                        }
628                    }
629                }
630                if let Err(e) = &return_tail {
631                    if length != Some(0) {
632                        items.push(Item::error_ellipsis(e));
633                    }
634                }
635                InnerItem::Array(SpecMscVec::new(spec, items.into_iter())).into()
636            }
637            (Major::Map, mut length, spec) => {
638                // FIXME this is recursing on the stack rather than on the heap
639                let mut items = vec![];
640                let spec = match length {
641                    Some(l) => spec.or_none_if_default_for_arg(l),
642                    None => Some(spec), // which is always indefinite length
643                };
644                while length != Some(0)
645                    && return_tail.as_ref().is_ok_and(|t| t.first() != Some(&0xff))
646                {
647                    let (key, new_tail) =
648                        match Self::from_cbor_with_rest_possibly_erroneous(return_tail.unwrap()) {
649                            Ok(knt) => knt,
650                            Err(e) => {
651                                // Error already parsing the key; no point displaying two ellipses, so
652                                // not emitting it.
653                                return_tail = Err(e);
654                                break;
655                            }
656                        };
657                    let (value, new_tail) = match new_tail {
658                        Ok(t) => match Self::from_cbor_with_rest_possibly_erroneous(t) {
659                            // value could be parsed, but not necessarily completely
660                            Ok(vnt) => vnt,
661                            // value could not be parsed at all
662                            Err(e) => (Item::error_ellipsis(&e), Err(e)),
663                        },
664                        // Key was troubled internally, so we don't stand a chance of parsing a
665                        // value, but at least the key was something more than an ellipsis, so we
666                        // display it independently.
667                        Err(e) => (Item::error_ellipsis(&e), Err(e)),
668                    };
669                    return_tail = new_tail;
670                    items.push(Kp::new(key, value));
671                    if let Some(ref mut n) = &mut length {
672                        *n -= 1;
673                    }
674                }
675                if length.is_none() {
676                    if let Ok(t) = return_tail.as_ref() {
677                        if t.is_empty() {
678                            return_tail = Err(CborError::out_of_data(
679                                "Indefinite length map terminated after item",
680                            ));
681                        } else {
682                            return_tail = Ok(&t[1..]);
683                        }
684                    }
685                }
686                if let Err(e) = &return_tail {
687                    if length != Some(0) {
688                        items.push(Kp::new(Item::error_ellipsis(e), Item::error_ellipsis(e)));
689                    }
690                }
691                InnerItem::Map(SpecMscVec::new(spec, items.into_iter())).into()
692            }
693        };
694
695        s.set_delimiters(DelimiterPolicy::SingleLineRegularSpacing);
696        Ok((s, return_tail))
697    }
698
699    fn visit(&mut self, visitor: &mut impl Visitor<'a>) -> ProcessResult {
700        let mut result = visitor.process(self);
701        if result.take_recurse() {
702            self.0.visit(visitor);
703        }
704        result
705    }
706
707    /// Clone the item, turning any [`Cow::Borrowed`] into owned versions, which can then satisfy
708    /// any lifetime.
709    pub fn cloned<'any>(&self) -> Item<'any> {
710        Item(self.0.cloned())
711    }
712}
713
714/// # Conversion between the in-memory format and serializations
715impl<'a> Item<'a> {
716    fn inner(&self) -> &InnerItem<'a> {
717        &self.0
718    }
719
720    fn inner_mut(&mut self) -> &mut InnerItem<'a> {
721        &mut self.0
722    }
723}
724
725/// # Creating items from data or by wrapping other items
726impl<'a> StandaloneItem<'a> {
727    fn tagged_with_spec(self, tag: u64, spec: Option<Spec>) -> Item<'a> {
728        InnerItem::Tagged(tag, spec, Box::new(self)).into()
729    }
730
731    /// Wrap the item into a CBOR tag.
732    pub fn tagged(self, tag: u64) -> Item<'a> {
733        InnerItem::Tagged(tag, None, Box::new(self)).into()
734    }
735}
736
737/// # Creating items from data or by wrapping other items
738impl<'a> Item<'a> {
739    fn new_integer_decimal_with_spec(value: impl Into<i128>, spec: Option<Spec>) -> Self {
740        Number(format!("{}", value.into()).into()).with_spec(spec)
741    }
742
743    /// Create a new item that is integer valued in CBOR and expressed in decimal in EDN.
744    ///
745    /// Note that while values exceeding i65 are accepted, they can not be encoded into CBOR.
746    pub fn new_integer_decimal(value: impl Into<i128>) -> Self {
747        Self::new_integer_decimal_with_spec(value, None)
748    }
749
750    /// Create a new item that is float valued in CBOR and expressed in decimal in EDN.
751    pub fn new_float_decimal(value: f64) -> Self {
752        Number::new_float(value).with_spec(None)
753    }
754
755    /// Create a new item that is integer valued in CBOR and expressed in hexadecimal in EDN.
756    ///
757    /// Negative values have not been implemented in this constructor.
758    pub fn new_integer_hex(value: impl Into<u64>) -> Self {
759        InnerItem::Number(Number(format!("0x{:x}", value.into()).into()), None).into()
760    }
761
762    fn new_bytes_hex_with_spec(value: &[u8], spec: Option<Spec>) -> Self {
763        InnerItem::String(CborString::new_bytes_hex_with_spec(value, spec)).into()
764    }
765
766    /// Create a new item that is a byte string in CBOR (identical to the passed in value) and
767    /// expressed as a `h'...'` string in EDN.
768    pub fn new_bytes_hex(value: &[u8]) -> Self {
769        Self::new_bytes_hex_with_spec(value, None)
770    }
771
772    fn new_text_with_spec(value: &str, spec: Option<Spec>) -> Self {
773        InnerItem::String(CborString::new_text_with_spec(value, spec)).into()
774    }
775
776    /// Create a new item that is a text string in CBOR (identical to the passed in value) and
777    /// expressed as a single double-quoted string in EDN.
778    ///
779    /// ```rust
780    /// # use cbor_edn::*;
781    /// assert_eq!(
782    ///     Item::new_text("Hello \"World\"\0").serialize(),
783    ///     r#""Hello \"World\"\u{0}""#,
784    /// );
785    /// ```
786    pub fn new_text(value: &str) -> Self {
787        Self::new_text_with_spec(value, None)
788    }
789
790    pub fn new_application_literal(identifier: &str, value: &str) -> Result<Self, InconsistentEdn> {
791        if cbordiagnostic::app_prefix(identifier).is_err() {
792            // FIXME bad error type
793            return Err(InconsistentEdn(
794                "Identifier is not a valid application string identifier",
795            ));
796        };
797        Ok(InnerItem::String(CborString::new_application_literal(identifier, value, None)).into())
798    }
799
800    /// Create a CBOR array out of the items
801    pub fn new_array(items: impl Iterator<Item = Item<'a>>) -> Self {
802        InnerItem::Array(SpecMscVec::new(None, items)).into()
803    }
804
805    /// Create a CBOR map out of the keys-value pairs
806    pub fn new_map(items: impl Iterator<Item = (Item<'a>, Item<'a>)>) -> Self {
807        InnerItem::Map(SpecMscVec::new(
808            None,
809            items.map(|(key, value)| Kp::new(key, value)),
810        ))
811        .into()
812    }
813
814    /// Wrap the item into a CBOR tag.
815    pub fn tagged(self, tag: u64) -> Item<'a> {
816        StandaloneItem::from(self).tagged(tag)
817    }
818
819    /// Creates an ellipsis from an error.
820    ///
821    /// FIXME: Ideally, all but out-of-data errors should have a comment on what went wrong.
822    /// Implementing that is postponed anticipating changes to what an item and an ellipsis is when
823    /// updating to the latest draft version.
824    fn error_ellipsis(_error: &CborError) -> Self {
825        Self(InnerItem::String(CborString {
826            items: vec![string::String1e::Ellipsis(3)],
827            separators: Vec::new(),
828        }))
829    }
830
831    /// Modifies an item by string-concatenating another onto it.
832    ///
833    /// # Panics
834    ///
835    /// if the items are not of the right types.
836    fn push_string_concatenation(&mut self, next: Item<'a>) {
837        let next = match next.0 {
838            InnerItem::String(cs) => cs,
839            _ => panic!("string-concatenating something that is not a string"),
840        };
841        let inner = match &mut self.0 {
842            InnerItem::String(cs) => cs,
843            _ => panic!("string-concatenating onto something that is not a string"),
844        };
845        inner.items.extend(next.items);
846        inner
847            .separators
848            .push((Default::default(), Default::default()));
849        inner.separators.extend(next.separators);
850    }
851}
852
853/// # Accessing and modifying an item in place
854///
855/// See also the trait methods of [`Transformable`].
856impl StandaloneItem<'_> {
857    /// Replace any comment before the item with the new comment
858    pub fn with_comment(self, comment: &str) -> Self {
859        let wrapped_comment = if comment.contains('/') {
860            format!("# {}\n", comment.replace('\n', "\n# "))
861        } else {
862            format!("/ {} /", comment)
863        };
864        Self(S(wrapped_comment.into()), self.1, self.2)
865    }
866
867    /// Replace any comment before the item with the new comment
868    pub fn set_comment(&mut self, comment: &str) {
869        let wrapped_comment = if comment.contains('/') {
870            format!("# {}\n", comment.replace('\n', "\n# "))
871        } else {
872            format!("/ {} /", comment)
873        };
874        self.0 = S(wrapped_comment.into());
875    }
876}
877
878/// # Accessing and modifying an item in place
879impl<'a> Item<'a> {
880    /// Access application-extension identifier and string value
881    ///
882    /// This only succeeds if the item is expressed using a single application oriented literal.
883    pub fn get_application_literal(&self) -> Result<(String, String), TypeMismatch> {
884        let InnerItem::String(CborString { ref items, .. }) = self.inner() else {
885            return Err(TypeMismatch::expecting("application-oriented literal"));
886        };
887        let [chunk] = items.as_slice() else {
888            return Err(TypeMismatch::expecting(
889                "single application-oriented literal",
890            ));
891        };
892        let PreprocessedStringComponent::AppString(identifier, value) = chunk
893            .preprocess()
894            // The only reason this would err is if there is embedded CBOR in there, and then
895            // that'd just mean it's not what we requested
896            .map_err(|_| TypeMismatch::expecting("application-oriented literal"))?
897        else {
898            return Err(TypeMismatch::expecting("application-oriented literal"));
899        };
900
901        Ok((identifier, value))
902    }
903
904    /// Access a byte literal value
905    ///
906    /// This only succeeds if the item is a single byte string on the CBOR level, no matter how
907    /// many EDN concatenations or even chunks. The EDN standard byte encodings (hex, base64 etc.)
908    /// are supported, other application-oriented literals need to be resolved first.
909    pub fn get_bytes(&self) -> Result<Vec<u8>, TypeMismatch> {
910        let mut result = vec![];
911
912        let mut append_items = |items: &Vec<String1e>| -> Result<(), TypeMismatch> {
913            for item in items {
914                if item
915                    .encoded_major_type()
916                    .map_err(|_| TypeMismatch::expecting("encodable item"))?
917                    != Major::ByteString
918                {
919                    return Err(TypeMismatch::expecting("byte literal"));
920                }
921                result.extend(
922                    item.bytes_value()
923                        .map_err(|_| TypeMismatch::expecting("byte literal or compatible"))?,
924                );
925            }
926            Ok(())
927        };
928
929        match self.inner() {
930            InnerItem::String(CborString { ref items, .. }) => append_items(items)?,
931            InnerItem::StreamString(_, ref chunks) => {
932                for CborString { ref items, .. } in chunks.iter() {
933                    append_items(items)?;
934                }
935            }
936            _ => return Err(TypeMismatch::expecting("byte literal")),
937        }
938
939        Ok(result)
940    }
941
942    /// Accesses a string literal value.
943    ///
944    /// This only succeeds if the item is a single text string on the CBOR level, no matter how
945    /// many EDN concatenations or even chunks. The EDN standard byte encodings (hex, base64 etc.)
946    /// are tolerated in subsequent items as required for expressing otherwise hard to read parts.
947    ///
948    /// ```
949    /// let item = cbor_edn::StandaloneItem::parse(
950    ///     r#" (_ "hello" h'20' "world" ) "#
951    /// ).unwrap();
952    /// let item = item.item();
953    /// assert_eq!("hello world", &item.get_string().unwrap());
954    /// ```
955    pub fn get_string(&self) -> Result<String, TypeMismatch> {
956        let mut result = vec![];
957
958        let mut append_items = |items: &Vec<String1e>| -> Result<(), TypeMismatch> {
959            for item in items {
960                result.extend(
961                    item.bytes_value()
962                        .map_err(|_| TypeMismatch::expecting("text literal or compatible"))?,
963                );
964            }
965            Ok(())
966        };
967
968        // Just checking the first item because they can not be mixed "except that byte string
969        // literal notation can be used inside a sequence of concatenated text string notation
970        // literals"
971        let check_first = |item: &String1e<'_>| -> Result<(), TypeMismatch> {
972            if item
973                .encoded_major_type()
974                .map_err(|_| TypeMismatch::expecting("encodable item"))?
975                != Major::TextString
976            {
977                return Err(TypeMismatch::expecting("text literal"));
978            }
979            Ok(())
980        };
981
982        match self.inner() {
983            InnerItem::String(CborString { ref items, .. }) => {
984                check_first(items.first().expect("Part of the type guarantees"))?;
985                append_items(items)?;
986            }
987            InnerItem::StreamString(_, ref chunks) => {
988                check_first(
989                    chunks
990                        .first
991                        .items
992                        .first()
993                        .expect("Part of the type guarantees"),
994                )?;
995                for CborString { ref items, .. } in chunks.iter() {
996                    append_items(items)?;
997                }
998            }
999            _ => return Err(TypeMismatch::expecting("byte literal")),
1000        }
1001
1002        String::from_utf8(result).map_err(|_| TypeMismatch::expecting("valid UTF-8"))
1003    }
1004
1005    /// Access the tag number
1006    ///
1007    /// This only succeeds if the item is a tagged item. Use [`Self::get_tagged()`] to get the
1008    /// corresponding tagged item.
1009    pub fn get_tag(&self) -> Result<u64, TypeMismatch> {
1010        let InnerItem::Tagged(tag, _, _) = self.inner() else {
1011            return Err(TypeMismatch::expecting("tagged item"));
1012        };
1013        Ok(*tag)
1014    }
1015
1016    /// Access the inner item of a tag
1017    ///
1018    /// This only succeeds if the item is a tagged item. Use [`Self::get_tag()`] to get the
1019    /// corresponding tag number.
1020    pub fn get_tagged(&self) -> Result<&StandaloneItem<'a>, TypeMismatch> {
1021        let InnerItem::Tagged(_, _, ref item) = self.inner() else {
1022            return Err(TypeMismatch::expecting("tagged item"));
1023        };
1024        Ok(item)
1025    }
1026
1027    /// Mutably ccess the inner item of a tag
1028    ///
1029    /// This only succeeds if the item is a tagged item. Use [`Self::get_tag()`] to get the
1030    /// corresponding tag number.
1031    pub fn get_tagged_mut(&mut self) -> Result<&mut StandaloneItem<'a>, TypeMismatch> {
1032        let InnerItem::Tagged(_, _, ref mut item) = self.inner_mut() else {
1033            return Err(TypeMismatch::expecting("tagged item"));
1034        };
1035        Ok(item)
1036    }
1037
1038    /// Access the integer value of an item
1039    ///
1040    /// This only succeeds if the item is integer valued; the returned range is an i65 (expressed
1041    /// as an i128 for simplicity).
1042    pub fn get_integer(&self) -> Result<i128, TypeMismatch> {
1043        let InnerItem::Number(ref number, _) = self.inner() else {
1044            return Err(TypeMismatch::expecting("integer"));
1045        };
1046        match number.value() {
1047            NumberValue::Float(_) => Err(TypeMismatch::expecting("integer")),
1048            NumberValue::Positive(n) => Ok(n.into()),
1049            NumberValue::Negative(n) => Ok(-1 - i128::from(n)),
1050            // FIXME: that's definitely not a type mismatch
1051            NumberValue::Big(n) => n
1052                .try_into()
1053                .map_err(|_| TypeMismatch::expecting("integer in i128 range")),
1054        }
1055    }
1056
1057    /// Access the float value of an item
1058    ///
1059    /// This only succeeds if the item is float valued.
1060    pub fn get_float(&self) -> Result<f64, TypeMismatch> {
1061        let InnerItem::Number(ref number, _) = self.inner() else {
1062            return Err(TypeMismatch::expecting("float"));
1063        };
1064        match number.value() {
1065            NumberValue::Float(f) => Ok(f),
1066            NumberValue::Positive(_) => Err(TypeMismatch::expecting("float (not integer)")),
1067            NumberValue::Negative(_) => Err(TypeMismatch::expecting("float (not integer)")),
1068            NumberValue::Big(_) => Err(TypeMismatch::expecting("float (not integer)")),
1069        }
1070    }
1071
1072    /// Access the items inside an array
1073    ///
1074    /// This only succeeds if the item is an array.
1075    pub fn get_array_items(&self) -> Result<impl Iterator<Item = &Item<'a>>, TypeMismatch> {
1076        let InnerItem::Array(smv) = self.inner() else {
1077            return Err(TypeMismatch::expecting("array"));
1078        };
1079
1080        Ok(smv.iter())
1081    }
1082
1083    /// Mutably access the items inside an array
1084    ///
1085    /// This only succeeds if the item is an array.
1086    pub fn get_array_items_mut(
1087        &mut self,
1088    ) -> Result<impl Iterator<Item = &mut Item<'a>>, TypeMismatch> {
1089        let InnerItem::Array(smv) = self.inner_mut() else {
1090            return Err(TypeMismatch::expecting("array"));
1091        };
1092
1093        Ok(smv.iter_mut())
1094    }
1095
1096    /// Access the items inside a map
1097    ///
1098    /// This only succeeds if the item is a map.
1099    pub fn get_map_items(
1100        &self,
1101    ) -> Result<impl Iterator<Item = (&Item<'a>, &Item<'a>)>, TypeMismatch> {
1102        let InnerItem::Map(smv) = self.inner() else {
1103            return Err(TypeMismatch::expecting("map"));
1104        };
1105
1106        Ok(smv.iter().map(|kp| (&kp.key, &kp.value)))
1107    }
1108
1109    /// Access the items inside a map
1110    ///
1111    /// This only succeeds if the item is a map.
1112    pub fn get_map_items_mut(
1113        &mut self,
1114    ) -> Result<impl Iterator<Item = (&mut Item<'a>, &mut Item<'a>)>, TypeMismatch> {
1115        let InnerItem::Map(smv) = self.inner_mut() else {
1116            return Err(TypeMismatch::expecting("map"));
1117        };
1118
1119        Ok(smv.iter_mut().map(|kp| (&mut kp.key, &mut kp.value)))
1120    }
1121
1122    /// Removes any encoding indicators present in the item.
1123    ///
1124    /// This does not affect space or comments; in particular, an item containing only the
1125    /// necessary space may be left with extraneous (but harmless) space that was previously needed
1126    /// to set an encoding indicator apart from a value.
1127    pub fn discard_encoding_indicators(&mut self) {
1128        self.inner_mut().discard_encoding_indicators();
1129    }
1130
1131    /// Alters how space and comments are placed inside the item.
1132    ///
1133    /// Being a plain [`Item`], this only affects inner space; it can not have any around itself.
1134    ///
1135    /// See the policy values for details.
1136    pub fn set_delimiters(&mut self, policy: DelimiterPolicy) {
1137        self.0.set_delimiters(policy);
1138    }
1139
1140    /// Turn the item into a [`StandaloneItem`] and add a single new comment
1141    pub fn with_comment(self, comment: &str) -> StandaloneItem<'a> {
1142        let wrapped_comment = if comment.contains('/') {
1143            format!("# {}\n", comment.replace('\n', "\n# "))
1144        } else {
1145            format!("/ {} /", comment)
1146        };
1147        StandaloneItem(S(wrapped_comment.into()), self, S::default())
1148    }
1149
1150    /// Calls a callback on any key item inside the map.
1151    ///
1152    /// Calling this on a non-map item returns a [type mismatch error][TypeMismatch].
1153    ///
1154    /// An error string returned by the callback is stored in the tree as a comment next to the
1155    /// key. A successful result may also contain text that gets placed next to the key, and may
1156    /// contain a callback that gets applied in the same fashion to the value after the key.
1157    ///
1158    /// # Example
1159    ///
1160    /// The [`application::comment_ccs`] method is an exampel of a callback function.
1161    ///
1162    /// # Future development
1163    ///
1164    /// Once `feature(try_trait)` is usable, those return types can be simplified; until then,
1165    /// using a [`Result`] enables easy propagation of errors out of the callbacks.
1166    pub fn visit_map_elements<F>(&mut self, f: &mut F) -> Result<(), TypeMismatch>
1167    where
1168        F: FnMut(
1169                &mut Item<'a>,
1170                &mut Item<'a>,
1171            ) -> Result<(Option<String>, Result<Option<String>, String>), String>
1172            + ?Sized,
1173    {
1174        use crate::space::Spaceish;
1175
1176        let InnerItem::Map(map) = &mut self.0 else {
1177            return Err(TypeMismatch::expecting("map"));
1178        };
1179        let SpecMscVec::Present {
1180            spec: _,
1181            s: first_space,
1182            items,
1183        } = map
1184        else {
1185            // empty map, nothing to do.
1186            return Ok(());
1187        };
1188        let mut tail = items.tail.iter_mut().peekable();
1189
1190        // Not used because currently we only do comments after:
1191        let _space_before_key = first_space;
1192        let key = &mut items.first.key;
1193        let space_after_key = &mut items.first.s0;
1194        // Not used because currently we only do comments after:
1195        let _space_before_value = &mut items.first.s1;
1196        let value = &mut items.first.value;
1197        let space_after_value = tail
1198            .peek_mut()
1199            .map(|i| &mut i.0 as &mut dyn Spaceish)
1200            .unwrap_or(&mut items.soc);
1201
1202        // This block is copied below because we have subtly different items here and there
1203        let (key_comment, value_comment) = match f(key, value) {
1204            Ok(r) => r,
1205            Err(e) => (Some(e), Ok(None)),
1206        };
1207        let value_comment = match value_comment {
1208            Ok(s) => s,
1209            Err(s) => Some(s),
1210        };
1211        if let Some(key_comment) = key_comment {
1212            space_after_key.prepend_comment(&key_comment)
1213        }
1214        if let Some(value_comment) = value_comment {
1215            space_after_value.prepend_comment(&value_comment)
1216        }
1217
1218        while let Some((msc, next)) = tail.next() {
1219            // Not used because currently we only do comments after:
1220            let _space_before_key = msc;
1221            let key = &mut next.key;
1222            let space_after_key = &mut next.s0;
1223            // Not used because currently we only do comments after:
1224            let _space_before_value = &mut items.first.s1;
1225            let value = &mut next.value;
1226            let space_after_value = tail
1227                .peek_mut()
1228                .map(|i| &mut i.0 as &mut dyn Spaceish)
1229                .unwrap_or(&mut items.soc);
1230
1231            // Copied from above
1232            let (key_comment, value_comment) = match f(key, value) {
1233                Ok(r) => r,
1234                Err(e) => (Some(e), Ok(None)),
1235            };
1236            let value_comment = match value_comment {
1237                Ok(s) => s,
1238                Err(s) => Some(s),
1239            };
1240            if let Some(key_comment) = key_comment {
1241                space_after_key.prepend_comment(&key_comment)
1242            }
1243            if let Some(value_comment) = value_comment {
1244                space_after_value.prepend_comment(&value_comment)
1245            }
1246        }
1247
1248        Ok(())
1249    }
1250
1251    /// Calls a callback on any key item inside the array.
1252    ///
1253    /// Calling this on a non-array item returns a [type mismatch error][TypeMismatch].
1254    ///
1255    /// An error string returned by the callback is stored in the tree as a comment next to the
1256    /// item, as is the string in the successful variant.
1257    ///
1258    /// # Example
1259    ///
1260    /// The [`application::comment_lang_tag`] method is an exampel of a callback function. It is
1261    /// relatively complex (see below).
1262    ///
1263    /// # Future development
1264    ///
1265    /// Once `feature(try_trait)` is usable, those return types can be simplified; until then,
1266    /// using a [`Result`] enables easy propagation of errors out of the callbacks.
1267    ///
1268    /// This function is relatively impractical to use: When a callback needs to know its position
1269    /// in the array (which is a frequent occurrence in inhomogenous arrays), it needs to use
1270    /// internal state to count up; in doing so it needs to be a closure rather than a function,
1271    /// and due to [suboptimal lifetimes](https://codeberg.org/chrysn/cbor-edn/issues/9) that means
1272    /// that the callback may easily need to be boxed.
1273    pub fn visit_array_elements<F>(&mut self, f: &mut F) -> Result<(), TypeMismatch>
1274    where
1275        F: FnMut(&mut Item<'a>) -> Result<Option<String>, String> + ?Sized,
1276    {
1277        if !matches!(self.0, InnerItem::Array(_)) {
1278            return Err(TypeMismatch::expecting("array"));
1279        }
1280        self.visit(&mut ArrayElementVisitor::new(f)).done();
1281        Ok(())
1282    }
1283}
1284
1285impl Unparse for StandaloneItem<'_> {
1286    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1287        self.0.serialize_write(formatter)?;
1288        self.1.serialize_write(formatter)?;
1289        self.2.serialize_write(formatter)?;
1290        Ok(())
1291    }
1292
1293    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1294        self.1.to_cbor()
1295    }
1296}
1297
1298impl Unparse for Item<'_> {
1299    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1300        self.0.serialize_write(formatter)
1301    }
1302
1303    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1304        self.0.to_cbor()
1305    }
1306}
1307
1308impl<'a> From<InnerItem<'a>> for StandaloneItem<'a> {
1309    fn from(inner: InnerItem<'a>) -> Self {
1310        Item::from(inner).into()
1311    }
1312}
1313
1314impl<'a> From<Item<'a>> for StandaloneItem<'a> {
1315    fn from(inner: Item<'a>) -> Self {
1316        Self(S::default(), inner, S::default())
1317    }
1318}
1319
1320impl<'a> From<InnerItem<'a>> for Item<'a> {
1321    fn from(inner: InnerItem<'a>) -> Self {
1322        Item(inner)
1323    }
1324}
1325
1326/// A CBOR Sequence.
1327///
1328/// Typical actions on this are the same as on [`StandaloneItem`], but it can process multiple CBOR
1329/// items in a row, and thus offers interaction with all those items:
1330///
1331/// ```
1332/// # use cbor_edn::*;
1333/// let from_edn = Sequence::parse("
1334///     1
1335///     2
1336///     3
1337/// ").unwrap();
1338/// assert_eq!(from_edn.items().count(), 3);
1339/// ```
1340#[derive(Debug, Clone, PartialEq)]
1341pub struct Sequence<'a> {
1342    s0: S<'a>,
1343    items: Option<NonemptyMscVec<'a, Item<'a>>>,
1344}
1345
1346impl<'a> Sequence<'a> {
1347    /// Ingests CBOR Diagnostic Notation (EDN) representing a CBOR sequence
1348    ///
1349    /// Note that this will only return syntactic errors. Content errors that make it impossible to
1350    /// produce this as CBOR, such as non-matching encoding indicators or unknown application
1351    /// oriented literals, are not reported.
1352    pub fn parse(s: &'a str) -> Result<Self, ParseError> {
1353        cbordiagnostic::seq(s).map_err(ParseError)
1354    }
1355
1356    /// Produce an EDN String from the sequence
1357    pub fn serialize(&self) -> String {
1358        Unparse::serialize(self)
1359    }
1360
1361    pub fn from_cbor(cbor: &[u8]) -> Result<Self, CborError> {
1362        let mut tail = cbor;
1363        // Could this be more efficient if we returned an iterator? Yes. Would it be easier to
1364        // maintain? Probably not.
1365        let mut items = vec![];
1366        while !tail.is_empty() {
1367            let (item, new_tail) = Item::from_cbor_with_rest(tail)?;
1368            items.push(item);
1369            tail = new_tail;
1370        }
1371        let mut s = Self::new(items.into_iter());
1372        s.set_delimiters(DelimiterPolicy::SingleLineRegularSpacing);
1373        Ok(s)
1374    }
1375
1376    /// Parses a CBOR sequence, allowing incomplete items.
1377    ///
1378    /// If at the end of the data there is an incomplete CBOR item, rather than producing an error,
1379    /// this produces ellipses wherever there is incomplete data.
1380    ///
1381    /// ```
1382    /// # use cbor_edn::Sequence;
1383    /// let from_cbor = Sequence::from_cbor_possibly_incomplete(
1384    ///     &[0x82, 0x65, 0x61, 0x62, 0x63]
1385    /// ).unwrap();
1386    /// assert_eq!(from_cbor.serialize(), r#"["abc" + ..., ...], ..."#);
1387    /// ```
1388    pub fn from_cbor_possibly_incomplete(cbor: &[u8]) -> Result<Self, CborError> {
1389        let mut tail = cbor;
1390        let mut items = vec![];
1391        while !tail.is_empty() {
1392            let (item, new_tail) = Item::from_cbor_with_rest_possibly_erroneous(tail)?;
1393            items.push(item);
1394            match new_tail {
1395                Ok(t) => tail = t,
1396                Err(e) => {
1397                    if e.is_out_of_data() {
1398                        // really it's "zero or more"
1399                        items.push(Item::error_ellipsis(&e));
1400                        break;
1401                    } else {
1402                        return Err(e);
1403                    }
1404                }
1405            }
1406        }
1407        let mut s = Self::new(items.into_iter());
1408        s.set_delimiters(DelimiterPolicy::SingleLineRegularSpacing);
1409        Ok(s)
1410    }
1411
1412    /// Encode into a binary CBOR representation
1413    pub fn to_cbor(&self) -> Result<Vec<u8>, InconsistentEdn> {
1414        Ok(Unparse::to_cbor(self)?.collect())
1415    }
1416
1417    /// Construct a CBOR sequence from items
1418    pub fn new(mut items: impl Iterator<Item = Item<'a>>) -> Self {
1419        Sequence {
1420            s0: Default::default(),
1421            items: items.next().map(|first| NonemptyMscVec::new(first, items)),
1422        }
1423    }
1424
1425    /// Access the items of the sequence
1426    pub fn items(&self) -> impl Iterator<Item = &Item<'a>> {
1427        self.items.as_ref().map(|i| i.iter()).into_iter().flatten()
1428    }
1429
1430    /// Mutably access the items of the sequence
1431    pub fn items_mut(&mut self) -> impl Iterator<Item = &mut Item<'a>> {
1432        self.items
1433            .as_mut()
1434            .map(|i| i.iter_mut())
1435            .into_iter()
1436            .flatten()
1437    }
1438
1439    #[deprecated(note = "renamed to items_mut()")]
1440    pub fn get_items_mut(&mut self) -> impl Iterator<Item = &mut Item<'a>> {
1441        self.items_mut()
1442    }
1443
1444    /// Removes any encoding indicators present in the sequence.
1445    ///
1446    /// This does not affect space or comments; in particular, an item containing only the
1447    /// necessary space may be left with extraneous (but harmless) space that was previously needed
1448    /// to set an encoding indicator apart from a value.
1449    pub fn discard_encoding_indicators(&mut self) {
1450        for i in self.items_mut() {
1451            i.discard_encoding_indicators()
1452        }
1453    }
1454
1455    /// Clone the item, turning any [`Cow::Borrowed`] into owned versions, which can then satisfy
1456    /// any lifetime.
1457    pub fn cloned<'any>(&self) -> Sequence<'any> {
1458        Sequence {
1459            s0: self.s0.cloned(),
1460            items: self.items.as_ref().map(|i| i.cloned()),
1461        }
1462    }
1463}
1464
1465impl Unparse for Sequence<'_> {
1466    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1467        self.s0.serialize_write(formatter)?;
1468        if let Some(items) = self.items.as_ref() {
1469            items.serialize_write(formatter)?;
1470        }
1471        Ok(())
1472    }
1473
1474    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1475        let chain = self.items.as_ref().map(|items| items.to_cbor());
1476        let chain = chain.transpose();
1477        chain.map(|optit| optit.into_iter().flatten())
1478    }
1479}
1480
1481/// Rule set for the `set_delimiters()` family of methods
1482#[derive(Copy, Clone, Debug, PartialEq)]
1483#[non_exhaustive]
1484pub enum DelimiterPolicy {
1485    /// Remove all comments, optional space and commas; place commas exactly where in there absence there
1486    /// would need to be space instead.
1487    DiscardAll,
1488    /// Like [`DiscardAll`][DelimiterPolicy::DiscardAll], but leave comments in place.
1489    DiscardAllButComments,
1490    /// Set commas where separation is mandatory, followed by a single space; set a single space after colons of key-value pairs.
1491    ///
1492    /// All other space and commas are removed. Comments are retained, including space between
1493    /// adjacent comments.
1494    SingleLineRegularSpacing,
1495    /// Replace all space with automated indentation. Comments are left in place, including line
1496    /// breaks, space and commas inside or between adjacent comments.
1497    ///
1498    /// For an easy default construction, see the [`.indented()`](Self::indented) method.
1499    IndentedRegularSpacing {
1500        /// Indentation level at the start
1501        base_indent: usize,
1502        /// Indentation added per nesting level
1503        indent_level: usize,
1504        /// Maximum width of lines that is left as a single item.
1505        ///
1506        /// If zero, this will wrap all nested structures; otherwise, it will leave small items
1507        /// with `SingleLineRegularSpacing`.
1508        ///
1509        /// Note that this measures line width in bytes; this is not exact if non-ASCII characters
1510        /// are involved, but a good enough estimate for most EDN content.
1511        max_width: usize,
1512        /// Guides whether
1513        trailing_newline: TrailingNewlinePolicy,
1514    },
1515    /// Set a single space wherever one is allowed.
1516    ///
1517    /// This is not a practical policy over-all, but some functions may set this for their
1518    /// downstream items.
1519    SingleSpace,
1520}
1521
1522impl DelimiterPolicy {
1523    /// Constructor for [`Self::IndentedRegularSpacing`] with default settings
1524    pub const fn indented() -> Self {
1525        Self::IndentedRegularSpacing {
1526            base_indent: 0,
1527            indent_level: 4,
1528            max_width: 80,
1529            trailing_newline: TrailingNewlinePolicy::IfMultiline,
1530        }
1531    }
1532
1533    /// Constructs a policy with default settings (like [`.indented()`][Self::indented]), but
1534    /// always producing a final newline.
1535    pub const fn indented_with_final_newline() -> Self {
1536        Self::IndentedRegularSpacing {
1537            base_indent: 0,
1538            indent_level: 4,
1539            max_width: 80,
1540            trailing_newline: TrailingNewlinePolicy::Always,
1541        }
1542    }
1543}
1544
1545#[derive(Copy, Clone, Debug, PartialEq)]
1546pub enum TrailingNewlinePolicy {
1547    /// Never produces a newline at the end of EDN
1548    Never,
1549    /// Produces a newline at the end of EDN if there are any internal newlines
1550    IfMultiline,
1551    /// Always produces a newline at the end of EDN
1552    Always,
1553}
1554
1555/// Trait through which a parsed CBOR diagnostic notation item can be turned back into a string
1556trait Unparse: Sized {
1557    /// Write the full item into a given formatter
1558    ///
1559    /// This is mainly used to implement this trait, but rarely called from the outside.
1560    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result;
1561
1562    /// Produce a String from the full item
1563    ///
1564    /// No reason is known to not use the provided method; this is what is usually called on an
1565    /// item implemlenting this trait.
1566    fn serialize(&self) -> String {
1567        struct Unparsed<'a, T: Unparse>(&'a T);
1568        impl<T: Unparse> core::fmt::Display for Unparsed<'_, T> {
1569            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1570                self.0.serialize_write(f)
1571            }
1572        }
1573
1574        format!("{}", Unparsed(self))
1575    }
1576
1577    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn>;
1578}
1579
1580/// This represents a `T *(MSC T) SOC` sequence.
1581///
1582/// This type is common to CBOR sequences, streamstrings and array/map, with different mechsnisms of
1583/// optionality around them ("just have the whole thing None", "there must be at least one" and
1584/// "the empty variant has a different type (specms vs. spec) next to it").
1585#[derive(Debug, Clone, PartialEq)]
1586struct NonemptyMscVec<'a, T: Unparse> {
1587    // Most users of this are somehow inside Item, and T is usally an item itself -- so we box the
1588    // T here to avoid recursively sized types.
1589    first: Box<T>,
1590    tail: Vec<(MSC<'a>, T)>,
1591    soc: SOC<'a>,
1592}
1593
1594impl<'a, T: Unparse> NonemptyMscVec<'a, T> {
1595    /// Creates a new instance from just the items, with default space.
1596    fn new(first: T, tail: impl Iterator<Item = T>) -> Self {
1597        Self {
1598            first: Box::new(first),
1599            tail: tail.map(|i| (Default::default(), i)).collect(),
1600            soc: Default::default(),
1601        }
1602    }
1603
1604    /// Creates a new instance, taking explicitly all space components (as used in a parser).
1605    fn new_parsing(first: T, tail: Vec<(MSC<'a>, T)>, soc: SOC<'a>) -> Self {
1606        Self {
1607            first: Box::new(first),
1608            tail,
1609            soc,
1610        }
1611    }
1612
1613    fn len(&self) -> usize {
1614        1 + self.tail.len()
1615    }
1616
1617    fn iter(&self) -> impl Iterator<Item = &T> {
1618        core::iter::once(&*self.first).chain(self.tail.iter().map(|(_msc, t)| t))
1619    }
1620}
1621
1622impl<'a> NonemptyMscVec<'a, Item<'a>> {
1623    fn visit(&mut self, visitor: &mut impl Visitor<'a>) -> ProcessResult {
1624        let mut own_result = self.first.visit(visitor);
1625        let mut last_result: Option<ProcessResult> = None;
1626        for (msc, item) in self.tail.iter_mut() {
1627            if let Some(result) = last_result.take() {
1628                result.use_space_after(msc).done();
1629            } else {
1630                own_result = own_result.use_space_after(msc);
1631            }
1632            let item_result = item.visit(visitor);
1633            let replaced = last_result.replace(item_result.use_space_before(msc));
1634            assert!(replaced.is_none());
1635        }
1636        if let Some(result) = last_result.take() {
1637            result.use_space_after(&mut self.soc).done();
1638        } else {
1639            own_result = own_result.use_space_after(&mut self.soc);
1640        }
1641
1642        own_result
1643    }
1644
1645    fn cloned<'any>(&self) -> NonemptyMscVec<'any, Item<'any>> {
1646        NonemptyMscVec {
1647            first: Box::new(self.first.cloned()),
1648            tail: self
1649                .tail
1650                .iter()
1651                .map(|(msc, i)| (msc.cloned(), i.cloned()))
1652                .collect(),
1653            soc: self.soc.cloned(),
1654        }
1655    }
1656}
1657// Those ↑ and ↓ are identical, but we don't have a trait for being visit'able and having a
1658// cloned()… should we?
1659impl<'a> NonemptyMscVec<'a, Kp<'a>> {
1660    fn visit(&mut self, visitor: &mut impl Visitor<'a>) -> ProcessResult {
1661        let mut own_result = self.first.visit(visitor);
1662        let mut last_result: Option<ProcessResult> = None;
1663        for (msc, item) in self.tail.iter_mut() {
1664            if let Some(result) = last_result.take() {
1665                result.use_space_after(msc).done();
1666            } else {
1667                own_result = own_result.use_space_after(msc);
1668            }
1669            let item_result = item.visit(visitor);
1670            let replaced = last_result.replace(item_result.use_space_before(msc));
1671            assert!(replaced.is_none());
1672        }
1673        if let Some(result) = last_result.take() {
1674            result.use_space_after(&mut self.soc).done();
1675        } else {
1676            own_result = own_result.use_space_after(&mut self.soc);
1677        }
1678
1679        own_result
1680    }
1681
1682    fn cloned<'any>(&self) -> NonemptyMscVec<'any, Kp<'any>> {
1683        NonemptyMscVec {
1684            first: Box::new(self.first.cloned()),
1685            tail: self
1686                .tail
1687                .iter()
1688                .map(|(msc, i)| (msc.cloned(), i.cloned()))
1689                .collect(),
1690            soc: self.soc.cloned(),
1691        }
1692    }
1693}
1694// ↓ And that's only needef for around strings
1695impl<'a> NonemptyMscVec<'a, CborString<'a>> {
1696    fn cloned<'any>(&self) -> NonemptyMscVec<'any, CborString<'any>> {
1697        NonemptyMscVec {
1698            first: Box::new(self.first.cloned()),
1699            tail: self
1700                .tail
1701                .iter()
1702                .map(|(msc, i)| (msc.cloned(), i.cloned()))
1703                .collect(),
1704            soc: self.soc.cloned(),
1705        }
1706    }
1707}
1708
1709// With feature(precise_capturing), we can use the impl … + use syntax, and unify over T.
1710// fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + use<'_, 'a, T> {
1711macro_rules! nmv_concrete_impl {
1712    ($t:ident) => {
1713        impl<'a> NonemptyMscVec<'a, $t<'a>> {
1714            fn iter_mut(&mut self) -> impl Iterator<Item = &mut $t<'a>> {
1715                let first: &mut $t<'a> = &mut self.first;
1716                let tail = &mut self.tail;
1717                core::iter::once(first).chain(tail.iter_mut().map(|(_msc, i)| i))
1718            }
1719        }
1720    };
1721}
1722nmv_concrete_impl!(Item);
1723nmv_concrete_impl!(CborString);
1724
1725impl<T: Unparse> Unparse for NonemptyMscVec<'_, T> {
1726    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1727        self.first.serialize_write(formatter)?;
1728        for (msc, item) in self.tail.iter() {
1729            msc.serialize_write(formatter)?;
1730            item.serialize_write(formatter)?;
1731        }
1732        self.soc.serialize_write(formatter)?;
1733        Ok(())
1734    }
1735
1736    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1737        // Collecting in a vec of inner iterators to flush out the error early
1738        let collected: Result<Vec<_>, _> = self.iter().map(Unparse::to_cbor).collect();
1739        Ok(collected?.into_iter().flatten())
1740    }
1741}
1742
1743/// An empty-allowing extension of [`NonemptyMscVec`] where the empty and nonempty versions differ
1744/// in that the empty version has a spec and the nonempty version has a specms.
1745///
1746/// Note that this is a bit funny in that the space after specms is always empty when there is
1747/// Some spec (because then its inner MS consumes them), whereas when there is no spec, the space
1748/// lands in the `.s`.
1749#[derive(Debug, Clone, PartialEq)]
1750enum SpecMscVec<'a, T: Unparse> {
1751    Present {
1752        spec: Option<(Spec, MS<'a>)>,
1753        s: S<'a>,
1754        items: NonemptyMscVec<'a, T>,
1755    },
1756    Absent {
1757        spec: Option<Spec>,
1758        s: S<'a>,
1759    },
1760}
1761
1762impl<T: Unparse> SpecMscVec<'_, T> {
1763    /// Construct a new list from a spec and items
1764    fn new(spec: Option<Spec>, mut items: impl Iterator<Item = T>) -> Self {
1765        if let Some(first) = items.next() {
1766            // The Some is a bit weird here because the type of SpecMscVec expects Spec to
1767            // non-nullable; we'll see how this develops once that is removed)
1768            SpecMscVec::Present {
1769                spec: spec.map(|spec| (spec, Default::default())),
1770                s: Default::default(),
1771                items: NonemptyMscVec::new(first, items),
1772            }
1773        } else {
1774            SpecMscVec::Absent {
1775                spec,
1776                s: Default::default(),
1777            }
1778        }
1779    }
1780
1781    fn len(&self) -> usize {
1782        match self {
1783            SpecMscVec::Present { items, .. } => items.len(),
1784            SpecMscVec::Absent { .. } => 0,
1785        }
1786    }
1787
1788    fn spec(&self) -> Option<Spec> {
1789        match self {
1790            SpecMscVec::Present {
1791                spec: Some((spec, _ms)),
1792                ..
1793            } => Some(*spec),
1794            SpecMscVec::Present { spec: None, .. } => None,
1795            SpecMscVec::Absent { spec, .. } => *spec,
1796        }
1797    }
1798
1799    fn iter(&self) -> impl Iterator<Item = &T> {
1800        let (first, tail) = match self {
1801            SpecMscVec::Absent { .. } => (None, None),
1802            SpecMscVec::Present {
1803                items: NonemptyMscVec { first, tail, .. },
1804                ..
1805            } => (Some(first.as_ref()), Some(tail)),
1806        };
1807        first
1808            .into_iter()
1809            .chain(tail.into_iter().flatten().map(|(_msc, i)| i))
1810    }
1811
1812    /// Discards the own spec.
1813    ///
1814    /// On presence, this discards a single blank character from the MS that becomes the S (for the
1815    /// common case of the MS just having that mandatory space), but retains any other space
1816    /// including comments.
1817    fn discard_own_encoding_indicator(&mut self) {
1818        match self {
1819            SpecMscVec::Absent { spec, .. } => *spec = None,
1820            SpecMscVec::Present { spec, s, .. } => {
1821                if let Some((_spec, ms)) = spec.take() {
1822                    if ms != Default::default() {
1823                        // Most of the time, s is already empty, but during manipulation, it can
1824                        // get some value too.
1825                        s.prefix(ms.0);
1826                    }
1827                }
1828            }
1829        }
1830    }
1831}
1832
1833// With feature(precise_capturing), we can use the impl … + use syntax, and unify over T. When
1834// restoring the generic form, beware that this will require an explicit lifetime on the impl
1835// (instead of `impl<T: …> SpecMscVec<'_, T>`).
1836//
1837// fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + use<'_, 'a, T> {
1838macro_rules! smv_concrete_impl {
1839    ($t:ident) => {
1840        impl<'a> SpecMscVec<'a, $t<'a>> {
1841            fn iter_mut(&mut self) -> impl Iterator<Item = &mut $t<'a>> {
1842                let (first, tail) = match self {
1843                    SpecMscVec::Absent { .. } => (None, None),
1844                    SpecMscVec::Present {
1845                        items: NonemptyMscVec { first, tail, .. },
1846                        ..
1847                    } => (Some(first.as_mut()), Some(tail)),
1848                };
1849                first
1850                    .into_iter()
1851                    .chain(tail.into_iter().flatten().map(|(_msc, i)| i))
1852            }
1853
1854            // This one is not sufferyng from feature(precise_capt) but from our .cloned() not being a
1855            // trait method.
1856            fn cloned<'any>(&self) -> SpecMscVec<'any, $t<'any>> {
1857                match self {
1858                    SpecMscVec::Present { spec, s, items } => SpecMscVec::Present {
1859                        spec: spec.as_ref().map(|(spec, ms)| (*spec, ms.cloned())),
1860                        s: s.cloned(),
1861                        items: items.cloned(),
1862                    },
1863                    SpecMscVec::Absent { spec, s } => SpecMscVec::Absent {
1864                        spec: spec.map(|s| s.clone()),
1865                        s: s.cloned(),
1866                    },
1867                }
1868            }
1869        }
1870    };
1871}
1872smv_concrete_impl!(Item);
1873smv_concrete_impl!(Kp);
1874
1875impl<'a> SpecMscVec<'a, Item<'a>> {
1876    fn visit(&mut self, visitor: &mut impl Visitor<'a>) {
1877        match self {
1878            SpecMscVec::Present { spec: _, s, items } => {
1879                // anything to after the last item is processed internally
1880                items.visit(visitor).use_space_before(s).done();
1881            }
1882            SpecMscVec::Absent { spec: _, s: _ } => (),
1883        }
1884    }
1885}
1886// Those ↑ and ↓ are identical, but we don't have a trait for being visit'able … should we?
1887impl<'a> SpecMscVec<'a, Kp<'a>> {
1888    fn visit(&mut self, visitor: &mut impl Visitor<'a>) {
1889        match self {
1890            SpecMscVec::Present { spec: _, s, items } => {
1891                // anything to after the last item is processed internally
1892                items.visit(visitor).use_space_before(s).done();
1893            }
1894            SpecMscVec::Absent { spec: _, s: _ } => (),
1895        }
1896    }
1897}
1898
1899impl<T: Unparse> Unparse for SpecMscVec<'_, T> {
1900    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1901        match self {
1902            SpecMscVec::Present { spec, s, items } => {
1903                if let Some((spec, msc)) = spec {
1904                    spec.serialize_write(formatter)?;
1905                    msc.serialize_write(formatter)?;
1906                }
1907                s.serialize_write(formatter)?;
1908                items.serialize_write(formatter)?;
1909                Ok(())
1910            }
1911            SpecMscVec::Absent { spec, s } => {
1912                if let Some(spec) = spec {
1913                    spec.serialize_write(formatter)?;
1914                }
1915                s.serialize_write(formatter)?;
1916                Ok(())
1917            }
1918        }
1919    }
1920
1921    // This writes just the CBOR items; it is up to the caller to process the spec.
1922    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1923        // FIXME: Or is this just now the point to split Unparse and not implement the CBOR side?
1924
1925        // Collecting in a vec of inner iterators to flush out the error early
1926        let collected: Result<Vec<_>, _> = self.iter().map(Unparse::to_cbor).collect();
1927        Ok(collected?.into_iter().flatten())
1928    }
1929}
1930
1931/// A key-value pair of CBOR items, both surrounded by [S]pace, separated by a ":"
1932#[derive(Debug, Clone, PartialEq)]
1933struct Kp<'a> {
1934    key: Item<'a>,
1935    s0: S<'a>,
1936    s1: S<'a>,
1937    value: Item<'a>,
1938}
1939
1940impl<'a> Kp<'a> {
1941    fn new(key: Item<'a>, value: Item<'a>) -> Self {
1942        Self {
1943            key,
1944            s0: Default::default(),
1945            s1: Default::default(),
1946            value,
1947        }
1948    }
1949
1950    fn visit(&mut self, visitor: &mut impl Visitor<'a>) -> ProcessResult {
1951        let key_result = self.key.visit(visitor);
1952        let value_result = self.value.visit(visitor);
1953        key_result
1954            .use_space_after(&mut self.s0)
1955            .chain(value_result.use_space_before(&mut self.s1))
1956    }
1957
1958    fn cloned<'any>(&self) -> Kp<'any> {
1959        Kp {
1960            key: self.key.cloned(),
1961            s0: self.s0.cloned(),
1962            s1: self.s1.cloned(),
1963            value: self.value.cloned(),
1964        }
1965    }
1966}
1967
1968impl Unparse for Kp<'_> {
1969    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
1970        self.key.serialize_write(formatter)?;
1971        self.s0.serialize_write(formatter)?;
1972        formatter.write_str(":")?;
1973        self.s1.serialize_write(formatter)?;
1974        self.value.serialize_write(formatter)?;
1975        Ok(())
1976    }
1977
1978    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
1979        Ok([self.key.to_cbor()?, self.value.to_cbor()?]
1980            .into_iter()
1981            .flatten())
1982    }
1983}
1984
1985#[derive(Debug, Clone, PartialEq)]
1986enum Simple<'a> {
1987    False,
1988    True,
1989    Null,
1990    Undefined,
1991    // Note that later processing may be upset if the string is not a Number item, but cpa'something' may make sense
1992    Numeric(Box<StandaloneItem<'a>>),
1993}
1994impl Simple<'_> {
1995    pub(crate) fn cloned<'any>(&self) -> Simple<'any> {
1996        match self {
1997            Simple::False => Simple::False,
1998            Simple::True => Simple::True,
1999            Simple::Null => Simple::Null,
2000            Simple::Undefined => Simple::Undefined,
2001            Simple::Numeric(standalone_item) => Simple::Numeric(Box::new(standalone_item.cloned())),
2002        }
2003    }
2004}
2005
2006impl Unparse for Simple<'_> {
2007    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
2008        match self {
2009            Simple::False => formatter.write_str("false")?,
2010            Simple::True => formatter.write_str("true")?,
2011            Simple::Null => formatter.write_str("null")?,
2012            Simple::Undefined => formatter.write_str("undefined")?,
2013            Simple::Numeric(i) => {
2014                formatter.write_str("simple(")?;
2015                i.serialize_write(formatter)?;
2016                formatter.write_str(")")?;
2017            }
2018        }
2019        Ok(())
2020    }
2021
2022    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
2023        let mut result = Vec::new();
2024        match self {
2025            Simple::False => result.push(0xf4),
2026            Simple::True => result.push(0xf5),
2027            Simple::Null => result.push(0xf6),
2028            Simple::Undefined => result.push(0xf7),
2029            Simple::Numeric(i) => {
2030                let InnerItem::Number(ref number, spec) = i.inner() else {
2031                    return Err(InconsistentEdn(
2032                        "Items inside simple() need to be numbers for serialization.",
2033                    ));
2034                };
2035                let NumberValue::Positive(number) = number.value() else {
2036                    return Err(InconsistentEdn(
2037                        "Non-positive numbers can not be in a Simple",
2038                    ));
2039                };
2040                if number > 255 {
2041                    return Err(InconsistentEdn("Spec exceeds valid range of 0..=255"));
2042                }
2043                let requested = Spec::encode_argument(spec.as_ref(), Major::FloatSimple, number)?;
2044                let permissible = Spec::encode_argument(None, Major::FloatSimple, number)?;
2045                if requested != permissible {
2046                    return Err(InconsistentEdn(
2047                        "Encoding indicators on simple value must use the preferred encoding",
2048                    ));
2049                }
2050                result.extend(permissible);
2051            }
2052        };
2053        Ok(result.into_iter())
2054    }
2055}
2056
2057impl<'a> From<Simple<'a>> for Item<'a> {
2058    fn from(input: Simple<'a>) -> Self {
2059        InnerItem::Simple(input).into()
2060    }
2061}
2062
2063/// An arbitrary CBOR item
2064#[derive(Clone, Debug, PartialEq)]
2065enum InnerItem<'a> {
2066    Map(SpecMscVec<'a, Kp<'a>>),
2067    Array(SpecMscVec<'a, Item<'a>>),
2068    Tagged(u64, Option<Spec>, Box<StandaloneItem<'a>>),
2069    /// Stored as a string, but we could also explicitly capture the variation:
2070    /// * is a sign present? (even in an integer negative 0?)
2071    /// * what is the base?
2072    /// * how many leading zeros are there?
2073    /// * is there an explicit power (and if so, does it have an explicit sign, or leading zeros?)
2074    /// * note that there are no inner spaces or underscors: no "1 000 000" or "1_000_000", the
2075    ///   latter would conflict with encoding indicators.
2076    ///
2077    /// (and it can be arbitrarily long, exceeding a u64)
2078    Number(Number<'a>, Option<Spec>),
2079    Simple(Simple<'a>),
2080    String(CborString<'a>),
2081    StreamString(MS<'a>, NonemptyMscVec<'a, CborString<'a>>),
2082}
2083
2084impl<'a> InnerItem<'a> {
2085    /// Discard any encoding indicators ([Spec]) that may be part of the item
2086    fn discard_encoding_indicators(&mut self) {
2087        match self {
2088            InnerItem::Map(items) => {
2089                for i in items.iter_mut() {
2090                    i.key.discard_encoding_indicators();
2091                    i.value.discard_encoding_indicators();
2092                }
2093                items.discard_own_encoding_indicator();
2094            }
2095            InnerItem::Array(items) => {
2096                for i in items.iter_mut() {
2097                    i.discard_encoding_indicators();
2098                }
2099                items.discard_own_encoding_indicator();
2100            }
2101            InnerItem::Tagged(_n, spec, item) => {
2102                *spec = None;
2103                item.item_mut().discard_encoding_indicators();
2104            }
2105            InnerItem::Number(_n, spec) => {
2106                *spec = None;
2107            }
2108            InnerItem::Simple(Simple::Numeric(i)) => i.item_mut().discard_encoding_indicators(),
2109            InnerItem::Simple(_) => {}
2110            InnerItem::String(items) => {
2111                items.discard_encoding_indicators();
2112            }
2113            InnerItem::StreamString(_ms, items) => {
2114                // FIXME: Shouldn't this just become String? (StreamString is kind of an encoding
2115                // indicator)
2116                for i in items.iter_mut() {
2117                    i.discard_encoding_indicators();
2118                }
2119            }
2120        }
2121    }
2122
2123    fn set_delimiters(&mut self, policy: DelimiterPolicy) {
2124        use DelimiterPolicy::*;
2125
2126        let nested_policy = if let IndentedRegularSpacing {
2127            base_indent,
2128            indent_level,
2129            max_width,
2130            trailing_newline,
2131        } = policy
2132        {
2133            // Try fitting it in one line; that doesn't do anything that won't be changed by proper
2134            // indentation later anyway, so we don't need to roll back.
2135            self.set_delimiters(SingleLineRegularSpacing);
2136            if self.serialize().len() + base_indent < max_width {
2137                return;
2138            }
2139
2140            IndentedRegularSpacing {
2141                base_indent: base_indent + indent_level,
2142                indent_level,
2143                max_width,
2144                trailing_newline,
2145            }
2146        } else {
2147            policy
2148        };
2149
2150        match self {
2151            InnerItem::Map(items) => match items {
2152                SpecMscVec::Absent { s, .. } => s.set_delimiters(nested_policy, false),
2153                SpecMscVec::Present { s, items, .. } => {
2154                    s.set_delimiters(nested_policy, true);
2155                    let set_on_item = |kp: &mut Kp| {
2156                        kp.key.set_delimiters(nested_policy);
2157                        kp.value.set_delimiters(nested_policy);
2158                        kp.s0.set_delimiters(nested_policy, false);
2159                        if matches!(policy, SingleLineRegularSpacing) {
2160                            kp.s1.0 = " ".into();
2161                        } else {
2162                            // Or true … but that may need an extra case in the top-level
2163                            // inden`ted-to-single-line logic
2164                            kp.s1.set_delimiters(nested_policy, false);
2165                        }
2166                    };
2167                    set_on_item(&mut items.first);
2168                    for (msc, item) in items.tail.iter_mut() {
2169                        set_on_item(item);
2170                        msc.set_delimiters(nested_policy, true);
2171                    }
2172                    items.soc.set_delimiters(policy, true);
2173                }
2174            },
2175            InnerItem::Array(items) => match items {
2176                SpecMscVec::Absent { s, .. } => s.set_delimiters(nested_policy, false),
2177                SpecMscVec::Present { s, items, .. } => {
2178                    s.set_delimiters(nested_policy, true);
2179                    items.first.set_delimiters(nested_policy);
2180                    for (msc, item) in items.tail.iter_mut() {
2181                        item.set_delimiters(nested_policy);
2182                        msc.set_delimiters(nested_policy, true);
2183                    }
2184                    items.soc.set_delimiters(policy, true);
2185                }
2186            },
2187            InnerItem::Tagged(_n, _spec, item) => {
2188                item.set_delimiters(nested_policy);
2189            }
2190            InnerItem::Number(_n, _spec) => {}
2191            InnerItem::Simple(Simple::Numeric(item)) => {
2192                // Setting the nested_policy on the item as a whole would lead to unsightly indentation --
2193                // setting it piecemeal instead.
2194                item.0.set_delimiters(nested_policy, false);
2195                item.1.set_delimiters(nested_policy);
2196                item.2.set_delimiters(nested_policy, false);
2197            }
2198            InnerItem::Simple(_) => {}
2199            InnerItem::String(CborString { items, separators }) => {
2200                for i in items {
2201                    i.set_delimiters(nested_policy);
2202                }
2203                for (sep_pre, sep_post) in separators {
2204                    match nested_policy {
2205                        SingleLineRegularSpacing => {
2206                            sep_pre.set_delimiters(SingleSpace, true);
2207                            sep_post.set_delimiters(SingleSpace, false);
2208                        }
2209                        _ => {
2210                            sep_pre.set_delimiters(nested_policy, true);
2211                            sep_post.set_delimiters(nested_policy, false);
2212                        }
2213                    }
2214                }
2215            }
2216            InnerItem::StreamString(ms, NonemptyMscVec { first, tail, soc }) => {
2217                ms.set_delimiters(nested_policy, true);
2218                first.set_delimiters(nested_policy);
2219                for (ms, item) in tail {
2220                    ms.set_delimiters(nested_policy, true);
2221                    item.set_delimiters(nested_policy);
2222                }
2223                soc.set_delimiters(policy, true);
2224            }
2225        }
2226    }
2227
2228    fn visit(&mut self, visitor: &mut impl Visitor<'a>) {
2229        match self {
2230            InnerItem::Map(spec_msc_vec) => {
2231                spec_msc_vec.visit(visitor);
2232            }
2233            InnerItem::Array(spec_msc_vec) => {
2234                spec_msc_vec.visit(visitor);
2235            }
2236            InnerItem::Tagged(_number, _spec, standalone_item) => {
2237                use transformable::sealed::Transformable;
2238                // This mainly returns no ProcessResult because comments can well be placed inside
2239                // the item -- but if someone really wants to act on the outside, that could be
2240                // taken through here.
2241                standalone_item.visit(visitor);
2242            }
2243            InnerItem::Number(_number, _spec) => (),
2244            InnerItem::Simple(_simple) => (),
2245            InnerItem::String(_cbor_string) => (),
2246            InnerItem::StreamString(_ms, _nonempty_msc_vec) => (),
2247        }
2248    }
2249
2250    fn cloned<'any>(&self) -> InnerItem<'any> {
2251        match self {
2252            InnerItem::Map(spec_msc_vec) => InnerItem::Map(spec_msc_vec.cloned()),
2253            InnerItem::Array(spec_msc_vec) => InnerItem::Array(spec_msc_vec.cloned()),
2254            InnerItem::Tagged(tag, spec, standalone_item) => {
2255                InnerItem::Tagged(*tag, *spec, Box::new(standalone_item.cloned()))
2256            }
2257            InnerItem::Number(number, spec) => InnerItem::Number(number.cloned(), *spec),
2258            InnerItem::Simple(simple) => InnerItem::Simple(simple.cloned()),
2259            InnerItem::String(cbor_string) => InnerItem::String(cbor_string.cloned()),
2260            InnerItem::StreamString(ms, nonempty_msc_vec) => {
2261                InnerItem::StreamString(ms.cloned(), nonempty_msc_vec.cloned())
2262            }
2263        }
2264    }
2265}
2266
2267impl Unparse for InnerItem<'_> {
2268    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
2269        match self {
2270            InnerItem::Map(items) => {
2271                write!(formatter, "{{")?;
2272                items.serialize_write(formatter)?;
2273                write!(formatter, "}}")?;
2274                Ok(())
2275            }
2276            InnerItem::Array(items) => {
2277                write!(formatter, "[")?;
2278                items.serialize_write(formatter)?;
2279                write!(formatter, "]")?;
2280                Ok(())
2281            }
2282            InnerItem::Tagged(n, spec, item) => {
2283                write!(formatter, "{}", n)?;
2284                if let Some(spec) = spec {
2285                    spec.serialize_write(formatter)?;
2286                }
2287                formatter.write_str("(")?;
2288                item.serialize_write(formatter)?;
2289                formatter.write_str(")")?;
2290                Ok(())
2291            }
2292            InnerItem::Number(n, spec) => {
2293                formatter.write_str(&n.0)?;
2294                if let Some(spec) = spec {
2295                    spec.serialize_write(formatter)?;
2296                }
2297                Ok(())
2298            }
2299            InnerItem::Simple(s) => s.serialize_write(formatter),
2300            InnerItem::String(s) => s.serialize_write(formatter),
2301            InnerItem::StreamString(ms, nmv) => {
2302                formatter.write_str("(_")?;
2303                ms.serialize_write(formatter)?;
2304                nmv.serialize_write(formatter)?;
2305                formatter.write_str(")")?;
2306                Ok(())
2307            }
2308        }
2309    }
2310
2311    fn to_cbor(&self) -> Result<impl Iterator<Item = u8>, InconsistentEdn> {
2312        let mut result = vec![];
2313        match self {
2314            InnerItem::Map(smv) => {
2315                let len = smv.len();
2316                let spec = smv.spec();
2317                let (head, tail) = Spec::encode_item_count(spec.as_ref(), Major::Map, len)?;
2318                result.extend(head);
2319                for i in smv.iter() {
2320                    result.extend(i.to_cbor()?);
2321                }
2322                result.extend(tail);
2323            }
2324            InnerItem::Array(smv) => {
2325                let len = smv.len();
2326                let spec = smv.spec();
2327                let (head, tail) = Spec::encode_item_count(spec.as_ref(), Major::Array, len)?;
2328                result.extend(head);
2329                for i in smv.iter() {
2330                    result.extend(i.to_cbor()?);
2331                }
2332                result.extend(tail);
2333            }
2334            InnerItem::Tagged(n, spec, item) => {
2335                result.extend(Spec::encode_argument(spec.as_ref(), Major::Tagged, *n)?);
2336                result.extend(item.to_cbor()?);
2337            }
2338            InnerItem::Number(n, spec) => match n.value() {
2339                NumberValue::Positive(n) => {
2340                    result.extend(Spec::encode_argument(spec.as_ref(), Major::Unsigned, n)?)
2341                }
2342                NumberValue::Negative(n) => {
2343                    result.extend(Spec::encode_argument(spec.as_ref(), Major::Negative, n)?)
2344                }
2345                NumberValue::Float(n) => result.extend(float::encode(n, *spec)?),
2346                NumberValue::Big(n) => match spec {
2347                    None => {
2348                        let (tag, positive) = if n >= num_bigint::BigInt::ZERO {
2349                            (2, n)
2350                        } else {
2351                            (3, -n)
2352                        };
2353                        use num_traits::ops::bytes::ToBytes;
2354                        result.extend(Spec::encode_argument(None, Major::Tagged, tag)?);
2355                        let bytes = positive.to_be_bytes();
2356                        result.extend(Spec::encode_argument(
2357                            None,
2358                            Major::ByteString,
2359                            bytes
2360                                .len()
2361                                .try_into()
2362                                .expect("Even on 128-bit systems, EDN does not exceed 64bit sizes"),
2363                        )?);
2364                        result.extend(bytes);
2365                    }
2366                    _ => {
2367                        return Err(InconsistentEdn(
2368                            "Encoding indicators not specified for bignums",
2369                        ))
2370                    }
2371                },
2372            },
2373            InnerItem::Simple(s) => result.extend(s.to_cbor()?),
2374            InnerItem::String(s) => result.extend(s.to_cbor()?),
2375            InnerItem::StreamString(_ms, NonemptyMscVec { first, tail, .. }) => {
2376                let major = first.encoded_major_type()?;
2377                if !matches!(major, Major::TextString | Major::ByteString) {
2378                    // Syntax can't catch this: Might be an application oriented literal that is
2379                    // not string-valued
2380                    return Err(InconsistentEdn(
2381                        "Item in indefinite length string that is neither bytes nor string",
2382                    ));
2383                }
2384                result.push(((major as u8) << 5) | 31);
2385                result.extend(first.to_cbor()?);
2386                for item in tail.iter() {
2387                    if item.1.encoded_major_type()? != major {
2388                        return Err(InconsistentEdn("Item in indefinite length string has different encoding than head element"));
2389                    }
2390                    result.extend(item.1.to_cbor()?);
2391                }
2392                result.push(0xff);
2393            }
2394        }
2395        Ok(result.into_iter())
2396    }
2397}
2398
2399#[derive(PartialEq, Debug, Copy, Clone)]
2400enum Major {
2401    Unsigned = 0,
2402    Negative = 1,
2403    ByteString = 2,
2404    TextString = 3,
2405    Array = 4,
2406    Map = 5,
2407    Tagged = 6,
2408    FloatSimple = 7,
2409}
2410
2411impl Major {
2412    /// Given a byte, return its major type and the additional information.
2413    fn from_byte(byte: u8) -> (Self, u8) {
2414        (
2415            match byte >> 5 {
2416                0 => Major::Unsigned,
2417                1 => Major::Negative,
2418                2 => Major::ByteString,
2419                3 => Major::TextString,
2420                4 => Major::Array,
2421                5 => Major::Map,
2422                6 => Major::Tagged,
2423                7 => Major::FloatSimple,
2424                _ => unreachable!(),
2425            },
2426            byte & 0x1f,
2427        )
2428    }
2429}
2430
2431/// An encoding indicator
2432///
2433/// Encoding indicators are typically rendered with an underscore, eg. in `4_1`, `_1` is the
2434/// encoding indicator `Spec("1")`, and tells that the number 4 was encoded in more bytes than
2435/// would have been needed.
2436///
2437/// While encoding indicators are described as an extensible registry, new values would interfere
2438/// so deeply with this crate's operation that they would need a code change; consequently, unknown
2439/// values are rejected at parsing time.
2440#[derive(Copy, Clone, Debug, PartialEq)]
2441#[allow(non_camel_case_types)] // reason: underscores are part of what we express here
2442enum Spec {
2443    S_,
2444    S_i,
2445    S_0,
2446    S_1,
2447    S_2,
2448    S_3,
2449}
2450
2451impl Spec {
2452    /// Given an item count, produce the encoded item count for a given Major type (only makes
2453    /// sense for an array and map), as well as any terminator that'd be necessary after the list
2454    /// in case of in indefinite length encoding
2455    fn encode_item_count(
2456        self_: Option<&Self>,
2457        major: Major,
2458        count: usize,
2459    ) -> Result<(Vec<u8>, &[u8]), InconsistentEdn> {
2460        debug_assert!(matches!(major, Major::Map | Major::Array), "Encoding an item count only makes see for maps and arrays; strings work a bit different.");
2461        Ok((
2462            Spec::encode_argument(self_, major, count.try_into().expect("Even on 128bit architectures we can't have more than 64bit long counts of items"))?,
2463            if matches!(self_, Some(Spec::S_)) { [0xff].as_slice() } else { [].as_slice() },
2464        ))
2465    }
2466
2467    fn encode_argument(
2468        self_: Option<&Self>,
2469        major: Major,
2470        argument: u64,
2471    ) -> Result<Vec<u8>, InconsistentEdn> {
2472        let full_spec = match (self_, argument) {
2473            (None, 0..=23) => Self::S_i,
2474            (None, 0..=U8MAX) => Self::S_0,
2475            (None, 0..=U16MAX) => Self::S_1,
2476            (None, 0..=U32MAX) => Self::S_2,
2477            (None, _) => Self::S_3,
2478            (Some(s), _) => *s,
2479        };
2480
2481        let immediate_value = match full_spec {
2482            Self::S_ => 31,
2483            Self::S_i => {
2484                if argument < 24 {
2485                    argument as u8
2486                } else {
2487                    return Err(InconsistentEdn(
2488                        "Immediate encoding demanded but value exceeds 23",
2489                    ));
2490                }
2491            }
2492            Self::S_0 => 24,
2493            Self::S_1 => 25,
2494            Self::S_2 => 26,
2495            Self::S_3 => 27,
2496        };
2497        let first = core::iter::once(((major as u8) << 5) | immediate_value);
2498        Ok(match full_spec {
2499            Self::S_ | Self::S_i => first.collect(),
2500            Self::S_0 => first.chain(u8::try_from(argument)?.to_be_bytes()).collect(),
2501            Self::S_1 => first
2502                .chain(u16::try_from(argument)?.to_be_bytes())
2503                .collect(),
2504            Self::S_2 => first
2505                .chain(u32::try_from(argument)?.to_be_bytes())
2506                .collect(),
2507            Self::S_3 => first.chain(argument.to_be_bytes()).collect(),
2508        })
2509    }
2510
2511    fn serialize_write(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
2512        match self {
2513            Self::S_ => formatter.write_str("_"),
2514            Self::S_i => formatter.write_str("_i"),
2515            Self::S_0 => formatter.write_str("_0"),
2516            Self::S_1 => formatter.write_str("_1"),
2517            Self::S_2 => formatter.write_str("_2"),
2518            Self::S_3 => formatter.write_str("_3"),
2519        }
2520    }
2521
2522    /// Return None if the integer argument leads to self being selected in preferred encoding
2523    /// anyway.
2524    ///
2525    /// We can't do this in [process_cbor_major_argument] because floats are not so trivial to
2526    /// classify.
2527    fn or_none_if_default_for_arg(self, arg: u64) -> Option<Self> {
2528        const U8MAXPLUS: u64 = U8MAX + 1;
2529        const U16MAXPLUS: u64 = U16MAX + 1;
2530        const U32MAXPLUS: u64 = U32MAX + 1;
2531        match (self, arg) {
2532            (Spec::S_i, 0..=23) => None,
2533            (Spec::S_0, 24..=U8MAX) => None,
2534            (Spec::S_1, U8MAXPLUS..=U16MAX) => None,
2535            (Spec::S_2, U16MAXPLUS..=U32MAX) => None,
2536            (Spec::S_3, U32MAXPLUS..=u64::MAX) => None,
2537            (s, _) => Some(s),
2538        }
2539    }
2540}
2541
2542impl core::str::FromStr for Spec {
2543    type Err = &'static str;
2544
2545    fn from_str(s: &str) -> Result<Self, Self::Err> {
2546        match s {
2547            "" => Ok(Self::S_),
2548            "i" => Ok(Self::S_i),
2549            "0" => Ok(Self::S_0),
2550            "1" => Ok(Self::S_1),
2551            "2" => Ok(Self::S_2),
2552            "3" => Ok(Self::S_3),
2553            _ => Err("Unsupported encoding indicator"),
2554        }
2555    }
2556}
2557
2558/// From a byte string, process the first and subsequent bytes into a major type, an argument, and
2559/// a spec
2560///
2561/// Spec will be S_ iff the [`Option<u64>`] is none.
2562#[allow(clippy::type_complexity)]
2563// reason: All items make sense here, and it is an internal function used in situations when you
2564// would expect those very items.
2565fn process_cbor_major_argument(
2566    cbor: &[u8],
2567) -> Result<(Major, Option<u64>, Spec, &[u8]), CborError> {
2568    // It would be tempting to use minicbor or another CBOR implementation, but they don't
2569    // expose which option was chosen for argument, so we are on our own, because we need that
2570    // information for encoding indicators.
2571    let head = cbor
2572        .first()
2573        .ok_or(CborError::out_of_data("Expected item"))?;
2574
2575    let (major, additional) = Major::from_byte(*head);
2576    let tail = &cbor[1..];
2577
2578    let (argument, spec, skip): (Option<u64>, _, _) = match additional {
2579        0..=23 => (Some(additional.into()), Spec::S_i, 0),
2580        24 => (
2581            Some(
2582                tail.first()
2583                    .copied()
2584                    .ok_or(CborError::out_of_data("Missing 1 byte"))?
2585                    .into(),
2586            ),
2587            Spec::S_0,
2588            1,
2589        ),
2590        25 => (
2591            Some(
2592                u16::from_be_bytes(
2593                    tail.get(..2)
2594                        .ok_or(CborError::out_of_data("Missing 2 bytes"))?
2595                        .try_into()
2596                        .unwrap(),
2597                )
2598                .into(),
2599            ),
2600            Spec::S_1,
2601            2,
2602        ),
2603        26 => (
2604            Some(
2605                u32::from_be_bytes(
2606                    tail.get(..4)
2607                        .ok_or(CborError::out_of_data("Missing 4 bytes"))?
2608                        .try_into()
2609                        .unwrap(),
2610                )
2611                .into(),
2612            ),
2613            Spec::S_2,
2614            4,
2615        ),
2616        27 => (
2617            Some(u64::from_be_bytes(
2618                tail.get(..8)
2619                    .ok_or(CborError::out_of_data("Missing 8 bytes"))?
2620                    .try_into()
2621                    .unwrap(),
2622            )),
2623            Spec::S_3,
2624            8,
2625        ),
2626        31 => (None, Spec::S_, 0),
2627        _ => return Err(CborError::invalid("Reserved header byte")),
2628    };
2629
2630    Ok((major, argument, spec, &tail[skip..]))
2631}
2632
2633peg::parser! { grammar cbordiagnostic() for str {
2634
2635// seq             = S [item *(MSC item) SOC]
2636    pub rule seq() -> Sequence<'input>
2637        = s0:S() items:(first:item() tail:(msc:MSC() inner:item() { (msc, inner) })* soc:SOC() { NonemptyMscVec::new_parsing(first, tail, soc) })? {
2638            Sequence { s0, items }
2639        }
2640
2641
2642// one-item        = S item S
2643    pub rule one_item() -> StandaloneItem<'input>
2644        = s1:S() i:item() s2:S() { StandaloneItem(s1, i, s2) }
2645
2646// item            = map / array / tagged
2647//                 / number / simple
2648//                 / string / streamstring
2649    rule item() -> Item<'input>
2650        = inner:(map() / array() / tagged() /
2651          number() / simple() /
2652          string:string() { InnerItem::String(string) } / streamstring()) { inner.into() }
2653
2654// string1         = (tstr / bstr) spec
2655    rule string1() -> String1e<'input>
2656        = value:$(tstr() / bstr()) spec:spec() {?
2657            Ok(if value.starts_with("<<") {
2658                // FIXME: How can we propagate the parsing we already did instead of parsing again
2659                // and having bad error handling?
2660                String1e::EmbeddedChunk(cbordiagnostic::seq(&value[2..value.len() - 2]).map_err(|_| "Parse error in embedded CBOR")?, spec)
2661            } else {
2662                String1e::TextChunk(Cow::Borrowed(value), spec)
2663            })
2664        }
2665// string1e        = string1 / ellipsis
2666    rule string1e() -> String1e<'input>
2667        = string1() / ellipsis()
2668// ellipsis        = 3*"." ; "..." or more dots
2669    rule ellipsis() -> String1e<'input>
2670        = dots:$("."*<3,>) { String1e::Ellipsis(dots.len()) }
2671// string          = string1e *(S "+" S string1e)
2672    rule string() -> CborString<'input>
2673        = head:string1e() tail:(separator:S() "+" s1:S() inner:string1e() { (separator, s1, inner) })* {
2674            CborString {
2675                items: core::iter::once(head).chain(tail.iter().map(|(_sep_pre, _sep_post, inner)| inner).cloned()).collect(),
2676                separators: tail.iter().map(|(sep_pre, sep_post, _inner)| (sep_pre.clone(), sep_post.clone())).collect()
2677            }
2678        }
2679
2680// number          = (hexfloat / hexint / octint / binint
2681//                    / decnumber / nonfin) spec
2682    rule number() -> InnerItem<'input>
2683        = num:$((hexfloat() / hexint() / octint() / binint() / decnumber() / nonfin())) spec:spec() {InnerItem::Number(Number(Cow::Borrowed(num)), spec)}
2684
2685// sign            = "+" / "-"
2686    rule sign() -> Sign
2687        = "+" { Sign::Plus } / "-" { Sign::Minus }
2688
2689// decnumber       = [sign] (1*DIGIT ["." *DIGIT] / "." 1*DIGIT)
2690//                          ["e" [sign] 1*DIGIT]
2691    pub rule decnumber() -> NumberParts<'input>
2692        = sign:sign()? prepost:(predot:$(DIGIT()+) postdot:("." postdot:$(DIGIT()*) { postdot })? { (predot, postdot) } / "." postdot:$(DIGIT()+) { ("", Some(postdot)) })
2693                         exponent:(['e'|'E'] sign:sign()? exponent:$(DIGIT()+) {(sign, exponent)})?
2694        {
2695            let (predot, postdot) = prepost;
2696            NumberParts {
2697                base: 10,
2698                sign,
2699                predot,
2700                postdot,
2701                exponent,
2702            }
2703        }
2704// hexfloat        = [sign] "0x" (1*HEXDIG ["." *HEXDIG] / "." 1*HEXDIG)
2705//                          "p" [sign] 1*DIGIT
2706   pub rule hexfloat() -> NumberParts<'input>
2707       = sign:sign()?
2708       "0" ['x'|'X']
2709       prepost:(
2710           predot:$(HEXDIG()+) postdot:("." postdot:$(HEXDIG()*) { postdot })?
2711           { (Some(predot), postdot) }
2712           / "." postdot:$(HEXDIG()+)
2713           { (None, Some(postdot)) }
2714       )
2715       ['p'|'P']
2716       expsign:sign()?
2717       exp:$(DIGIT()+)
2718       {
2719           NumberParts {
2720               base: 16,
2721               sign,
2722               predot: prepost.0.unwrap_or(""),
2723               postdot: prepost.1,
2724               exponent: Some((expsign, exp))
2725           }
2726       }
2727// hexint          = [sign] "0x" 1*HEXDIG
2728   pub rule hexint() -> NumberParts<'input>
2729       = sign:sign()? "0" ['x'|'X'] predot:$(HEXDIG()+) { NumberParts {base: 16, sign, predot, postdot: None, exponent: None} }
2730// octint          = [sign] "0o" 1*ODIGIT
2731   pub rule octint() -> NumberParts<'input>
2732       = sign:sign()? "0" ['o'|'O'] predot:$(ODIGIT()+) { NumberParts {base: 8, sign, predot, postdot: None, exponent: None} }
2733// binint          = [sign] "0b" 1*BDIGIT
2734   pub rule binint() -> NumberParts<'input>
2735       = sign:sign()? "0" ['b'|'B'] predot:$(BDIGIT()+) { NumberParts {base: 2, sign, predot, postdot: None, exponent: None} }
2736// nonfin          = %s"Infinity"
2737//                 / %s"-Infinity"
2738//                 / %s"NaN"
2739    rule nonfin()
2740        = "Infinity" / "-Infinity" / "NaN"
2741// simple          = %s"false"
2742//                 / %s"true"
2743//                 / %s"null"
2744//                 / %s"undefined"
2745//                 / %s"simple(" S item S ")"
2746    rule simple() -> InnerItem<'input>
2747        = "false" { InnerItem::Simple(Simple::False) }
2748                / "true" { InnerItem::Simple(Simple::True) }
2749                / "null" { InnerItem::Simple(Simple::Null) }
2750                / "undefined" { InnerItem::Simple(Simple::Undefined) }
2751                / "simple(" s1:S() i:item() s2:S() ")" {InnerItem::Simple(Simple::Numeric(Box::new(StandaloneItem(s1, i, s2))))}
2752// uint            = "0" / DIGIT1 *DIGIT
2753    rule uint() -> u64
2754        = n:$("0" / DIGIT1() DIGIT()*) {? n.parse().or(Err("Exceeding tag space")) }
2755// tagged          = uint spec "(" S item S ")"
2756    rule tagged() -> InnerItem<'input>
2757        = tag:uint() tagspec:spec() "(" s0:S() value:item() s1:S() ")" { InnerItem::Tagged(tag, tagspec, Box::new(StandaloneItem(s0, value, s1))) }
2758
2759// app-prefix      = lcalpha *lcalnum ; including h and b64
2760//                 / ucalpha *ucalnum ; tagged variant, if defined
2761    pub rule app_prefix() =
2762        quiet!{lcalpha() lcalnum()* / ucalpha() ucalnum()*} / expected!("application prefix")
2763// app-string      = app-prefix sqstr
2764    pub rule app_string() -> (&'input str, String)
2765        = prefix:$(app_prefix()) data:sqstr() { (prefix, data) }
2766// sqstr           = SQUOTE *single-quoted SQUOTE
2767    pub rule sqstr() -> String // Yes it is String: Just because they can contain binary doesn't mean
2768                               // that the ABNF allows it -- no '\xff'.
2769        = SQUOTE() sqstr:single_quoted()* SQUOTE() { sqstr.iter().filter_map(|c| *c).collect() }
2770// bstr            = app-string / sqstr / embedded
2771//                   ; app-string could be any type
2772    rule bstr()
2773        = app_string() / sqstr() / embedded()
2774// tstr            = DQUOTE *double-quoted DQUOTE
2775    pub rule tstr() -> String
2776        = DQUOTE() text:double_quoted()* DQUOTE() { text.iter().filter_map(|c| *c).collect() }
2777
2778// embedded        = "<<" seq ">>"
2779    rule embedded()
2780        = "<<" seq() ">>"
2781
2782// array           = "[" (specms S item *(MSC item) SOC / spec S) "]"
2783    rule array() -> InnerItem<'input>
2784        = "[" array:(
2785            spec:specms() s:S() first:item() tail:(msc:MSC() inner:item() { (msc, inner) })* soc:SOC()
2786            { SpecMscVec::Present { spec, s, items: NonemptyMscVec::new_parsing(first, tail, soc) } }
2787            / spec:spec() s:S()
2788            { SpecMscVec::Absent { spec, s } }
2789            ) "]"
2790        { InnerItem::Array(array) }
2791// map             = "{" (specms S keyp *(MSC keyp) SOC / spec S) "}"
2792    rule map() -> InnerItem<'input>
2793        = "{" map:(
2794            spec:specms() s:S() first:keyp() tail:(msc:MSC() inner:keyp() { (msc, inner) })* soc:SOC()
2795            { SpecMscVec::Present { spec, s, items: NonemptyMscVec::new_parsing(first, tail, soc) } }
2796            / spec:spec() s:S()
2797            { SpecMscVec::Absent { spec, s } }
2798            ) "}"
2799        { InnerItem::Map(map) }
2800// keyp            = item S ":" S item
2801    rule keyp() -> Kp<'input>
2802        = key:item() s0:S() ":" s1:S() value:item() { Kp { key, s0, s1, value } }
2803
2804// ; We allow %x09 HT in prose, but not in strings
2805// blank           = %x09 / %x0A / %x0D / %x20
2806    rule blank() -> ()
2807        = quiet!{"\x09" / "\x0A" / "\x0D" / "\x20"} / expected!("tabs, spaces or newlines")
2808
2809// non-slash       = blank / %x21-2e / %x30-D7FF / %xE000-10FFFF
2810    rule non_slash() -> ()
2811        = blank() / ['\x21'..='\x2e' | '\x30'..='\u{D7FF}' | '\u{E000}'..='\u{10FFFF}'] {}
2812// non-lf          = %x09 / %x0D / %x20-D7FF / %xE000-10FFFF
2813    rule non_lf() -> ()
2814        = ['\x09' | '\x0D' | '\x20'..='\u{D7FF}' | '\u{E000}'..='\u{10FFFF}'] {}
2815
2816// comment         = "/" *non-slash "/"
2817//                 / "#" *non-lf %x0A
2818    rule comment() -> Comment
2819        = quiet!{"/" body:$(non_slash()*) "/" { Comment::Slashed } / "#" body:$(non_lf()*) "\x0A" { Comment::Hashed }} / expected!("comment")
2820
2821// ; optional space
2822// S               = *blank *(comment *blank)
2823    // This rule is expressed twice because it is very common to need `s0:S()`, but for comment
2824    // reshaping we occasionally need the internals
2825    rule S() -> S<'input>
2826        = data:S_details() { S(Cow::Borrowed(data.data)) }
2827    pub(crate) rule S_details() -> SDetails<'input>
2828        = sliced:with_slice(<blank()* comments:(comment:comment() blank()* { comment })* { comments.last().cloned() }>) { SDetails { data: sliced.1, last_comment_style: sliced.0 } }
2829// ; mandatory space
2830// MS              = (blank/comment) S
2831    rule MS() -> MS<'input>
2832        = data:$( (blank() / comment() ) S()) { MS(Cow::Borrowed(data)) }
2833// ; mandatory comma and/or space
2834// MSC             = ("," S) / (MS ["," S])
2835    rule MSC() -> MSC<'input>
2836        = data:$( ("," S()) / (MS() ("," S())?) ) { MSC(Cow::Borrowed(data)) }
2837
2838// ; optional comma and/or space
2839// SOC             = S ["," S]
2840    rule SOC() -> SOC<'input>
2841        = data:$( SOC_details() ) { SOC(Cow::Borrowed(data)) }
2842    pub(crate) rule SOC_details() -> (SDetails<'input>, Option<SDetails<'input>>)
2843        = before:S_details() after:("," after:S_details() { after })? { (before, after) }
2844
2845// ; check semantically that strings are either all text or all bytes
2846// ; note that there must be at least one string to distinguish
2847// streamstring    = "(_" MS string *(MSC string) SOC ")"
2848    rule streamstring() -> InnerItem<'input>
2849        = "(_" ms:MS() first:string() tail:(msc:MSC() inner:string() { (msc, inner) })* soc:SOC() ")" {
2850            InnerItem::StreamString(ms, NonemptyMscVec::new_parsing(first, tail, soc))
2851        }
2852
2853// spec            = ["_" *wordchar]
2854    rule spec() -> Option<Spec>
2855        = quiet!{("_" spec:$(wordchar()*) {? spec.parse() })? } / expected!(r#"a valid encoding indicator ("_", "_i", "_0", "_1", "_2" or "_3")"#)
2856// specms          = ["_" *wordchar MS]
2857    rule specms() -> Option<(Spec, MS<'input>)>
2858        = quiet!{("_" spec:$(wordchar()*) ms:MS() {? spec.parse().map(|spec| (spec, ms)) })? } / expected!(r#"a valid encoding indicator ("_", "_i", "_0", "_1", "_2" or "_3")"#)
2859
2860// double-quoted   = unescaped
2861//                 / SQUOTE
2862//                 / "\" DQUOTE
2863//                 / "\" escapable
2864    rule double_quoted() -> Option<char>
2865        = unescaped() /
2866            SQUOTE() { Some('\'') } /
2867            "\\" DQUOTE() { Some('"') } /
2868            "\\" e:escapable() { Some(e) }
2869
2870// single-quoted   = unescaped
2871//                 / DQUOTE
2872//                 / "\" SQUOTE
2873//                 / "\" escapable
2874    rule single_quoted() -> Option<char>
2875        = unescaped() / DQUOTE() { Some('"') } / "\\" SQUOTE() { Some('\'') } / "\\" e:escapable() { Some(e) }
2876
2877// escapable       = %s"b" ; BS backspace U+0008
2878//                 / %s"f" ; FF form feed U+000C
2879//                 / %s"n" ; LF line feed U+000A
2880//                 / %s"r" ; CR carriage return U+000D
2881//                 / %s"t" ; HT horizontal tab U+0009
2882//                 / "/"   ; / slash (solidus) U+002F (JSON!)
2883//                 / "\"   ; \ backslash (reverse solidus) U+005C
2884//                 / (%s"u" hexchar) ;  uXXXX      U+XXXX
2885    rule escapable() -> char
2886        = "b" { '\x08' }
2887            / "f" { '\x0c' }
2888            / "n" { '\n' }
2889            / "r" { '\r' }
2890            / "t" { '\t' }
2891            / "/" { '/' }
2892            / "\\" { '\\' }
2893            / h:("u" h:hexchar() { h }) { h }
2894
2895// hexchar         = "{" (1*"0" [ hexscalar ] / hexscalar) "}"
2896//                 / non-surrogate
2897//                 / (high-surrogate "\" %s"u" low-surrogate)
2898    rule hexchar() -> char
2899        =
2900            "{" hex:$("0"+ hexscalar()? / hexscalar()) "}"
2901            {
2902                char::try_from(
2903                    u32::from_str_radix(hex, 16)
2904                        .expect("Syntax ensures this works")
2905                    )
2906                    .expect("Syntax rules out surrogate sequences and numbers beyond Unicode specification")
2907            }
2908            / hex:$(non_surrogate())
2909            {
2910                char::try_from(
2911                    u32::from(
2912                        u16::from_str_radix(hex, 16)
2913                            .expect("Syntax ensures this works")
2914                        )
2915                    )
2916                    .expect("Syntax rules out surrogate sequences and numbers beyond Unicode specification")
2917            }
2918            / hl:(h:$(high_surrogate()) "\\" "u" l:$(low_surrogate()) { format!("{h}{l}") /* conveniently, syntax ensures it's always 4 nibbles */ } )
2919            {
2920                encoding_rs::UTF_16BE.decode(
2921                    &u32::from_str_radix(&hl, 16)
2922                        .expect("Syntax ensures this works")
2923                        .to_be_bytes()
2924                        // now it is UTF-16
2925                    )
2926                    .0
2927                    .chars()
2928                    .next()
2929                    .expect("Syntax ensures this produces exactly one valid character")
2930            }
2931// non-surrogate   = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG)
2932//                 / ("D" ODIGIT 2HEXDIG )
2933    rule non_surrogate()
2934        = ((DIGIT() / "A"/"B"/"C" / "E"/"F" / "a"/"b"/"c" / "e"/"f") HEXDIG()*<3,3>)
2935                / (("D" / "d") ODIGIT() HEXDIG()*<2,2> )
2936// high-surrogate  = "D" ("8"/"9"/"A"/"B") 2HEXDIG
2937    rule high_surrogate()
2938        = ("D" / "d") ("8"/"9"/"A"/"B"/"a"/"b") HEXDIG()*<2,2>
2939// low-surrogate   = "D" ("C"/"D"/"E"/"F") 2HEXDIG
2940    rule low_surrogate()
2941        = ("D" / "d") ("C"/"D"/"E"/"F" / "c"/"d"/"e"/"f") HEXDIG()*<2,2>
2942// hexscalar       = "10" 4HEXDIG / HEXDIG1 4HEXDIG
2943//                 / non-surrogate / 1*3HEXDIG
2944    rule hexscalar()
2945        = "10" HEXDIG()*<4,4> / HEXDIG1() HEXDIG()*<4,4> / non_surrogate() / HEXDIG()*<1,3>
2946
2947// ; Note that no other C0 characters are allowed, including %x09 HT
2948// unescaped       = %x0A ; new line
2949//                 / %x0D ; carriage return -- ignored on input
2950//                 / %x20-21
2951//                      ; omit 0x22 "
2952//                 / %x23-26
2953//                      ; omit 0x27 '
2954//                 / %x28-5B
2955//                      ; omit 0x5C \
2956//                 / %x5D-D7FF ; skip surrogate code points
2957//                 / %xE000-10FFFF
2958    // Returning an option to express that the carriage return is ignored
2959    rule unescaped() -> Option<char> = "\r" { None } / good:[ '\x0a' | '\x0D' | '\x20'..='\x21' | '\x23'..='\x26' | '\x28'..='\x5b' | '\x5d'..='\u{d7ff}' | '\u{e000}'..='\u{10ffff}' ] { Some(good) }
2960
2961// DQUOTE          = %x22    ; " double quote
2962    rule DQUOTE() = "\""
2963// SQUOTE          = "'"     ; ' single quote
2964    rule SQUOTE() = "'"
2965
2966// DIGIT           = %x30-39 ; 0-9
2967// DIGIT1          = %x31-39 ; 1-9
2968// ODIGIT          = %x30-37 ; 0-7
2969// BDIGIT          = %x30-31 ; 0-1
2970// HEXDIG          = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
2971// HEXDIG1         = DIGIT1 / "A" / "B" / "C" / "D" / "E" / "F"
2972    rule DIGIT() = quiet!{['0'..='9']} / expected!("digits")
2973    rule DIGIT1() = quiet!{['1'..='9']} / expected!("digits excluding 0")
2974    rule ODIGIT() = ['0'..='7']
2975    rule BDIGIT() = ['0'..='1']
2976    rule HEXDIG() -> u8 = n:$(DIGIT() / ['A'..='F' | 'a'..='f']) { u8::from_str_radix(n, 16).expect("Syntax ensures this is OK") }
2977    rule HEXDIG1() = DIGIT1() / ['A'..='F' | 'a'..='f']
2978
2979// ; Note: double-quoted strings as in "A" are case-insensitive in ABNF
2980// lcalpha         = %x61-7A ; a-z
2981// lcalnum         = lcalpha / DIGIT
2982// ucalpha         = %x41-5A ; A-Z
2983// ucalnum         = ucalpha / DIGIT
2984// wordchar        = "_" / lcalnum / ucalpha ; [_a-z0-9A-Z]
2985    rule lcalpha() = ['a'..='z']
2986    rule lcalnum() = ['a'..='z'] / DIGIT()
2987    rule ucalpha() = ['A'..='Z']
2988    rule ucalnum() = ['A'..='Z'] / DIGIT()
2989    rule wordchar() = "_" / lcalnum() / ucalpha()
2990
2991// Not starting a new grammar for these: their names are unique enough, and they reuse many of the
2992// other definitions
2993
2994// app-string-h    = S *(HEXDIG S HEXDIG S / ellipsis S)
2995//                   ["#" *non-lf]
2996    pub rule app_string_h() -> Vec<u8> = S() byte:(high:HEXDIG() S() low:HEXDIG() S() { (high << 4) | low } / ellipsis() S() {? Err("Hex string was abbreviated") })*
2997        ("#" non_lf()*)?
2998        { byte }
2999
3000    /// Return both the value and slice matched by the rule.
3001    ///
3002    /// This is the canonical workaround to get both a slice and a value, as discussed in
3003    /// <https://github.com/kevinmehall/rust-peg/issues/377#issuecomment-2158664327>
3004    rule with_slice<T>(r: rule<T>) -> (T, &'input str)
3005        = value:&r() input:$(r()) { (value, input) }
3006}}