json_spanned_value/
spanned.rs

1//! [Spanned] and aliases thereof -
2//! spanned::{[Value], [Null], [Bool],
3//! [Num]\[[ber](Number)\],
4//! [Str]\[[ing](String)\],
5//! [Obj]\[[ect](Object)\],
6//! [Span], [Array]}
7
8use super::{start, end};
9
10use serde::de::*;
11
12use std::borrow::Borrow;
13use std::cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
14use std::convert::*;
15use std::fmt::{self, Debug, Display, Formatter};
16use std::hash::{Hash, Hasher};
17use std::ops::{Deref, Range};
18
19
20
21/// A value with start/end position information.
22/// Can wrap arbitrary [Deserialize]able JSON values, not just basic JSON types.
23#[derive(Clone)]
24pub struct Spanned<V> {
25    pub(crate) start:  usize,
26    pub(crate) end:    usize,
27    pub(crate) value:  V,
28}
29
30impl<V> Spanned<V> {
31    /// Get the starting byte offset (inclusive) of this value.
32    /// Likely `0` unless loaded through [crate::from_*](crate::from_slice).
33    pub fn start(&self) -> usize { self.start }
34
35    /// Get the ending byte offset (non-inclusive) of this value.
36    /// Likely `0` unless loaded through [crate::from_*](crate::from_slice).
37    pub fn end(&self) -> usize { self.end }
38
39    /// Get the start .. end byte offset of this value as a (start, end) tuple.
40    /// Likely `(0, 0)` unless loaded through [crate::from_*](crate::from_slice).
41    pub fn span(&self) -> (usize, usize) { (self.start, self.end) }
42
43    /// Get the start .. end byte offset of this value as a start .. end [Range].
44    /// Likely `0 .. 0` unless loaded through [crate::from_*](crate::from_slice).
45    pub fn range(&self) -> Range<usize> { self.start .. self.end }
46
47    /// Get the interior value of the spanned region as an owned value.
48    pub fn into_inner(self) -> V { self.value }
49
50    /// Get the interior value of the spanned region as a reference.
51    pub fn get_ref(&self) -> &V { &self.value }
52
53    /// Get the interior value of the spanned region as a mutable/exclusive reference.
54    pub fn get_mut(&mut self) -> &mut V { &mut self.value }
55}
56
57impl                    Borrow<str> for Str<'_>    { fn borrow(&self) -> &str { self.get_ref() } }
58impl                    Borrow<str> for String     { fn borrow(&self) -> &str { self.get_ref() } }
59impl<V>                 Deref       for Spanned<V> { fn deref(&self) -> &Self::Target { &self.value } type Target = V; }
60//impl<V>               DerefMut    for Spanned<V> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } }
61impl<R, V: AsRef<R>>    AsRef<R>    for Spanned<V> { fn as_ref(&self) -> &R { self.value.as_ref() } }
62impl<V: Debug>          Debug       for Spanned<V> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { self.value.fmt(fmt) } }
63impl<V: Display>        Display     for Spanned<V> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { self.value.fmt(fmt) } }
64impl<V>                 From<V>     for Spanned<V> { fn from(v: V) -> Self { Self { value: v, start: 0, end: 0 } } }
65impl<V: Eq>             Eq          for Spanned<V> {}
66impl<V: Ord>            Ord         for Spanned<V> { fn cmp(&self, other: &Self) -> Ordering { self.value.cmp(&other.value) } }
67impl<V: PartialEq>      PartialEq   for Spanned<V> { fn eq(&self, other: &Self) -> bool { self.value.eq(&other.value) } }
68impl<V: PartialOrd>     PartialOrd  for Spanned<V> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.value.partial_cmp(&other.value) } }
69impl<V: Hash>           Hash        for Spanned<V> { fn hash<H: Hasher>(&self, hasher: &mut H) { self.value.hash(hasher) } }
70
71impl<'de, V: Deserialize<'de>> Deserialize<'de> for Spanned<V> {
72    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
73        let (start, start_ch)   = start().unwrap_or((0, '\0'));
74        let value               = V::deserialize(deserializer)?;
75        let end                 = end().unwrap_or(0);
76        let end                 = if "[{ntf\"".contains(start_ch) { end } else { end.saturating_sub(1) };
77        Ok(Self { start, end, value })
78    }
79}
80
81
82
83#[doc = "Owned, arbitrary json value + span information"                ] pub type Value    = Spanned<super::Value>;
84#[doc = "`null` + span information"                                     ] pub type Null     = Spanned<()>;
85#[doc = "`true` or `false` + span information"                          ] pub type Bool     = Spanned<bool>;
86#[doc = "Borrowed number like `123` + span information"                 ] pub type Num<'n>  = Spanned<&'n serde_json::Number>;
87#[doc = "Owned number like `123` + span information"                    ] pub type Number   = Spanned<serde_json::Number>;
88#[doc = "Borrowed string like `\"abc\"` + span information"             ] pub type Str<'s>  = Spanned<&'s str>;
89#[doc = "Owned string like `\"abc\"` + span information"                ] pub type String   = Spanned<std::string::String>;
90#[doc = "Borrowed object like `{\"a\":1, \"b\":2}` + span information"  ] pub type Obj<'o>  = Spanned<&'o super::Map<self::String, self::Value>>;
91#[doc = "Owned object like `{\"a\":1, \"b\":2}` + span information"     ] pub type Object   = Spanned<super::Map<self::String, self::Value>>;
92#[doc = "Borrowed array like `[1,2,3]` + span information"              ] pub type Span<'s> = Spanned<&'s [self::Value]>;
93#[doc = "Owned array like `[1,2,3]` + span information"                 ] pub type Array    = Spanned<Vec<self::Value>>;
94
95/// Various conversion methods:
96///
97/// * `as_span_[type]()` returns borrowing `Option`s of some sort.
98/// * `into_span_[type]()` returns `Ok(type)` or `Err(original)`.
99///
100/// See also on [super::Value] as provided by `Deref` implementation:
101///
102/// * `is_[type]()` returns bools with obvious meanings.
103/// * `as_[type]()` for borrowing `Option`s without span info.
104/// * `into_[type]()` for `Ok(type)` without span info, or `Err(original)`.
105impl Value {
106    #[doc="`Some(span + ()) if self is `null`"                                     ] pub fn as_span_null    (&self) -> Option<Null>    { match  self.value { super::Value::Null      => Some(Spanned { start: self.start, end: self.end, value: () }), _ => None } }
107    #[doc="`Some(span + inner)` if self is `true` or `false`"                      ] pub fn as_span_bool    (&self) -> Option<Bool>    { match  self.value { super::Value::Bool(v)   => Some(Spanned { start: self.start, end: self.end, value: v  }), _ => None } }
108    #[doc="`Some(span + &inner)` if self is a number like `123`"                   ] pub fn as_span_number  (&self) -> Option<Num>     { match &self.value { super::Value::Number(v) => Some(Spanned { start: self.start, end: self.end, value: &v }), _ => None } }
109    #[doc="`Some(span + &inner)` if self is a string like `\"asdf\"`"              ] pub fn as_span_string  (&self) -> Option<Str>     { match &self.value { super::Value::String(v) => Some(Spanned { start: self.start, end: self.end, value: &v }), _ => None } }
110    #[doc="`Some(span + &inner)` if self is an array like `[1, 2, 3]`"             ] pub fn as_span_array   (&self) -> Option<Span>    { match &self.value { super::Value::Array(v)  => Some(Spanned { start: self.start, end: self.end, value: v  }), _ => None } }
111    #[doc="`Some(span + &inner)` if self is an object like `{\"a\": 1, \"b\": 2}`" ] pub fn as_span_object  (&self) -> Option<Obj>     { match &self.value { super::Value::Object(v) => Some(Spanned { start: self.start, end: self.end, value: v  }), _ => None } }
112
113    // TODO: as_span_*_mut ?  how would that even work?
114
115    #[doc="`Ok(span + ())` if self is `null`, otherwise Err(self)"                                      ] pub fn into_span_null     (self) -> Result<Null,     Self> { let Self { start, end, value } = self; match value { super::Value::Null      => Ok(Spanned { start, end, value: () }), value => Err(Spanned { start, end, value }) } }
116    #[doc="`Ok(span + inner)` if self is `true` or `false`, otherwise Err(self)"                        ] pub fn into_span_bool     (self) -> Result<Bool,     Self> { let Self { start, end, value } = self; match value { super::Value::Bool(v)   => Ok(Spanned { start, end, value: v  }), value => Err(Spanned { start, end, value }) } }
117    #[doc="`Ok(span + inner)` if self is a number like `123`, otherwise Err(self)"                      ] pub fn into_span_number   (self) -> Result<Number,   Self> { let Self { start, end, value } = self; match value { super::Value::Number(v) => Ok(Spanned { start, end, value: v  }), value => Err(Spanned { start, end, value }) } }
118    #[doc="`Ok(span + inner)` if self is a string like `\"asdf\"`, otherwise Err(self)"                 ] pub fn into_span_string   (self) -> Result<String,   Self> { let Self { start, end, value } = self; match value { super::Value::String(v) => Ok(Spanned { start, end, value: v  }), value => Err(Spanned { start, end, value }) } }
119    #[doc="`Ok(span + inner)` if self is an array like `[1, 2, 3]`, otherwise Err(self)"                ] pub fn into_span_array    (self) -> Result<Array,    Self> { let Self { start, end, value } = self; match value { super::Value::Array(v)  => Ok(Spanned { start, end, value: v  }), value => Err(Spanned { start, end, value }) } }
120    #[doc="`Ok(span + inner)` if self is an object like `{\"a\": 1, \"b\": 2}`, otherwise Err(self)"    ] pub fn into_span_object   (self) -> Result<Object,   Self> { let Self { start, end, value } = self; match value { super::Value::Object(v) => Ok(Spanned { start, end, value: v  }), value => Err(Spanned { start, end, value }) } }
121
122    /// Lookup a value by JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901))
123    pub fn pointer(&self, path: &str) -> Option<&Value> {
124        if path == "" { return Some(self) }
125        if !path.starts_with("/") { return None }
126        let mut current = self;
127        let tokens = path.split('/').skip(1).map(|t| t.replace("~1", "/").replace("~0", "~"));
128        for token in tokens {
129            current = match &current.value {
130                super::Value::Object(o) => o.get(token.as_str())?,
131                super::Value::Array(a)  => a.get(token.parse::<usize>().ok()?)?,
132                _other                  => return None,
133            };
134        }
135        Some(current)
136    }
137
138    /// Lookup a value by JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901))
139    pub fn pointer_mut(&mut self, path: &str) -> Option<&mut Value> {
140        if path == "" { return Some(self) }
141        if !path.starts_with("/") { return None }
142        let mut current = self;
143        let tokens = path.split('/').skip(1).map(|t| t.replace("~1", "/").replace("~0", "~"));
144        for token in tokens {
145            current = match &mut current.value {
146                super::Value::Object(o) => o.get_mut(token.as_str())?,
147                super::Value::Array(a)  => a.get_mut(token.parse::<usize>().ok()?)?,
148                _other                  => return None,
149            };
150        }
151        Some(current)
152    }
153}
154
155#[cfg(test)] mod tests {
156    use crate::*;
157
158    #[test] fn pointer() {
159        let text = "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}";
160        let v : spanned::Value = from_str(text).unwrap();
161        assert_eq!(&text[v.pointer("").unwrap().range()],           "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}");
162        assert_eq!(&text[v.pointer("/a").unwrap().range()],         "{\"b\": [0, [0, 1, {\"c\": \"value\"}]]}");
163        assert_eq!(&text[v.pointer("/a/b").unwrap().range()],       "[0, [0, 1, {\"c\": \"value\"}]]");
164        assert_eq!(&text[v.pointer("/a/b/0").unwrap().range()],     "0");
165        assert_eq!(&text[v.pointer("/a/b/1").unwrap().range()],     "[0, 1, {\"c\": \"value\"}]");
166        assert_eq!(&text[v.pointer("/a/b/1/0").unwrap().range()],   "0");
167        assert_eq!(&text[v.pointer("/a/b/1/1").unwrap().range()],   "1");
168        assert_eq!(&text[v.pointer("/a/b/1/2").unwrap().range()],   "{\"c\": \"value\"}");
169        assert_eq!(&text[v.pointer("/a/b/1/2/c").unwrap().range()], "\"value\"");
170
171        assert!(         v.pointer("/a/b/1/2/d").is_none());
172        assert!(         v.pointer("/a/b/1/2/").is_none());
173        assert!(         v.pointer("/a/b/1/3").is_none());
174        assert!(         v.pointer("/a/b/1/").is_none());
175        assert!(         v.pointer("/a/b/2").is_none());
176        assert!(         v.pointer("/a/b/").is_none());
177        assert!(         v.pointer("/a/nope").is_none());
178        assert!(         v.pointer("/a/").is_none());
179        assert!(         v.pointer("/nope").is_none());
180        assert!(         v.pointer("/").is_none());
181    }
182
183    #[test] fn pointer_mut() {
184        let text = "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}";
185        let mut v : spanned::Value = from_str(text).unwrap();
186        assert_eq!(&text[v.pointer_mut("").unwrap().range()],           "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}");
187        assert_eq!(&text[v.pointer_mut("/a").unwrap().range()],         "{\"b\": [0, [0, 1, {\"c\": \"value\"}]]}");
188        assert_eq!(&text[v.pointer_mut("/a/b").unwrap().range()],       "[0, [0, 1, {\"c\": \"value\"}]]");
189        assert_eq!(&text[v.pointer_mut("/a/b/0").unwrap().range()],     "0");
190        assert_eq!(&text[v.pointer_mut("/a/b/1").unwrap().range()],     "[0, 1, {\"c\": \"value\"}]");
191        assert_eq!(&text[v.pointer_mut("/a/b/1/0").unwrap().range()],   "0");
192        assert_eq!(&text[v.pointer_mut("/a/b/1/1").unwrap().range()],   "1");
193        assert_eq!(&text[v.pointer_mut("/a/b/1/2").unwrap().range()],   "{\"c\": \"value\"}");
194        assert_eq!(&text[v.pointer_mut("/a/b/1/2/c").unwrap().range()], "\"value\"");
195
196        assert!(         v.pointer_mut("/a/b/1/2/d").is_none());
197        assert!(         v.pointer_mut("/a/b/1/2/").is_none());
198        assert!(         v.pointer_mut("/a/b/1/3").is_none());
199        assert!(         v.pointer_mut("/a/b/1/").is_none());
200        assert!(         v.pointer_mut("/a/b/2").is_none());
201        assert!(         v.pointer_mut("/a/b/").is_none());
202        assert!(         v.pointer_mut("/a/nope").is_none());
203        assert!(         v.pointer_mut("/a/").is_none());
204        assert!(         v.pointer_mut("/nope").is_none());
205        assert!(         v.pointer_mut("/").is_none());
206    }
207}