Skip to main content

ephemeris_documents/json/cst/
key.rs

1//! Object keys of the JSON syntax tree.
2
3use std::borrow::Cow;
4
5use super::quote::Quote;
6use crate::json::Dialect;
7
8/// An object key: the name it decodes to and, for a parsed key, its source
9/// spelling. A key without one is spelled canonically when printed.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub(crate) struct Key {
12    source: Option<String>,
13    name: String,
14}
15
16impl Key {
17    pub(in crate::json) const fn from_source(source: String, name: String) -> Self {
18        Self {
19            source: Some(source),
20            name,
21        }
22    }
23
24    /// A key that takes the canonical spelling of the dialect it is printed in.
25    pub(super) fn canonical(name: &str) -> Self {
26        Self {
27            source: None,
28            name: name.to_owned(),
29        }
30    }
31
32    pub(in crate::json) fn name(&self) -> &str {
33        &self.name
34    }
35
36    fn is_plain_identifier(name: &str) -> bool {
37        let mut chars = name.chars();
38        match chars.next() {
39            Some(first) if first.is_ascii_alphabetic() || first == '_' || first == '$' => {}
40            _ => return false,
41        }
42        chars.all(|character| {
43            character.is_ascii_alphanumeric() || character == '_' || character == '$'
44        })
45    }
46
47    /// The key as it is printed in `dialect`.
48    pub(super) fn spelling(&self, dialect: Dialect) -> Cow<'_, str> {
49        match &self.source {
50            Some(source) => Cow::Borrowed(source),
51            None if dialect == Dialect::Json5 && Self::is_plain_identifier(&self.name) => {
52                Cow::Borrowed(&self.name)
53            }
54            None => Cow::Owned(Quote::Double.wrap(&self.name)),
55        }
56    }
57}