jmap_tools/pointer/
mod.rs1pub(crate) mod eval;
8pub(crate) mod parser;
9
10use std::{
11 borrow::Cow,
12 fmt::{Debug, Display, Formatter},
13 iter::Peekable,
14 slice::Iter,
15};
16
17use crate::{Element, Key, Property, Value};
18
19pub trait JsonPointerHandler<'x, P: Property, E: Element>: Debug {
20 fn eval_jptr<'y>(
21 &'y self,
22 pointer: JsonPointerIter<'_, P>,
23 results: &mut Vec<Cow<'y, Value<'x, P, E>>>,
24 );
25 fn patch_jptr<'y: 'x>(
26 &mut self,
27 pointer: JsonPointerIter<'_, P>,
28 value: Value<'y, P, E>,
29 ) -> bool;
30 fn to_value<'y>(&'y self) -> Cow<'y, Value<'x, P, E>>;
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34pub struct JsonPointer<P: Property>(pub(crate) Vec<JsonPointerItem<P>>);
35
36pub type JsonPointerIter<'x, P> = Peekable<Iter<'x, JsonPointerItem<P>>>;
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub enum JsonPointerItem<P: Property> {
40 Root,
41 Wildcard,
42 Key(Key<'static, P>),
43 Number(u64),
44}
45
46impl<P: Property> JsonPointer<P> {
47 pub fn iter(&self) -> JsonPointerIter<'_, P> {
48 self.0.iter().peekable()
49 }
50
51 #[allow(clippy::should_implement_trait)]
52 pub fn into_iter(self) -> impl Iterator<Item = JsonPointerItem<P>> {
53 self.0.into_iter()
54 }
55
56 pub fn into_inner(self) -> Vec<JsonPointerItem<P>> {
57 self.0
58 }
59
60 pub fn encode<I, T>(items: I) -> String
61 where
62 I: IntoIterator<Item = T>,
63 T: AsRef<str>,
64 {
65 let mut encoded = String::with_capacity(8);
66 for (pos, item) in items.into_iter().enumerate() {
67 if pos > 0 {
68 encoded.push('/');
69 }
70 let item = item.as_ref();
71 for c in item.chars() {
72 match c {
73 '~' => encoded.push_str("~0"),
74 '/' => encoded.push_str("~1"),
75 _ => encoded.push(c),
76 }
77 }
78 }
79 encoded
80 }
81
82 pub fn first(&self) -> Option<&JsonPointerItem<P>> {
83 self.0.first()
84 }
85
86 pub fn last(&self) -> Option<&JsonPointerItem<P>> {
87 self.0.last()
88 }
89
90 pub fn len(&self) -> usize {
91 self.0.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
95 self.0.is_empty()
96 }
97}
98
99impl<P: Property> JsonPointerItem<P> {
100 pub fn as_key(&self) -> Option<&Key<'static, P>> {
101 match self {
102 JsonPointerItem::Key(key) => Some(key),
103 _ => None,
104 }
105 }
106
107 pub fn as_property_key(&self) -> Option<&P> {
108 match self {
109 JsonPointerItem::Key(Key::Property(key)) => Some(key),
110 _ => None,
111 }
112 }
113
114 pub fn as_string_key(&self) -> Option<&str> {
115 match self {
116 JsonPointerItem::Key(Key::Borrowed(key)) => Some(key),
117 JsonPointerItem::Key(Key::Owned(key)) => Some(key),
118 _ => None,
119 }
120 }
121
122 pub fn to_cow(&self) -> Option<Cow<'_, str>> {
123 match self {
124 JsonPointerItem::Key(Key::Property(key)) => Some(key.to_cow()),
125 JsonPointerItem::Key(Key::Borrowed(key)) => Some(Cow::Borrowed(key)),
126 JsonPointerItem::Key(Key::Owned(key)) => Some(Cow::Borrowed(key)),
127 _ => None,
128 }
129 }
130}
131
132impl<P: Property> Display for JsonPointer<P> {
133 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134 for (i, ptr) in self.0.iter().enumerate() {
135 if i > 0 {
136 write!(f, "/")?;
137 }
138
139 match ptr {
140 JsonPointerItem::Root => {}
141 JsonPointerItem::Wildcard => write!(f, "*")?,
142 JsonPointerItem::Key(k) => {
143 for c in k.to_string().chars() {
144 match c {
145 '~' => write!(f, "~0")?,
146 '/' => write!(f, "~1")?,
147 _ => write!(f, "{}", c)?,
148 }
149 }
150 }
151 JsonPointerItem::Number(n) => write!(f, "{}", n)?,
152 }
153 }
154 Ok(())
155 }
156}