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}