1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! [Spanned] and aliases thereof -

//! spanned::{[Value], [Null], [Bool],

//! [Num]\[[ber](Number)\],

//! [Str]\[[ing](String)\],

//! [Obj]\[[ect](Object)\],

//! [Span], [Array]}


use super::{start, end};

use serde::de::*;

use std::borrow::Borrow;
use std::cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use std::convert::*;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, Range};



/// A value with start/end position information.

/// Can wrap arbitrary [Deserialize]able JSON values, not just basic JSON types.

#[derive(Clone)]
pub struct Spanned<V> {
    pub(crate) start:  usize,
    pub(crate) end:    usize,
    pub(crate) value:  V,
}

impl<V> Spanned<V> {
    /// Get the starting byte offset (inclusive) of this value.

    /// Likely `0` unless loaded through [crate::from_*](crate::from_slice).

    pub fn start(&self) -> usize { self.start }

    /// Get the ending byte offset (non-inclusive) of this value.

    /// Likely `0` unless loaded through [crate::from_*](crate::from_slice).

    pub fn end(&self) -> usize { self.end }

    /// Get the start .. end byte offset of this value as a (start, end) tuple.

    /// Likely `(0, 0)` unless loaded through [crate::from_*](crate::from_slice).

    pub fn span(&self) -> (usize, usize) { (self.start, self.end) }

    /// Get the start .. end byte offset of this value as a start .. end [Range].

    /// Likely `0 .. 0` unless loaded through [crate::from_*](crate::from_slice).

    pub fn range(&self) -> Range<usize> { self.start .. self.end }

    /// Get the interior value of the spanned region as an owned value.

    pub fn into_inner(self) -> V { self.value }

    /// Get the interior value of the spanned region as a reference.

    pub fn get_ref(&self) -> &V { &self.value }

    /// Get the interior value of the spanned region as a mutable/exclusive reference.

    pub fn get_mut(&mut self) -> &mut V { &mut self.value }
}

impl                    Borrow<str> for Str<'_>    { fn borrow(&self) -> &str { self.get_ref() } }
impl                    Borrow<str> for String     { fn borrow(&self) -> &str { self.get_ref() } }
impl<V>                 Deref       for Spanned<V> { fn deref(&self) -> &Self::Target { &self.value } type Target = V; }
//impl<V>               DerefMut    for Spanned<V> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } }

impl<R, V: AsRef<R>>    AsRef<R>    for Spanned<V> { fn as_ref(&self) -> &R { self.value.as_ref() } }
impl<V: Debug>          Debug       for Spanned<V> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { self.value.fmt(fmt) } }
impl<V: Display>        Display     for Spanned<V> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { self.value.fmt(fmt) } }
impl<V>                 From<V>     for Spanned<V> { fn from(v: V) -> Self { Self { value: v, start: 0, end: 0 } } }
impl<V: Eq>             Eq          for Spanned<V> {}
impl<V: Ord>            Ord         for Spanned<V> { fn cmp(&self, other: &Self) -> Ordering { self.value.cmp(&other.value) } }
impl<V: PartialEq>      PartialEq   for Spanned<V> { fn eq(&self, other: &Self) -> bool { self.value.eq(&other.value) } }
impl<V: PartialOrd>     PartialOrd  for Spanned<V> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.value.partial_cmp(&other.value) } }
impl<V: Hash>           Hash        for Spanned<V> { fn hash<H: Hasher>(&self, hasher: &mut H) { self.value.hash(hasher) } }

impl<'de, V: Deserialize<'de>> Deserialize<'de> for Spanned<V> {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (start, start_ch)   = start().unwrap_or((0, '\0'));
        let value               = V::deserialize(deserializer)?;
        let end                 = end().unwrap_or(0);
        let end                 = if "[{ntf\"".contains(start_ch) { end } else { end.saturating_sub(1) };
        Ok(Self { start, end, value })
    }
}



#[doc = "Owned, arbitrary json value + span information"                ] pub type Value    = Spanned<super::Value>;
#[doc = "`null` + span information"                                     ] pub type Null     = Spanned<()>;
#[doc = "`true` or `false` + span information"                          ] pub type Bool     = Spanned<bool>;
#[doc = "Borrowed number like `123` + span information"                 ] pub type Num<'n>  = Spanned<&'n serde_json::Number>;
#[doc = "Owned number like `123` + span information"                    ] pub type Number   = Spanned<serde_json::Number>;
#[doc = "Borrowed string like `\"abc\"` + span information"             ] pub type Str<'s>  = Spanned<&'s str>;
#[doc = "Owned string like `\"abc\"` + span information"                ] pub type String   = Spanned<std::string::String>;
#[doc = "Borrowed object like `{\"a\":1, \"b\":2}` + span information"  ] pub type Obj<'o>  = Spanned<&'o super::Map<self::String, self::Value>>;
#[doc = "Owned object like `{\"a\":1, \"b\":2}` + span information"     ] pub type Object   = Spanned<super::Map<self::String, self::Value>>;
#[doc = "Borrowed array like `[1,2,3]` + span information"              ] pub type Span<'s> = Spanned<&'s [self::Value]>;
#[doc = "Owned array like `[1,2,3]` + span information"                 ] pub type Array    = Spanned<Vec<self::Value>>;

/// Various conversion methods:

///

/// * `as_span_[type]()` returns borrowing `Option`s of some sort.

/// * `into_span_[type]()` returns `Ok(type)` or `Err(original)`.

///

/// See also on [super::Value] as provided by `Deref` implementation:

///

