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};
#[derive(Clone)]
pub struct Spanned<V> {
pub(crate) start: usize,
pub(crate) end: usize,
pub(crate) value: V,
}
impl<V> Spanned<V> {
pub fn start(&self) -> usize { self.start }
pub fn end(&self) -> usize { self.end }
pub fn span(&self) -> (usize, usize) { (self.start, self.end) }
pub fn range(&self) -> Range<usize> { self.start .. self.end }
pub fn into_inner(self) -> V { self.value }
pub fn get_ref(&self) -> &V { &self.value }
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<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>>;
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 } }
#[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 }) } }
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 ¤t.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)
}
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());
}
}