Skip to main content

ephemeris_documents/json/cst/
tail.rs

1//! Commas and trailing trivia after elements.
2
3use std::fmt::{self, Write as _};
4
5use super::trivia::Trivia;
6use crate::json::Dialect;
7
8/// Whether the source has a comma after an element.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub(crate) enum Comma {
11    Present,
12    Absent,
13}
14
15/// Where an element sits in its container.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub(crate) enum Position {
18    Inner,
19    Last,
20}
21
22impl Position {
23    /// The elements of a container with their positions.
24    pub(super) fn each<T>(elements: &[T]) -> impl Iterator<Item = (Self, &T)> {
25        let (inner, last) = match elements.split_last() {
26            Some((last, inner)) => (inner, Some(last)),
27            None => (elements, None),
28        };
29        inner
30            .iter()
31            .map(|element| (Self::Inner, element))
32            .chain(last.map(|element| (Self::Last, element)))
33    }
34}
35
36/// What follows the value of a member or item: an optional comma and the rest
37/// of the line.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub(crate) struct Tail {
40    /// Between the value and its comma. Empty when there is no comma.
41    pub(super) after_value: Trivia,
42    pub(super) comma: Comma,
43    /// The rest of the line after the value or comma.
44    pub(super) trailing: Trivia,
45}
46
47impl Tail {
48    pub(in crate::json) const fn new(after_value: Trivia, comma: Comma, trailing: Trivia) -> Self {
49        Self {
50            after_value,
51            comma,
52            trailing,
53        }
54    }
55
56    /// The tail of a canonical element: a comma and nothing else.
57    pub(super) fn canonical() -> Self {
58        Self::new(Trivia::default(), Comma::Present, Trivia::default())
59    }
60
61    pub(super) fn trivia_mut(&mut self, visit: &mut dyn FnMut(&mut Trivia)) {
62        visit(&mut self.after_value);
63        visit(&mut self.trailing);
64    }
65
66    pub(super) fn write(
67        &self,
68        f: &mut fmt::Formatter<'_>,
69        dialect: Dialect,
70        position: Position,
71    ) -> fmt::Result {
72        write!(f, "{}", self.after_value)?;
73        if dialect.comma(position, self.comma) {
74            f.write_char(',')?;
75        }
76        write!(f, "{}", self.trailing)
77    }
78}