use crate::parser::classify;
pub(super) const INDENT: &str = " ";
pub(crate) fn push_escaped_key_segment(key: &str, out: &mut String) {
let bytes = key.as_bytes();
let needs_escape = bytes.iter().any(|&b| b == b'\\' || b == b'.' || b == b':');
if !needs_escape {
out.push_str(key);
return;
}
out.reserve(key.len() + 4);
for ch in key.chars() {
match ch {
'\\' => out.push_str("\\\\"),
'.' => out.push_str("\\."),
':' => out.push_str("\\:"),
other => out.push(other),
}
}
}
pub(crate) fn needs_raw_marker(s: &str) -> bool {
match s.as_bytes().first() {
None => false,
Some(&b' ') | Some(&b'\t') => needs_raw_marker_slow(s.trim_start()),
Some(&b'{') | Some(&b'[') => true,
Some(_) => needs_raw_marker_content(s),
}
}
fn needs_raw_marker_content(s: &str) -> bool {
if matches!(s, "null" | "true" | "false" | "(" | "((" | "()" | "(())") {
return true;
}
if s.starts_with('(') {
return true;
}
if classify::matches_integer_grammar(s) || classify::matches_float_grammar(s) {
return true;
}
false
}
#[cold]
#[inline(never)]
fn needs_raw_marker_slow(t: &str) -> bool {
t.starts_with('{') || t.starts_with('[') || needs_raw_marker_content(t)
}
pub(super) fn push_indent(out: &mut String, level: usize) {
const SPACES: &str = " "; let mut remaining = level * INDENT.len();
if remaining == 0 {
return;
}
out.reserve(remaining);
while remaining > 0 {
let chunk = remaining.min(SPACES.len());
out.push_str(&SPACES[..chunk]);
remaining -= chunk;
}
}