1use alloc::boxed::Box;
14use alloc::collections::{BTreeMap, BTreeSet};
15use alloc::vec::Vec;
16use core::fmt;
17
18#[cfg(feature = "arbitrary-nums")]
19use bigdecimal::BigDecimal;
20#[cfg(feature = "arbitrary-nums")]
21use num_bigint::BigInt;
22#[cfg(feature = "floats")]
23use ordered_float::OrderedFloat;
24
25use crate::{error, parse};
26
27#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
28#[non_exhaustive]
29pub enum Edn<'e> {
30 Vector(Vec<Self>),
31 Set(BTreeSet<Self>),
32 Map(BTreeMap<Self, Self>),
33 List(Vec<Self>),
34 Key(&'e str),
35 Symbol(&'e str),
36 Str(&'e str),
37 Int(i64),
38 Tagged(&'e str, Box<Self>),
39 #[cfg(feature = "floats")]
40 Double(OrderedFloat<f64>),
41 Rational((i64, i64)),
42 #[cfg(feature = "arbitrary-nums")]
43 BigInt(BigInt),
44 #[cfg(feature = "arbitrary-nums")]
45 BigDec(BigDecimal),
46 Char(char),
47 Bool(bool),
48 Nil,
49}
50
51const SYMBOL_SPECIAL_CHARS: &str = ".*+!-_?$%&=<>:#";
52pub(crate) const MAX_PRETTY_DEPTH: usize = 42;
53
54fn is_symbol_char(c: char) -> bool {
55 c.is_alphanumeric() || SYMBOL_SPECIAL_CHARS.contains(c)
56}
57
58fn is_symbol_start(c: char) -> bool {
59 !c.is_numeric() && !matches!(c, ':' | '#') && is_symbol_char(c)
60}
61
62fn valid_symbol_part(part: &str) -> bool {
63 let mut chars = part.chars();
64 let Some(first) = chars.next() else { return false };
65 let second = chars.clone().next();
66
67 is_symbol_start(first)
68 && !(matches!(first, '-' | '+' | '.') && second.is_some_and(char::is_numeric))
69 && chars.all(is_symbol_char)
70}
71
72pub(crate) fn validate_tag(tag: &str, tag_span: parse::Span) -> error::Result<()> {
73 let tag = tag.strip_prefix(':').unwrap_or(tag);
74 let valid = tag.chars().next().is_some_and(char::is_alphabetic)
75 && match tag.split_once('/') {
76 Some((prefix, name)) => {
77 !name.contains('/') && valid_symbol_part(prefix) && valid_symbol_part(name)
78 }
79 None => valid_symbol_part(tag),
80 };
81
82 if valid { Ok(()) } else { Err(error::Error::from_position(error::Code::InvalidTag, tag_span.0)) }
83}
84
85impl<'e> TryFrom<parse::Node<'e>> for Edn<'e> {
86 type Error = error::Error;
87 fn try_from(parse::Node { kind: value, .. }: parse::Node<'e>) -> error::Result<Self> {
110 use error::{Code, Error, Result};
111 use parse::NodeKind;
112
113 Ok(match value {
114 NodeKind::Vector(items, _) => {
115 Edn::Vector(items.into_iter().map(TryInto::try_into).collect::<Result<_>>()?)
116 }
117 NodeKind::Set(items, _) => {
118 let mut set = BTreeSet::new();
119 for node in items {
120 let position = node.span().1;
121 if !set.insert(node.try_into()?) {
122 return Err(Error::from_position(Code::SetDuplicateKey, position));
123 }
124 }
125 Edn::Set(set)
126 }
127 NodeKind::Map(entries, _) => {
128 let mut map = BTreeMap::new();
129 for (key, value) in entries {
130 let position = value.span().1;
131 if map.insert(key.try_into()?, value.try_into()?).is_some() {
132 return Err(Error::from_position(Code::HashMapDuplicateKey, position));
133 }
134 }
135 Edn::Map(map)
136 }
137 NodeKind::List(items, _) => {
138 Edn::List(items.into_iter().map(TryInto::try_into).collect::<Result<_>>()?)
139 }
140 NodeKind::Key(key) => Edn::Key(key),
141 NodeKind::Symbol(symbol) => Edn::Symbol(symbol),
142 NodeKind::Str(str) => Edn::Str(str),
143 NodeKind::Int(int) => Edn::Int(int),
144 NodeKind::Tagged(tag, tag_span, node) => {
145 validate_tag(tag, tag_span)?;
146 if tag.starts_with(':') && !matches!(&node.kind, NodeKind::Map(..)) {
147 return Err(Error::from_position(Code::InvalidTag, tag_span.0));
148 }
149 Edn::Tagged(tag, Box::new((*node).try_into()?))
150 }
151 #[cfg(feature = "floats")]
152 NodeKind::Double(double) => Edn::Double(double),
153 NodeKind::Rational(rational) => Edn::Rational(rational),
154 #[cfg(feature = "arbitrary-nums")]
155 NodeKind::BigInt(big_int) => Edn::BigInt(big_int),
156 #[cfg(feature = "arbitrary-nums")]
157 NodeKind::BigDec(big_dec) => Edn::BigDec(big_dec),
158 NodeKind::Char(ch) => Edn::Char(ch),
159 NodeKind::Bool(bool) => Edn::Bool(bool),
160 NodeKind::Nil => Edn::Nil,
161 })
162 }
163}
164
165pub fn read_string(edn: &str) -> Result<Edn<'_>, error::Error> {
171 Ok(parse::parse_as_edn(edn)?.0)
172}
173
174pub fn read(edn: &str) -> Result<(Edn<'_>, &str), error::Error> {
183 let (edn, remaining) = parse::parse_optional_edn(edn)?;
184 let Some(edn) = edn else {
185 return Err(error::Error {
186 code: error::Code::UnexpectedEOF,
187 line: None,
188 column: None,
189 ptr: None,
190 });
191 };
192 Ok((edn, remaining))
193}
194
195fn get_tag<'a>(tag: &'a str, key: &'a str) -> Option<&'a str> {
196 if !key.contains('/') {
198 return None;
199 }
200
201 if !tag.starts_with(':') {
203 return None;
204 }
205 let tag = tag.get(1..)?;
206 Some(tag)
207}
208
209fn check_key<'a>(tag: &'a str, key: &'a str) -> &'a str {
210 if key.starts_with(tag) {
212 let (_, key) = key.rsplit_once(tag).expect("Tag must exist, because it starts with it.");
213
214 if let Some(k) = key.strip_prefix('/') {
216 return k;
217 }
218 }
219 key
220}
221
222impl Edn<'_> {
223 pub fn get(&self, e: &Self) -> Option<&Self> {
224 if let Edn::Map(m) = self {
225 return m.get(e);
226 } else if let Edn::Tagged(tag, m) = self {
227 if let Edn::Key(key) = e {
228 let tag = get_tag(tag, key)?;
229 let key = check_key(tag, key);
230
231 return m.get(&Edn::Key(key));
232 }
233
234 return m.get(e);
236 }
237 None
238 }
239 pub fn nth(&self, i: usize) -> Option<&Self> {
240 let vec = match self {
241 Edn::Vector(v) => v,
242 Edn::List(l) => l,
243 _ => return None,
244 };
245
246 vec.get(i)
247 }
248
249 pub fn contains(&self, e: &Self) -> bool {
250 match self {
251 Edn::Map(m) => m.contains_key(e),
252 Edn::Tagged(tag, m) => {
253 if let Edn::Key(key) = e {
254 let Some(tag) = get_tag(tag, key) else { return false };
255 let key = check_key(tag, key);
256
257 return m.contains(&Edn::Key(key));
258 }
259
260 m.contains(e)
262 }
263 Edn::Vector(v) => v.contains(e),
264 Edn::Set(s) => s.contains(e),
265 Edn::List(l) => l.contains(e),
266 _ => false,
267 }
268 }
269}
270
271pub(crate) const fn char_to_edn(c: char) -> Option<&'static str> {
272 match c {
273 '\n' => Some("newline"),
274 '\r' => Some("return"),
275 ' ' => Some("space"),
276 '\t' => Some("tab"),
277 _ => None,
278 }
279}
280
281fn write_indent(f: &mut fmt::Formatter<'_>, depth: usize) -> fmt::Result {
282 for _ in 0..depth {
283 f.write_str("\t")?;
284 }
285 Ok(())
286}
287
288impl Edn<'_> {
289 fn fmt_edn(&self, f: &mut fmt::Formatter<'_>, pretty: bool, depth: usize) -> fmt::Result {
290 let pretty = pretty && depth < MAX_PRETTY_DEPTH;
291 match self {
292 Self::Vector(v) => Self::fmt_sequence(f, "[", "]", v, pretty, depth),
293 Self::Set(s) => Self::fmt_sequence(f, "#{", "}", s, pretty, depth),
294 Self::Map(m) => {
295 f.write_str("{")?;
296 let mut entries = m.iter().peekable();
297 while let Some((key, value)) = entries.next() {
298 if pretty {
299 f.write_str("\n")?;
300 write_indent(f, depth + 1)?;
301 }
302 key.fmt_edn(f, pretty, depth + 1)?;
303 f.write_str(" ")?;
304 value.fmt_edn(f, pretty, depth + 1)?;
305 if entries.peek().is_some() {
306 if pretty {
307 f.write_str(",")?;
308 } else {
309 f.write_str(", ")?;
310 }
311 }
312 }
313 if pretty && !m.is_empty() {
314 f.write_str("\n")?;
315 write_indent(f, depth)?;
316 }
317 f.write_str("}")
318 }
319 Self::List(l) => Self::fmt_sequence(f, "(", ")", l, pretty, depth),
320 Self::Symbol(sy) => write!(f, "{sy}"),
321 Self::Tagged(t, value) => {
322 write!(f, "#{t} ")?;
323 value.fmt_edn(f, pretty, depth)
324 }
325 Self::Key(k) => write!(f, ":{k}"),
326 Self::Str(s) => write!(f, "\"{s}\""),
327 Self::Int(i) => write!(f, "{i}"),
328 #[cfg(feature = "floats")]
329 Self::Double(d) => write!(f, "{d}"),
330 #[cfg(feature = "arbitrary-nums")]
331 Self::BigInt(bi) => write!(f, "{bi}N"),
332 #[cfg(feature = "arbitrary-nums")]
333 Self::BigDec(bd) => write!(f, "{bd}M"),
334 Self::Rational((n, d)) => write!(f, "{n}/{d}"),
335 Self::Bool(b) => write!(f, "{b}"),
336 Self::Char(c) => {
337 f.write_str("\\")?;
338 if let Some(c) = char_to_edn(*c) {
339 return f.write_str(c);
340 }
341 write!(f, "{c}")
342 }
343 Self::Nil => f.write_str("nil"),
344 }
345 }
346
347 fn fmt_sequence<'a, I>(
348 f: &mut fmt::Formatter<'_>,
349 opener: &str,
350 closer: &str,
351 items: I,
352 pretty: bool,
353 depth: usize,
354 ) -> fmt::Result
355 where
356 I: IntoIterator<Item = &'a Self>,
357 Self: 'a,
358 {
359 f.write_str(opener)?;
360 let mut items = items.into_iter().peekable();
361 let mut has_items = false;
362 while let Some(item) = items.next() {
363 has_items = true;
364 if pretty {
365 f.write_str("\n")?;
366 write_indent(f, depth + 1)?;
367 }
368 item.fmt_edn(f, pretty, depth + 1)?;
369 if !pretty && items.peek().is_some() {
370 f.write_str(" ")?;
371 }
372 }
373 if pretty && has_items {
374 f.write_str("\n")?;
375 write_indent(f, depth)?;
376 }
377 f.write_str(closer)
378 }
379}
380
381impl fmt::Display for Edn<'_> {
382 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383 self.fmt_edn(f, f.alternate(), 0)
384 }
385}