tower_sesh/value/index.rs
1// Adapted from https://github.com/serde-rs/json.
2
3use std::{fmt, ops};
4
5use super::{Map, Value};
6
7/// A type that can be used to index into a [`Value`].
8///
9/// The [`get`] and [`get_mut`] methods of `Value` accept any type that
10/// implements `Index`, as does the [square-bracket indexing operator]. This
11/// trait is implemented for strings which are used as the index into a map,
12/// and for `usize` which is used as the index into an array.
13///
14/// [`get`]: Value::get
15/// [`get_mut`]: Value::get_mut
16/// [square-bracket indexing operator]: Value#impl-Index<Idx>-for-Value
17///
18/// This trait is sealed and cannot be implemented for types outside of
19/// `tower_sesh`.
20///
21/// # Examples
22///
23/// ```
24/// # use tower_sesh::Value;
25/// #
26/// let value = Value::from_iter([("inner", [1, 2, 3])]);
27///
28/// // Data is a map so it can be indexed with a string.
29/// let inner = &value["inner"];
30///
31/// // Inner is an array so it can be indexed with an integer.
32/// let first = &inner[0];
33///
34/// assert_eq!(first, 1);
35/// ```
36pub trait Index: private::Sealed {
37 /// Return `None` if the key is not already in the array or map.
38 #[doc(hidden)]
39 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
40
41 /// Return `None` if the key is not already in the array or map.
42 #[doc(hidden)]
43 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
44
45 /// Panic if array index is out of bounds. If key is not already in the
46 /// map, insert it with a value of `Null`. Panic if `Value` is a type that
47 /// cannot be indexed into, except if `Value` is `Null` then it can be
48 /// treated as an empty map.
49 #[doc(hidden)]
50 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
51}
52
53impl Index for usize {
54 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
55 match v {
56 Value::Array(vec) => vec.get(*self),
57 _ => None,
58 }
59 }
60
61 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
62 match v {
63 Value::Array(vec) => vec.get_mut(*self),
64 _ => None,
65 }
66 }
67
68 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
69 match v {
70 Value::Array(vec) => {
71 let len = vec.len();
72 vec.get_mut(*self).unwrap_or_else(|| {
73 panic!(
74 "array index out of bounds: the len is {} but the index is {}",
75 len, self
76 )
77 })
78 }
79 _ => panic!("invalid index into non-array variant {}", Type(v)),
80 }
81 }
82}
83impl private::Sealed for usize {}
84
85impl Index for str {
86 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
87 match v {
88 Value::Map(map) => map.get(self),
89 _ => None,
90 }
91 }
92
93 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
94 match v {
95 Value::Map(map) => map.get_mut(self),
96 _ => None,
97 }
98 }
99
100 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
101 if let Value::Null = v {
102 *v = Value::Map(Map::new());
103 }
104 match v {
105 Value::Map(map) => map.entry(self.to_owned()).or_insert(Value::Null),
106 _ => panic!("invalid index into non-map variant {}", Type(v)),
107 }
108 }
109}
110impl private::Sealed for str {}
111
112impl Index for String {
113 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
114 self[..].index_into(v)
115 }
116
117 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
118 self[..].index_into_mut(v)
119 }
120
121 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
122 self[..].index_or_insert(v)
123 }
124}
125impl private::Sealed for String {}
126
127impl<T> Index for &T
128where
129 T: ?Sized + Index,
130{
131 fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
132 (**self).index_into(v)
133 }
134
135 fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
136 (**self).index_into_mut(v)
137 }
138
139 fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
140 (**self).index_or_insert(v)
141 }
142}
143impl<T> private::Sealed for &T where T: ?Sized + Index {}
144
145mod private {
146 pub trait Sealed {}
147}
148
149/// Used in panic messages.
150struct Type<'a>(&'a Value);
151
152impl fmt::Display for Type<'_> {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 match *self.0 {
155 Value::Null => f.write_str("Null"),
156 Value::Bool(_) => f.write_str("Bool"),
157 Value::Number(_) => f.write_str("Number"),
158 Value::String(_) => f.write_str("String"),
159 Value::ByteArray(_) => f.write_str("ByteArray"),
160 Value::Array(_) => f.write_str("Array"),
161 Value::Map(_) => f.write_str("Map"),
162 }
163 }
164}
165
166impl<Idx> ops::Index<Idx> for Value
167where
168 Idx: Index,
169{
170 type Output = Value;
171
172 /// Index into a `Value` using the syntax `value[0]` or `value["k"]`.
173 ///
174 /// Returns `Value::Null` if the type of `self` does not match the type of
175 /// the index, for example if the index is a string and `self` is an array
176 /// or a number. Also returns `Value::Null` if the given key does not exist
177 /// in the map or the given index is not within the bounds of the array.
178 ///
179 /// # Examples
180 ///
181 /// ```
182 /// # use tower_sesh::Value;
183 /// #
184 /// let value = Value::from_iter([
185 /// ("x", Value::from_iter([
186 /// ("y", ["z", "zz"]),
187 /// ])),
188 /// ]);
189 ///
190 /// assert_eq!(value["x"]["y"], Value::from(["z", "zz"]));
191 /// assert_eq!(value["x"]["y"][0], Value::from("z"));
192 ///
193 /// assert_eq!(value["a"], Value::Null); // returns null for undefined values
194 /// assert_eq!(value["a"]["b"], Value::Null); // does not panic
195 /// ```
196 fn index(&self, index: Idx) -> &Self::Output {
197 static NULL: Value = Value::Null;
198 index.index_into(self).unwrap_or(&NULL)
199 }
200}
201
202impl<Idx> ops::IndexMut<Idx> for Value
203where
204 Idx: Index,
205{
206 /// Write into a `Value` using the syntax `value[0] = ...` or
207 /// `value["k"] = ...`.
208 ///
209 /// If the index is a number, the value must be an array of length bigger
210 /// than the index. Indexing into a value that is not an array or an array
211 /// that is too small will panic.
212 ///
213 /// If the index is a string, the value must be a map (or null which is
214 /// treated like an empty map). If the key is not already present in the
215 /// map, it will be inserted with a value of null. Indexing into a value
216 /// that is neither a map nor null will panic.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// # use tower_sesh::Value;
222 /// #
223 /// let mut value = Value::from_iter([("x", 0)]);
224 ///
225 /// // replace an existing key
226 /// value["x"] = Value::from(1);
227 ///
228 /// // insert a new key
229 /// value["y"] = Value::from([false, false, false]);
230 ///
231 /// // replace an array value
232 /// value["y"][0] = Value::from(true);
233 ///
234 /// // inserted a deeply nested key
235 /// value["a"]["b"]["c"]["d"] = Value::from(true);
236 ///
237 /// println!("{:?}", value);
238 /// ```
239 fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
240 index.index_or_insert(self)
241 }
242}