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