1use crate::parser::{parse, ParseError};
2use serde_json::Value;
3use std::fmt::{Display, Formatter};
4use std::fmt::Result as FmtResult;
5use std::fmt::Write;
6use std::marker::PhantomData;
7use std::ops::{Index, IndexMut};
8use std::str::FromStr;
9
10#[derive(Clone, Debug, Eq, PartialEq)]
15pub struct JsonPointer<S: AsRef<str>, C: AsRef<[S]>> {
16 ref_toks: C,
17 _phantom: PhantomData<S>,
18}
19
20impl<S: AsRef<str>, C: AsRef<[S]>> JsonPointer<S, C> {
21 pub fn new(ref_toks: C) -> JsonPointer<S, C> {
23 JsonPointer {
24 ref_toks: ref_toks,
25 _phantom: PhantomData,
26 }
27 }
28
29 pub fn get<'json>(&self, val: &'json Value) -> Result<&'json Value, IndexError> {
32 self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| {
33 let tok = tok.as_ref();
34 match *val {
35 Value::Object(ref obj) => obj.get(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())),
36 Value::Array(ref arr) => {
37 let idx = if tok == "-" {
38 arr.len()
39 } else if let Ok(idx) = tok.parse() {
40 idx
41 } else {
42 return Err(IndexError::NoSuchKey(tok.to_owned()));
43 };
44 arr.get(idx).ok_or(IndexError::OutOfBounds(idx))
45 },
46 _ => Err(IndexError::NotIndexable),
47 }
48 }))
49 }
50
51 pub fn get_mut<'json>(&self, val: &'json mut Value) -> Result<&'json mut Value, IndexError> {
54 self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| {
55 let tok = tok.as_ref();
56 match *val {
57 Value::Object(ref mut obj) => obj.get_mut(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())),
58 Value::Array(ref mut arr) => {
59 let idx = if tok == "-" {
60 arr.len()
61 } else if let Ok(idx) = tok.parse() {
62 idx
63 } else {
64 return Err(IndexError::NoSuchKey(tok.to_owned()));
65 };
66 arr.get_mut(idx).ok_or(IndexError::OutOfBounds(idx))
67 },
68 _ => Err(IndexError::NotIndexable),
69 }
70 }))
71 }
72
73 pub fn get_owned(&self, val: Value) -> Result<Value, IndexError> {
76 self.ref_toks.as_ref().iter().fold(Ok(val), |val, tok| val.and_then(|val| {
77 let tok = tok.as_ref();
78 match val {
79 Value::Object(mut obj) => obj.remove(tok).ok_or_else(|| IndexError::NoSuchKey(tok.to_owned())),
80 Value::Array(mut arr) => {
81 let idx = if tok == "-" {
82 arr.len()
83 } else if let Ok(idx) = tok.parse() {
84 idx
85 } else {
86 return Err(IndexError::NoSuchKey(tok.to_owned()));
87 };
88 if idx >= arr.len() {
89 Err(IndexError::OutOfBounds(idx))
90 } else {
91 Ok(arr.swap_remove(idx))
92 }
93 },
94 _ => Err(IndexError::NotIndexable),
95 }
96 }))
97 }
98
99 pub fn uri_fragment(&self) -> String {
102 fn legal_fragment_byte(b: u8) -> bool {
103 match b {
104 0x21 | 0x24 | 0x26..=0x3b | 0x3d | 0x3f..=0x5a | 0x5f | 0x61..=0x7a => true,
105 _ => false,
106 }
107 }
108
109 let mut s = "#".to_string();
110 for part in self.ref_toks.as_ref().iter() {
111 s += "/";
112 for b in part.as_ref().bytes() {
113 if legal_fragment_byte(b) {
114 s.push(b as char)
115 } else {
116 write!(s, "%{:02x}", b).unwrap()
117 }
118 }
119 }
120 s
121 }
122}
123
124impl<S: AsRef<str>> JsonPointer<S, Vec<S>> {
125 pub fn push(&mut self, component: S) {
127 self.ref_toks.push(component);
128 }
129
130 pub fn pop(&mut self) -> Option<S> {
132 self.ref_toks.pop()
133 }
134}
135
136impl<S: AsRef<str>, C: AsRef<[S]>> Display for JsonPointer<S, C> {
137 fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
138 for part in self.ref_toks.as_ref().iter() {
139 write!(fmt, "/")?;
140 for ch in part.as_ref().chars() {
141 match ch {
142 '~' => write!(fmt, "~0"),
143 '/' => write!(fmt, "~1"),
144 c => write!(fmt, "{}", c),
145 }?
146 }
147 }
148 Ok(())
149 }
150}
151
152impl FromStr for JsonPointer<String, Vec<String>> {
153 type Err = ParseError;
154 fn from_str(s: &str) -> Result<Self, Self::Err> {
155 parse(s)
156 }
157}
158
159#[derive(Clone, Debug, PartialEq)]
161pub enum IndexError {
162 NoSuchKey(String),
164 NotIndexable,
166 OutOfBounds(usize),
168}
169
170impl<'a, S: AsRef<str>, C: AsRef<[S]>> Index<&'a JsonPointer<S, C>> for Value {
171 type Output = Value;
172 fn index(&self, ptr: &'a JsonPointer<S, C>) -> &Value {
173 ptr.get(self).unwrap()
174 }
175}
176
177impl<'a, S: AsRef<str>, C: AsRef<[S]>> IndexMut<&'a JsonPointer<S, C>> for Value {
178 fn index_mut(&mut self, ptr: &'a JsonPointer<S, C>) -> &mut Value {
179 ptr.get_mut(self).unwrap()
180 }
181}