mybatis_sql/
ops_index.rs

1use crate::ops::{OpsIndex, OpsIndexMut, Value};
2use rbson::Document;
3
4pub trait Index: private::Sealed {
5    /// Return None if the key is not already in the array or object.
6    #[doc(hidden)]
7    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>;
8
9    /// Return None if the key is not already in the array or object.
10    #[doc(hidden)]
11    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>;
12
13    /// Panic if array index out of bounds. If key is not already in the object,
14    /// insert it with a value of null. Panic if Value is a type that cannot be
15    /// indexed into, except if Value is null then it can be treated as an empty
16    /// object.
17    #[doc(hidden)]
18    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value;
19}
20
21impl Index for usize {
22    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
23        match *v {
24            Value::Array(ref vec) => vec.get(*self),
25            _ => None,
26        }
27    }
28    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
29        match *v {
30            Value::Array(ref mut vec) => vec.get_mut(*self),
31            _ => None,
32        }
33    }
34    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
35        match *v {
36            Value::Array(ref mut vec) => {
37                let len = vec.len();
38                vec.get_mut(*self).unwrap_or_else(|| {
39                    panic!(
40                        "cannot access index {} of JSON array of length {}",
41                        self, len
42                    )
43                })
44            }
45            _ => panic!("cannot access index {} of JSON {}", self, Type(v)),
46        }
47    }
48}
49
50impl Index for str {
51    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
52        match *v {
53            Value::Document(ref map) => map.get(self),
54            _ => None,
55        }
56    }
57    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
58        match *v {
59            Value::Document(ref mut map) => map.get_mut(self),
60            _ => None,
61        }
62    }
63    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
64        if let Value::Null = *v {
65            *v = Value::Document(Document::new());
66        }
67        match *v {
68            Value::Document(ref mut map) => map.entry(self.to_owned()).or_insert(Value::Null),
69            _ => panic!("cannot access key {:?} in JSON {}", self, Type(v)),
70        }
71    }
72}
73
74impl Index for String {
75    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
76        self[..].index_into(v)
77    }
78    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
79        self[..].index_into_mut(v)
80    }
81    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
82        self[..].index_or_insert(v)
83    }
84}
85
86impl<'a, T> Index for &'a T
87where
88    T: ?Sized + Index,
89{
90    fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> {
91        (**self).index_into(v)
92    }
93    fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> {
94        (**self).index_into_mut(v)
95    }
96    fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value {
97        (**self).index_or_insert(v)
98    }
99}
100
101// Prevent users from implementing the Index trait.
102mod private {
103    pub trait Sealed {}
104    impl Sealed for usize {}
105    impl Sealed for str {}
106    impl Sealed for String {}
107    impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {}
108}
109
110/// Used in panic messages.
111struct Type<'a>(&'a Value);
112
113impl<'a> std::fmt::Display for Type<'a> {
114    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
115        match *self.0 {
116            Value::Null => formatter.write_str("Null"),
117            Value::Boolean(_) => formatter.write_str("Boolean"),
118            Value::Int32(_) => formatter.write_str("Int32"),
119            Value::Int64(_) => formatter.write_str("Int64"),
120            Value::Double(_) => formatter.write_str("Double"),
121            Value::String(_) => formatter.write_str("String"),
122            Value::Array(_) => formatter.write_str("Array"),
123            Value::Document(_) => formatter.write_str("Document"),
124            _ => formatter.write_str("Other"),
125        }
126    }
127}
128
129// The usual semantics of Index is to panic on invalid indexing.
130//
131// That said, the usual semantics are for things like Vec and BTreeMap which
132// have different use cases than Value. If you are working with a Vec, you know
133// that you are working with a Vec and you can get the len of the Vec and make
134// sure your indices are within bounds. The Value use cases are more
135// loosey-goosey. You got some JSON from an endpoint and you want to pull values
136// out of it. Outside of this Index impl, you already have the option of using
137// value.as_array() and working with the Vec directly, or matching on
138// Value::Array and getting the Vec directly. The Index impl means you can skip
139// that and index directly into the thing using a concise syntax. You don't have
140// to check the type, you don't have to check the len, it is all about what you
141// expect the Value to look like.
142//
143// Basically the use cases that would be well served by panicking here are
144// better served by using one of the other approaches: get and get_mut,
145// as_array, or match. The value of this impl is that it adds a way of working
146// with Value that is not well served by the existing approaches: concise and
147// careless and sometimes that is exactly what you want.
148impl<I> OpsIndex<I> for Value
149where
150    I: Index,
151{
152    type Output = Value;
153
154    fn index(&self, index: I) -> &Value {
155        static NULL: Value = Value::Null;
156        index.index_into(self).unwrap_or(&NULL)
157    }
158}
159
160impl<I> OpsIndexMut<I> for Value
161where
162    I: Index,
163{
164    fn index_mut(&mut self, index: I) -> &mut Value {
165        index.index_or_insert(self)
166    }
167}