1use std::{collections::HashMap, ops};
2
3use anyhow::Result;
4use chrono::{DateTime, FixedOffset, Utc};
5use enum_as_inner::EnumAsInner;
6use url::Url;
7use uuid::Uuid;
8
9pub mod binary;
10pub mod notation;
11pub mod rpc;
12pub mod xml;
13
14#[derive(Debug, Default, Clone, PartialEq, Eq)]
15pub enum Uri {
16 #[default]
17 Empty,
18 Url(Url),
19 String(String, url::ParseError),
20}
21
22impl Uri {
23 pub fn new() -> Self {
24 Uri::Empty
25 }
26
27 pub fn parse(uri: &str) -> Self {
28 let uri = uri.trim();
29 if uri.is_empty() {
30 return Uri::Empty;
31 }
32 match Url::parse(uri) {
33 Ok(url) => Uri::Url(url),
34 Err(e) => Uri::String(uri.to_string(), e),
35 }
36 }
37
38 pub fn as_str(&self) -> &str {
39 match self {
40 Uri::Url(url) => url.as_str(),
41 Uri::String(s, _) => s,
42 Uri::Empty => "",
43 }
44 }
45
46 pub fn is_empty(&self) -> bool {
47 matches!(self, Uri::Empty)
48 }
49
50 pub fn is_url(&self) -> bool {
51 matches!(self, Uri::Url(_))
52 }
53
54 pub fn error(&self) -> Option<url::ParseError> {
55 match self {
56 Uri::String(_, e) => Some(*e),
57 _ => None,
58 }
59 }
60}
61
62impl From<Url> for Uri {
63 fn from(uri: Url) -> Self {
64 Uri::Url(uri)
65 }
66}
67
68impl From<&str> for Uri {
69 fn from(uri: &str) -> Self {
70 Self::parse(uri)
71 }
72}
73
74impl From<String> for Uri {
75 fn from(uri: String) -> Self {
76 Self::parse(&uri)
77 }
78}
79
80impl From<&Uri> for String {
81 fn from(uri: &Uri) -> Self {
82 match uri {
83 Uri::Url(url) => url.to_string(),
84 Uri::String(s, _) => s.clone(),
85 Uri::Empty => String::new(),
86 }
87 }
88}
89
90impl<'a> From<&'a Uri> for &'a str {
91 fn from(uri: &'a Uri) -> Self {
92 match uri {
93 Uri::Url(url) => url.as_str(),
94 Uri::String(s, _) => s,
95 Uri::Empty => "",
96 }
97 }
98}
99
100impl TryFrom<&Uri> for Url {
101 type Error = url::ParseError;
102
103 fn try_from(uri: &Uri) -> core::result::Result<Self, Self::Error> {
104 match uri {
105 Uri::Url(url) => Ok(url.clone()),
106 Uri::String(_, e) => Err(*e),
107 Uri::Empty => Err(url::ParseError::EmptyHost),
108 }
109 }
110}
111
112#[derive(Debug, Default, Clone, EnumAsInner, PartialEq)]
113pub enum Llsd {
114 #[default]
115 Undefined,
116 Boolean(bool),
117 Integer(i32),
118 Real(f64),
119 String(String),
120 Uri(Uri),
121 Uuid(Uuid),
122 Date(DateTime<Utc>),
123 Binary(Vec<u8>),
124 Array(Vec<Llsd>),
125 Map(HashMap<String, Llsd>),
126}
127
128impl Llsd {
129 pub fn new() -> Self {
130 Llsd::Undefined
131 }
132
133 pub fn array() -> Self {
134 Llsd::Array(Vec::new())
135 }
136
137 pub fn map() -> Self {
138 Llsd::Map(HashMap::new())
139 }
140
141 pub fn clear(&mut self) {
142 *self = Llsd::Undefined;
143 }
144
145 pub fn push<T: Into<Llsd>>(mut self, llsd: T) -> Result<Self> {
146 match &mut self {
147 Llsd::Array(array) => array.push(llsd.into()),
148 Llsd::Undefined => {
149 self = Llsd::Array(vec![llsd.into()]);
150 }
151 _ => return Err(anyhow::Error::msg("not an array")),
152 }
153 Ok(self)
154 }
155
156 pub fn insert<K: Into<String>, T: Into<Llsd>>(mut self, key: K, llsd: T) -> Result<Self> {
157 match &mut self {
158 Llsd::Map(map) => {
159 map.insert(key.into(), llsd.into());
160 }
161 Llsd::Undefined => {
162 let mut map = HashMap::new();
163 map.insert(key.into(), llsd.into());
164 self = Llsd::Map(map);
165 }
166 _ => return Err(anyhow::Error::msg("not a map")),
167 }
168 Ok(self)
169 }
170
171 pub fn get(&self, index: impl Index) -> Option<&Llsd> {
172 index.index_into(self)
173 }
174
175 pub fn get_mut(&mut self, index: impl Index) -> Option<&mut Llsd> {
176 index.index_into_mut(self)
177 }
178
179 pub fn contains(&self, index: impl Index) -> bool {
180 self.get(index).is_some()
181 }
182
183 pub fn len(&self) -> usize {
184 match self {
185 Llsd::Array(a) => a.len(),
186 Llsd::Map(m) => m.len(),
187 _ => 0,
188 }
189 }
190
191 pub fn is_empty(&self) -> bool {
192 self.len() == 0
193 }
194
195 pub fn pointer(&self, pointer: &str) -> Option<&Llsd> {
196 if pointer.is_empty() {
197 return Some(self);
198 }
199 if !pointer.starts_with('/') {
200 return None;
201 }
202 pointer
203 .split('/')
204 .skip(1)
205 .map(|x| x.replace("~1", "/").replace("~0", "~"))
206 .try_fold(self, |target, token| match target {
207 Llsd::Array(array) => token.parse::<usize>().ok().and_then(|x| array.get(x)),
208 Llsd::Map(map) => map.get(&token),
209 _ => None,
210 })
211 }
212
213 pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Llsd> {
214 if pointer.is_empty() {
215 return Some(self);
216 }
217 if !pointer.starts_with('/') {
218 return None;
219 }
220 pointer
221 .split('/')
222 .skip(1)
223 .map(|x| x.replace("~1", "/").replace("~0", "~"))
224 .try_fold(self, |target, token| match target {
225 Llsd::Array(array) => token.parse::<usize>().ok().and_then(|x| array.get_mut(x)),
226 Llsd::Map(map) => map.get_mut(&token),
227 _ => None,
228 })
229 }
230
231 pub fn take(&mut self) -> Self {
232 std::mem::replace(self, Llsd::Undefined)
233 }
234}
235
236impl From<bool> for Llsd {
237 fn from(llsd: bool) -> Self {
238 Llsd::Boolean(llsd)
239 }
240}
241
242macro_rules! impl_from_int {
243 ($($t:ty),*) => {
244 $(
245 impl From<$t> for Llsd {
246 fn from(llsd: $t) -> Self {
247 Llsd::Integer(llsd as i32)
248 }
249 }
250 )*
251 };
252}
253
254impl_from_int!(u8, u16, u32, u64, i8, i16, i32, i64);
255
256macro_rules! impl_from_real {
257 ($($t:ty),*) => {
258 $(
259 impl From<$t> for Llsd {
260 fn from(llsd: $t) -> Self {
261 Llsd::Real(llsd as f64)
262 }
263 }
264 )*
265 };
266}
267
268impl_from_real!(f32, f64);
269
270impl From<&str> for Llsd {
271 fn from(llsd: &str) -> Self {
272 Llsd::String(llsd.to_string())
273 }
274}
275
276impl From<Uuid> for Llsd {
277 fn from(llsd: Uuid) -> Self {
278 Llsd::Uuid(llsd)
279 }
280}
281
282impl From<Url> for Llsd {
283 fn from(llsd: Url) -> Self {
284 Llsd::Uri(llsd.into())
285 }
286}
287
288impl From<DateTime<Utc>> for Llsd {
289 fn from(llsd: DateTime<Utc>) -> Self {
290 Llsd::Date(llsd)
291 }
292}
293
294impl From<DateTime<FixedOffset>> for Llsd {
295 fn from(llsd: DateTime<FixedOffset>) -> Self {
296 Llsd::Date(llsd.with_timezone(&Utc))
297 }
298}
299
300impl From<&[u8]> for Llsd {
301 fn from(llsd: &[u8]) -> Self {
302 Llsd::Binary(Vec::from(llsd))
303 }
304}
305
306impl<const N: usize> From<[u8; N]> for Llsd {
307 fn from(llsd: [u8; N]) -> Self {
308 Llsd::Binary(llsd.to_vec())
309 }
310}
311
312impl<T: Into<Llsd>> From<Vec<T>> for Llsd {
313 fn from(llsd: Vec<T>) -> Self {
314 Llsd::Array(llsd.into_iter().map(Into::into).collect())
315 }
316}
317
318impl<K: Into<String>, V: Into<Llsd>> From<HashMap<K, V>> for Llsd {
319 fn from(llsd: HashMap<K, V>) -> Self {
320 Llsd::Map(
321 llsd.into_iter()
322 .map(|(k, v)| (k.into(), v.into()))
323 .collect(),
324 )
325 }
326}
327
328impl<T: Into<Llsd>> FromIterator<T> for Llsd {
329 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
330 Llsd::Array(iter.into_iter().map(Into::into).collect())
331 }
332}
333
334impl<K: Into<String>, V: Into<Llsd>> FromIterator<(K, V)> for Llsd {
335 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
336 Llsd::Map(
337 iter.into_iter()
338 .map(|(k, v)| (k.into(), v.into()))
339 .collect(),
340 )
341 }
342}
343
344impl TryFrom<&Llsd> for Uuid {
345 type Error = anyhow::Error;
346
347 fn try_from(llsd: &Llsd) -> Result<Self> {
348 match llsd {
349 Llsd::Uuid(llsd) => Ok(*llsd),
350 Llsd::String(llsd) => Ok(Uuid::parse_str(llsd.as_str())?),
351 _ => Err(anyhow::Error::msg("not a UUID")),
352 }
353 }
354}
355
356impl TryFrom<&Llsd> for Url {
357 type Error = anyhow::Error;
358
359 fn try_from(llsd: &Llsd) -> Result<Self> {
360 match llsd {
361 Llsd::Uri(uri) => Ok(uri.try_into()?),
362 Llsd::String(llsd) => Ok(Url::parse(llsd.as_str())?),
363 _ => Err(anyhow::Error::msg("not a URL")),
364 }
365 }
366}
367
368mod private {
369 pub trait Sealed {}
370 impl Sealed for usize {}
371 impl Sealed for str {}
372 impl Sealed for String {}
373 impl<T> Sealed for &T where T: ?Sized + Sealed {}
374}
375
376pub trait Index: private::Sealed {
377 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd>;
378 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd>;
379 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd;
380}
381
382impl<I> ops::Index<I> for Llsd
383where
384 I: Index,
385{
386 type Output = Llsd;
387 fn index(&self, index: I) -> &Llsd {
388 static NULL: Llsd = Llsd::Undefined;
389 index.index_into(self).unwrap_or(&NULL)
390 }
391}
392
393impl Index for usize {
394 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
395 match v {
396 Llsd::Array(vec) => vec.get(*self),
397 _ => None,
398 }
399 }
400 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
401 match v {
402 Llsd::Array(vec) => vec.get_mut(*self),
403 _ => None,
404 }
405 }
406 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
407 match v {
408 Llsd::Array(vec) => {
409 let len = vec.len();
410 vec.get_mut(*self).unwrap_or_else(|| {
411 panic!(
412 "cannot access index {} of JSON array of length {}",
413 self, len
414 )
415 })
416 }
417 _ => panic!("cannot access index {}", self),
418 }
419 }
420}
421
422impl Index for str {
423 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
424 match v {
425 Llsd::Map(map) => map.get(self),
426 _ => None,
427 }
428 }
429 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
430 match v {
431 Llsd::Map(map) => map.get_mut(self),
432 _ => None,
433 }
434 }
435 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
436 if let Llsd::Undefined = v {
437 *v = Llsd::Map(HashMap::new());
438 }
439 match v {
440 Llsd::Map(map) => map.entry(self.to_owned()).or_insert(Llsd::Undefined),
441 _ => panic!("cannot access key {:?}", self),
442 }
443 }
444}
445
446impl<T> Index for &T
447where
448 T: ?Sized + Index,
449{
450 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
451 (**self).index_into(v)
452 }
453 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
454 (**self).index_into_mut(v)
455 }
456 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
457 (**self).index_or_insert(v)
458 }
459}
460
461impl Index for String {
462 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
463 self[..].index_into(v)
464 }
465 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
466 self[..].index_into_mut(v)
467 }
468 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
469 self[..].index_or_insert(v)
470 }
471}
472
473impl<I> ops::IndexMut<I> for Llsd
474where
475 I: Index,
476{
477 fn index_mut(&mut self, index: I) -> &mut Llsd {
478 index.index_or_insert(self)
479 }
480}