/// * `is_[type]()` returns bools with obvious meanings.

/// * `as_[type]()` for borrowing `Option`s without span info.

/// * `into_[type]()` for `Ok(type)` without span info, or `Err(original)`.

impl Value {
    #[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 } }
    #[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 } }
    #[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 } }
    #[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 } }
    #[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 } }
    #[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 } }

    // TODO: as_span_*_mut ?  how would that even work?


    #[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 }) } }
    #[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 }) } }
    #[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 }) } }
    #[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 }) } }
    #[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 }) } }
    #[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 }) } }

    /// Lookup a value by JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901))

    pub fn pointer(&self, path: &str) -> Option<&Value> {
        if path == "" { return Some(self) }
        if !path.starts_with("/") { return None }
        let mut current = self;
        let tokens = path.split('/').skip(1).map(|t| t.replace("~1", "/").replace("~0", "~"));
        for token in tokens {
            current = match &current.value {
                super::Value::Object(o) => o.get(token.as_str())?,
                super::Value::Array(a)  => a.get(token.parse::<usize>().ok()?)?,
                _other                  => return None,
            };
        }
        Some(current)
    }

    /// Lookup a value by JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901))

    pub fn pointer_mut(&mut self, path: &str) -> Option<&mut Value> {
        if path == "" { return Some(self) }
        if !path.starts_with("/") { return None }
        let mut current = self;
        let tokens = path.split('/').skip(1).map(|t| t.replace("~1", "/").replace("~0", "~"));
        for token in tokens {
            current = match &mut current.value {
                super::Value::Object(o) => o.get_mut(token.as_str())?,
                super::Value::Array(a)  => a.get_mut(token.parse::<usize>().ok()?)?,
                _other                  => return None,
            };
        }
        Some(current)
    }
}

#[cfg(test)] mod tests {
    use crate::*;

    #[test] fn pointer() {
        let text = "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}";
        let v : spanned::Value = from_str(text).unwrap();
        assert_eq!(&text[v.pointer("").unwrap().range()],           "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}");
        assert_eq!(&text[v.pointer("/a").unwrap().range()],         "{\"b\": [0, [0, 1, {\"c\": \"value\"}]]}");
        assert_eq!(&text[v.pointer("/a/b").unwrap().range()],       "[0, [0, 1, {\"c\": \"value\"}]]");
        assert_eq!(&text[v.pointer("/a/b/0").unwrap().range()],     "0");
        assert_eq!(&text[v.pointer("/a/b/1").unwrap().range()],     "[0, 1, {\"c\": \"value\"}]");
        assert_eq!(&text[v.pointer("/a/b/1/0").unwrap().range()],   "0");
        assert_eq!(&text[v.pointer("/a/b/1/1").unwrap().range()],   "1");
        assert_eq!(&text[v.pointer("/a/b/1/2").unwrap().range()],   "{\"c\": \"value\"}");
        assert_eq!(&text[v.pointer("/a/b/1/2/c").unwrap().range()], "\"value\"");

        assert!(         v.pointer("/a/b/1/2/d").is_none());
        assert!(         v.pointer("/a/b/1/2/").is_none());
        assert!(         v.pointer("/a/b/1/3").is_none());
        assert!(         v.pointer("/a/b/1/").is_none());
        assert!(         v.pointer("/a/b/2").is_none());
        assert!(         v.pointer("/a/b/").is_none());
        assert!(         v.pointer("/a/nope").is_none());
        assert!(         v.pointer("/a/").is_none());
        assert!(         v.pointer("/nope").is_none());
        assert!(         v.pointer("/").is_none());
    }

    #[test] fn pointer_mut() {
        let text = "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}";
        let mut v : spanned::Value = from_str(text).unwrap();
        assert_eq!(&text[v.pointer_mut("").unwrap().range()],           "{\"a\": {\"b\": [0, [0, 1, {\"c\": \"value\"}]]}}");
        assert_eq!(&text[v.pointer_mut("/a").unwrap().range()],         "{\"b\": [0, [0, 1, {\"c\": \"value\"}]]}");
        assert_eq!(&text[v.pointer_mut("/a/b").unwrap().range()],       "[0, [0, 1, {\"c\": \"value\"}]]");
        assert_eq!(&text[v.pointer_mut("/a/b/0").unwrap().range()],     "0");
        assert_eq!(&text[v.pointer_mut("/a/b/1").unwrap().range()],     "[0, 1, {\"c\": \"value\"}]");
        assert_eq!(&text[v.pointer_mut("/a/b/1/0").unwrap().range()],   "0");
        assert_eq!(&text[v.pointer_mut("/a/b/1/1").unwrap().range()],   "1");
        assert_eq!(&text[v.pointer_mut("/a/b/1/2").unwrap().range()],   "{\"c\": \"value\"}");
        assert_eq!(&text[v.pointer_mut("/a/b/1/2/c").unwrap().range()], "\"value\"");

        assert!(         v.pointer_mut("/a/b/1/2/d").is_none());
        assert!(         v.pointer_mut("/a/b/1/2/").is_none());
        assert!(         v.pointer_mut("/a/b/1/3").is_none());
        assert!(         v.pointer_mut("/a/b/1/").is_none());
        assert!(         v.pointer_mut("/a/b/2").is_none());
        assert!(         v.pointer_mut("/a/b/").is_none());
        assert!(         v.pointer_mut("/a/nope").is_none());
        assert!(         v.pointer_mut("/a/").is_none());
        assert!(         v.pointer_mut("/nope").is_none());
        assert!(         v.pointer_mut("/").is_none());
    }
}