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 derive;
11pub mod notation;
12pub mod rpc;
13pub mod xml;
14
15#[cfg(feature = "derive")]
16pub use llsd_rs_derive::{LlsdFrom, LlsdFromTo, LlsdInto};
17
18#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub enum Uri {
20 #[default]
21 Empty,
22 Url(Url),
23 String(String, url::ParseError),
24}
25
26impl Uri {
27 pub fn new() -> Self {
28 Uri::Empty
29 }
30
31 pub fn parse(uri: &str) -> Self {
32 let uri = uri.trim();
33 if uri.is_empty() {
34 return Uri::Empty;
35 }
36 match Url::parse(uri) {
37 Ok(url) => Uri::Url(url),
38 Err(e) => Uri::String(uri.to_string(), e),
39 }
40 }
41
42 pub fn as_str(&self) -> &str {
43 match self {
44 Uri::Url(url) => url.as_str(),
45 Uri::String(s, _) => s,
46 Uri::Empty => "",
47 }
48 }
49
50 pub fn is_empty(&self) -> bool {
51 matches!(self, Uri::Empty)
52 }
53
54 pub fn is_url(&self) -> bool {
55 matches!(self, Uri::Url(_))
56 }
57
58 pub fn error(&self) -> Option<url::ParseError> {
59 match self {
60 Uri::String(_, e) => Some(*e),
61 _ => None,
62 }
63 }
64}
65
66impl From<Url> for Uri {
67 fn from(uri: Url) -> Self {
68 Uri::Url(uri)
69 }
70}
71
72impl From<&str> for Uri {
73 fn from(uri: &str) -> Self {
74 Self::parse(uri)
75 }
76}
77
78impl From<String> for Uri {
79 fn from(uri: String) -> Self {
80 Self::parse(&uri)
81 }
82}
83
84impl From<&Uri> for String {
85 fn from(uri: &Uri) -> Self {
86 match uri {
87 Uri::Url(url) => url.to_string(),
88 Uri::String(s, _) => s.clone(),
89 Uri::Empty => String::new(),
90 }
91 }
92}
93
94impl<'a> From<&'a Uri> for &'a str {
95 fn from(uri: &'a Uri) -> Self {
96 match uri {
97 Uri::Url(url) => url.as_str(),
98 Uri::String(s, _) => s,
99 Uri::Empty => "",
100 }
101 }
102}
103
104impl TryFrom<&Uri> for Url {
105 type Error = url::ParseError;
106
107 fn try_from(uri: &Uri) -> core::result::Result<Self, Self::Error> {
108 match uri {
109 Uri::Url(url) => Ok(url.clone()),
110 Uri::String(_, e) => Err(*e),
111 Uri::Empty => Err(url::ParseError::EmptyHost),
112 }
113 }
114}
115
116#[derive(Debug, Default, Clone, EnumAsInner, PartialEq)]
117pub enum Llsd {
118 #[default]
119 Undefined,
120 Boolean(bool),
121 Integer(i32),
122 Real(f64),
123 String(String),
124 Uri(Uri),
125 Uuid(Uuid),
126 Date(DateTime<Utc>),
127 Binary(Vec<u8>),
128 Array(Vec<Llsd>),
129 Map(HashMap<String, Llsd>),
130}
131
132impl Llsd {
133 pub fn new() -> Self {
134 Llsd::Undefined
135 }
136
137 pub fn array() -> Self {
138 Llsd::Array(Vec::new())
139 }
140
141 pub fn map() -> Self {
142 Llsd::Map(HashMap::new())
143 }
144
145 pub fn clear(&mut self) {
146 *self = Llsd::Undefined;
147 }
148
149 pub fn push<T: Into<Llsd>>(mut self, llsd: T) -> Result<Self> {
150 match &mut self {
151 Llsd::Array(array) => array.push(llsd.into()),
152 Llsd::Undefined => {
153 self = Llsd::Array(vec![llsd.into()]);
154 }
155 _ => return Err(anyhow::Error::msg("not an array")),
156 }
157 Ok(self)
158 }
159
160 pub fn insert<K: Into<String>, T: Into<Llsd>>(mut self, key: K, llsd: T) -> Result<Self> {
161 match &mut self {
162 Llsd::Map(map) => {
163 map.insert(key.into(), llsd.into());
164 }
165 Llsd::Undefined => {
166 let mut map = HashMap::new();
167 map.insert(key.into(), llsd.into());
168 self = Llsd::Map(map);
169 }
170 _ => return Err(anyhow::Error::msg("not a map")),
171 }
172 Ok(self)
173 }
174
175 pub fn get(&self, index: impl Index) -> Option<&Llsd> {
176 index.index_into(self)
177 }
178
179 pub fn get_mut(&mut self, index: impl Index) -> Option<&mut Llsd> {
180 index.index_into_mut(self)
181 }
182
183 pub fn contains(&self, index: impl Index) -> bool {
184 self.get(index).is_some()
185 }
186
187 pub fn len(&self) -> usize {
188 match self {
189 Llsd::Array(a) => a.len(),
190 Llsd::Map(m) => m.len(),
191 _ => 0,
192 }
193 }
194
195 pub fn is_empty(&self) -> bool {
196 self.len() == 0
197 }
198
199 pub fn pointer(&self, pointer: &str) -> Option<&Llsd> {
200 if pointer.is_empty() {
201 return Some(self);
202 }
203 if !pointer.starts_with('/') {
204 return None;
205 }
206 pointer
207 .split('/')
208 .skip(1)
209 .map(|x| x.replace("~1", "/").replace("~0", "~"))
210 .try_fold(self, |target, token| match target {
211 Llsd::Array(array) => token.parse::<usize>().ok().and_then(|x| array.get(x)),
212 Llsd::Map(map) => map.get(&token),
213 _ => None,
214 })
215 }
216
217 pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Llsd> {
218 if pointer.is_empty() {
219 return Some(self);
220 }
221 if !pointer.starts_with('/') {
222 return None;
223 }
224 pointer
225 .split('/')
226 .skip(1)
227 .map(|x| x.replace("~1", "/").replace("~0", "~"))
228 .try_fold(self, |target, token| match target {
229 Llsd::Array(array) => token.parse::<usize>().ok().and_then(|x| array.get_mut(x)),
230 Llsd::Map(map) => map.get_mut(&token),
231 _ => None,
232 })
233 }
234
235 pub fn take(&mut self) -> Self {
236 std::mem::replace(self, Llsd::Undefined)
237 }
238}
239
240impl From<bool> for Llsd {
241 fn from(llsd: bool) -> Self {
242 Llsd::Boolean(llsd)
243 }
244}
245
246impl From<&bool> for Llsd {
247 fn from(v: &bool) -> Self {
248 Llsd::Boolean(*v)
249 }
250}
251
252macro_rules! impl_from_int {
253 ($($t:ty),*) => {
254 $(
255 impl From<$t> for Llsd {
256 fn from(llsd: $t) -> Self {
257 Llsd::Integer(llsd as i32)
258 }
259 }
260 impl TryFrom<&Llsd> for $t {
261 type Error = anyhow::Error;
262
263 fn try_from(llsd: &Llsd) -> Result<Self> {
264 match llsd {
265 Llsd::Integer(value) => Ok(*value as $t),
266 Llsd::Real(value) => Ok(*value as $t),
267 Llsd::Boolean(value) => Ok(if *value { 1 } else { 0 } as $t),
268 Llsd::String(value) => {
269 value.parse::<$t>().map_err(|_| anyhow::Error::msg("Invalid integer"))
270 }
271 _ => Err(anyhow::Error::msg("Expected LLSD Integer")),
272 }
273 }
274 }
275 )*
276 };
277}
278
279impl_from_int!(u8, u16, u32, u64, i8, i16, i32, i64);
280
281macro_rules! impl_from_real {
282 ($($t:ty),*) => {
283 $(
284 impl From<$t> for Llsd {
285 fn from(llsd: $t) -> Self {
286 Llsd::Real(llsd as f64)
287 }
288 }
289 impl From<&$t> for Llsd {
290 fn from(llsd: &$t) -> Self {
291 Llsd::Real(*llsd as f64)
292 }
293 }
294 impl TryFrom<&Llsd> for $t {
295 type Error = anyhow::Error;
296
297 fn try_from(llsd: &Llsd) -> Result<Self> {
298 match llsd {
299 Llsd::Real(value) => Ok(*value as $t),
300 Llsd::Integer(value) => Ok(*value as $t),
301 Llsd::Boolean(value) => Ok(if *value { 1.0 } else { 0.0 } as $t),
302 Llsd::String(value) => {
303 value.parse::<$t>().map_err(|_| anyhow::Error::msg("Invalid real"))
304 }
305 _ => Err(anyhow::Error::msg("Expected LLSD Real")),
306 }
307 }
308 }
309 )*
310 };
311}
312
313impl_from_real!(f32, f64);
314
315impl From<&str> for Llsd {
316 fn from(llsd: &str) -> Self {
317 Llsd::String(llsd.to_string())
318 }
319}
320
321impl From<String> for Llsd {
322 fn from(llsd: String) -> Self {
323 Llsd::String(llsd)
324 }
325}
326
327impl From<&String> for Llsd {
328 fn from(v: &String) -> Self {
329 Llsd::String(v.clone())
330 }
331}
332
333impl From<Uuid> for Llsd {
334 fn from(llsd: Uuid) -> Self {
335 Llsd::Uuid(llsd)
336 }
337}
338
339impl From<&Uuid> for Llsd {
340 fn from(v: &Uuid) -> Self {
341 Llsd::Uuid(*v)
342 }
343}
344
345impl From<Url> for Llsd {
346 fn from(llsd: Url) -> Self {
347 Llsd::Uri(llsd.into())
348 }
349}
350
351impl From<&Url> for Llsd {
352 fn from(v: &Url) -> Self {
353 Llsd::Uri(v.clone().into())
354 }
355}
356
357impl From<DateTime<Utc>> for Llsd {
358 fn from(llsd: DateTime<Utc>) -> Self {
359 Llsd::Date(llsd)
360 }
361}
362
363impl From<&DateTime<Utc>> for Llsd {
364 fn from(v: &DateTime<Utc>) -> Self {
365 Llsd::Date(*v)
366 }
367}
368
369impl From<DateTime<FixedOffset>> for Llsd {
370 fn from(llsd: DateTime<FixedOffset>) -> Self {
371 Llsd::Date(llsd.with_timezone(&Utc))
372 }
373}
374
375impl From<&DateTime<FixedOffset>> for Llsd {
376 fn from(v: &DateTime<FixedOffset>) -> Self {
377 Llsd::Date(v.with_timezone(&Utc))
378 }
379}
380
381impl From<&[u8]> for Llsd {
382 fn from(llsd: &[u8]) -> Self {
383 Llsd::Binary(Vec::from(llsd))
384 }
385}
386
387impl<const N: usize> From<[u8; N]> for Llsd {
388 fn from(llsd: [u8; N]) -> Self {
389 Llsd::Binary(llsd.to_vec())
390 }
391}
392
393impl<T: Into<Llsd>> From<Vec<T>> for Llsd {
394 fn from(llsd: Vec<T>) -> Self {
395 Llsd::Array(llsd.into_iter().map(Into::into).collect())
396 }
397}
398
399impl<K: Into<String>, V: Into<Llsd>> From<HashMap<K, V>> for Llsd {
400 fn from(llsd: HashMap<K, V>) -> Self {
401 Llsd::Map(
402 llsd.into_iter()
403 .map(|(k, v)| (k.into(), v.into()))
404 .collect(),
405 )
406 }
407}
408
409impl<A: Into<Llsd>, B: Into<Llsd>> From<(A, B)> for Llsd {
411 fn from(t: (A, B)) -> Self {
412 let (a, b) = t;
413 Llsd::Array(vec![a.into(), b.into()])
414 }
415}
416impl<A, B> TryFrom<&Llsd> for (A, B)
417where
418 for<'x> A: TryFrom<&'x Llsd, Error = anyhow::Error>,
419 for<'x> B: TryFrom<&'x Llsd, Error = anyhow::Error>,
420{
421 type Error = anyhow::Error;
422 fn try_from(v: &Llsd) -> Result<Self> {
423 if let Llsd::Array(a) = v {
424 if a.len() == 2 {
425 Ok((A::try_from(&a[0])?, B::try_from(&a[1])?))
426 } else {
427 Err(anyhow::Error::msg("Expected array of length 2"))
428 }
429 } else {
430 Err(anyhow::Error::msg("Expected LLSD Array"))
431 }
432 }
433}
434
435impl<A: Into<Llsd>, B: Into<Llsd>, C: Into<Llsd>> From<(A, B, C)> for Llsd {
436 fn from(t: (A, B, C)) -> Self {
437 let (a, b, c) = t;
438 Llsd::Array(vec![a.into(), b.into(), c.into()])
439 }
440}
441impl<A, B, C> TryFrom<&Llsd> for (A, B, C)
442where
443 for<'x> A: TryFrom<&'x Llsd, Error = anyhow::Error>,
444 for<'x> B: TryFrom<&'x Llsd, Error = anyhow::Error>,
445 for<'x> C: TryFrom<&'x Llsd, Error = anyhow::Error>,
446{
447 type Error = anyhow::Error;
448 fn try_from(v: &Llsd) -> Result<Self> {
449 if let Llsd::Array(a) = v {
450 if a.len() == 3 {
451 Ok((
452 A::try_from(&a[0])?,
453 B::try_from(&a[1])?,
454 C::try_from(&a[2])?,
455 ))
456 } else {
457 Err(anyhow::Error::msg("Expected array of length 3"))
458 }
459 } else {
460 Err(anyhow::Error::msg("Expected LLSD Array"))
461 }
462 }
463}
464
465impl<A: Into<Llsd>, B: Into<Llsd>, C: Into<Llsd>, D: Into<Llsd>> From<(A, B, C, D)> for Llsd {
466 fn from(t: (A, B, C, D)) -> Self {
467 let (a, b, c, d) = t;
468 Llsd::Array(vec![a.into(), b.into(), c.into(), d.into()])
469 }
470}
471impl<A, B, C, D> TryFrom<&Llsd> for (A, B, C, D)
472where
473 for<'x> A: TryFrom<&'x Llsd, Error = anyhow::Error>,
474 for<'x> B: TryFrom<&'x Llsd, Error = anyhow::Error>,
475 for<'x> C: TryFrom<&'x Llsd, Error = anyhow::Error>,
476 for<'x> D: TryFrom<&'x Llsd, Error = anyhow::Error>,
477{
478 type Error = anyhow::Error;
479 fn try_from(v: &Llsd) -> Result<Self> {
480 if let Llsd::Array(a) = v {
481 if a.len() == 4 {
482 Ok((
483 A::try_from(&a[0])?,
484 B::try_from(&a[1])?,
485 C::try_from(&a[2])?,
486 D::try_from(&a[3])?,
487 ))
488 } else {
489 Err(anyhow::Error::msg("Expected array of length 4"))
490 }
491 } else {
492 Err(anyhow::Error::msg("Expected LLSD Array"))
493 }
494 }
495}
496
497impl<K: Into<String>, V: Into<Llsd>> FromIterator<(K, V)> for Llsd {
498 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
499 Llsd::Map(
500 iter.into_iter()
501 .map(|(k, v)| (k.into(), v.into()))
502 .collect(),
503 )
504 }
505}
506
507impl TryFrom<&Llsd> for Uuid {
508 type Error = anyhow::Error;
509
510 fn try_from(llsd: &Llsd) -> Result<Self> {
511 match llsd {
512 Llsd::Uuid(llsd) => Ok(*llsd),
513 Llsd::String(llsd) => Ok(Uuid::parse_str(llsd.as_str())?),
514 _ => Err(anyhow::Error::msg("not a UUID")),
515 }
516 }
517}
518
519impl TryFrom<&Llsd> for Url {
520 type Error = anyhow::Error;
521
522 fn try_from(llsd: &Llsd) -> Result<Self> {
523 match llsd {
524 Llsd::Uri(uri) => Ok(uri.try_into()?),
525 Llsd::String(llsd) => Ok(Url::parse(llsd.as_str())?),
526 _ => Err(anyhow::Error::msg("not a URL")),
527 }
528 }
529}
530
531mod private {
532 pub trait Sealed {}
533 impl Sealed for usize {}
534 impl Sealed for str {}
535 impl Sealed for String {}
536 impl<T> Sealed for &T where T: ?Sized + Sealed {}
537}
538
539pub trait Index: private::Sealed {
540 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd>;
541 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd>;
542 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd;
543}
544
545impl<I> ops::Index<I> for Llsd
546where
547 I: Index,
548{
549 type Output = Llsd;
550 fn index(&self, index: I) -> &Llsd {
551 static NULL: Llsd = Llsd::Undefined;
552 index.index_into(self).unwrap_or(&NULL)
553 }
554}
555
556impl Index for usize {
557 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
558 match v {
559 Llsd::Array(vec) => vec.get(*self),
560 _ => None,
561 }
562 }
563 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
564 match v {
565 Llsd::Array(vec) => vec.get_mut(*self),
566 _ => None,
567 }
568 }
569 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
570 match v {
571 Llsd::Array(vec) => {
572 let len = vec.len();
573 vec.get_mut(*self).unwrap_or_else(|| {
574 panic!(
575 "cannot access index {} of JSON array of length {}",
576 self, len
577 )
578 })
579 }
580 _ => panic!("cannot access index {}", self),
581 }
582 }
583}
584
585impl Index for str {
586 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
587 match v {
588 Llsd::Map(map) => map.get(self),
589 _ => None,
590 }
591 }
592 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
593 match v {
594 Llsd::Map(map) => map.get_mut(self),
595 _ => None,
596 }
597 }
598 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
599 if let Llsd::Undefined = v {
600 *v = Llsd::Map(HashMap::new());
601 }
602 match v {
603 Llsd::Map(map) => map.entry(self.to_owned()).or_insert(Llsd::Undefined),
604 _ => panic!("cannot access key {:?}", self),
605 }
606 }
607}
608
609impl<T> Index for &T
610where
611 T: ?Sized + Index,
612{
613 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
614 (**self).index_into(v)
615 }
616 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
617 (**self).index_into_mut(v)
618 }
619 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
620 (**self).index_or_insert(v)
621 }
622}
623
624impl Index for String {
625 fn index_into<'v>(&self, v: &'v Llsd) -> Option<&'v Llsd> {
626 self[..].index_into(v)
627 }
628 fn index_into_mut<'v>(&self, v: &'v mut Llsd) -> Option<&'v mut Llsd> {
629 self[..].index_into_mut(v)
630 }
631 fn index_or_insert<'v>(&self, v: &'v mut Llsd) -> &'v mut Llsd {
632 self[..].index_or_insert(v)
633 }
634}
635
636impl<I> ops::IndexMut<I> for Llsd
637where
638 I: Index,
639{
640 fn index_mut(&mut self, index: I) -> &mut Llsd {
641 index.index_or_insert(self)
642 }
643}
644
645impl TryFrom<&Llsd> for bool {
646 type Error = anyhow::Error;
647
648 fn try_from(llsd: &Llsd) -> anyhow::Result<Self> {
649 if let Some(value) = llsd.as_boolean() {
650 Ok(*value)
651 } else {
652 Err(anyhow::Error::msg("Expected LLSD Boolean"))
653 }
654 }
655}
656
657impl TryFrom<&Llsd> for String {
658 type Error = anyhow::Error;
659
660 fn try_from(llsd: &Llsd) -> anyhow::Result<Self> {
661 if let Some(value) = llsd.as_string() {
662 Ok(value.clone())
663 } else {
664 Err(anyhow::Error::msg("Expected LLSD String"))
665 }
666 }
667}
668
669impl<T> TryFrom<&Llsd> for Vec<T>
670where
671 T: for<'a> TryFrom<&'a Llsd, Error = anyhow::Error>,
672{
673 type Error = anyhow::Error;
674
675 fn try_from(llsd: &Llsd) -> anyhow::Result<Self> {
676 if let Some(array) = llsd.as_array() {
677 array.iter().map(|item| T::try_from(item)).collect()
678 } else {
679 Err(anyhow::Error::msg("Expected LLSD Array"))
680 }
681 }
682}
683
684impl<V> TryFrom<&Llsd> for HashMap<String, V>
685where
686 V: for<'a> TryFrom<&'a Llsd, Error = anyhow::Error>,
687{
688 type Error = anyhow::Error;
689
690 fn try_from(llsd: &Llsd) -> anyhow::Result<Self> {
691 if let Some(map) = llsd.as_map() {
692 map.iter()
693 .map(|(k, v)| Ok((k.clone(), V::try_from(v)?)))
694 .collect()
695 } else {
696 Err(anyhow::Error::msg("Expected LLSD Map"))
697 }
698 }
699}