Skip to main content

yaml_rt_serde/value/
index.rs

1use std::fmt;
2use std::ops;
3
4use super::{Mapping, Number, Value};
5
6mod private {
7    pub trait Sealed {}
8
9    impl Sealed for usize {}
10    impl Sealed for str {}
11    impl Sealed for String {}
12    impl Sealed for super::Value {}
13    impl<T> Sealed for &T where T: ?Sized + Sealed {}
14}
15
16/// A sealed type that can index a YAML [`Value`] or [`Mapping`].
17pub trait Index: private::Sealed {
18    #[doc(hidden)]
19    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value>;
20
21    #[doc(hidden)]
22    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value>;
23
24    #[doc(hidden)]
25    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value;
26
27    #[doc(hidden)]
28    fn mapping_position(&self, mapping: &Mapping) -> Option<usize>;
29}
30
31impl Index for usize {
32    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value> {
33        match value.untag_ref() {
34            Value::Sequence(sequence) => sequence.get(*self),
35            Value::Mapping(mapping) => mapping.get(Value::Number(Number::from(*self))),
36            _ => None,
37        }
38    }
39
40    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
41        match value.untag_mut() {
42            Value::Sequence(sequence) => sequence.get_mut(*self),
43            Value::Mapping(mapping) => mapping.get_mut(Value::Number(Number::from(*self))),
44            _ => None,
45        }
46    }
47
48    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value {
49        match value.untag_mut() {
50            Value::Sequence(sequence) => {
51                let len = sequence.len();
52                sequence.get_mut(*self).unwrap_or_else(|| {
53                    panic!("cannot access index {self} of YAML sequence of length {len}")
54                })
55            }
56            Value::Mapping(mapping) => mapping
57                .entry(Value::Number(Number::from(*self)))
58                .or_insert(Value::Null),
59            value => panic!("cannot access index {self} of YAML {}", Type(value)),
60        }
61    }
62
63    fn mapping_position(&self, mapping: &Mapping) -> Option<usize> {
64        mapping.position(&Value::Number(Number::from(*self)))
65    }
66}
67
68impl Index for Value {
69    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value> {
70        match value.untag_ref() {
71            Value::Mapping(mapping) => mapping.get(self),
72            _ => None,
73        }
74    }
75
76    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
77        match value.untag_mut() {
78            Value::Mapping(mapping) => mapping.get_mut(self),
79            _ => None,
80        }
81    }
82
83    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value {
84        if matches!(value, Value::Null) {
85            *value = Value::Mapping(Mapping::new());
86        }
87        match value.untag_mut() {
88            Value::Mapping(mapping) => mapping.entry(self.clone()).or_insert(Value::Null),
89            value => panic!("cannot access key {self:?} in YAML {}", Type(value)),
90        }
91    }
92
93    fn mapping_position(&self, mapping: &Mapping) -> Option<usize> {
94        mapping.position(self)
95    }
96}
97
98impl Index for str {
99    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value> {
100        match value.untag_ref() {
101            Value::Mapping(mapping) => mapping.get(self),
102            _ => None,
103        }
104    }
105
106    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
107        match value.untag_mut() {
108            Value::Mapping(mapping) => mapping.get_mut(self),
109            _ => None,
110        }
111    }
112
113    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value {
114        if matches!(value, Value::Null) {
115            *value = Value::Mapping(Mapping::new());
116        }
117        match value.untag_mut() {
118            Value::Mapping(mapping) => mapping
119                .entry(Value::String(self.to_owned()))
120                .or_insert(Value::Null),
121            value => panic!("cannot access key {self:?} in YAML {}", Type(value)),
122        }
123    }
124
125    fn mapping_position(&self, mapping: &Mapping) -> Option<usize> {
126        mapping
127            .entries
128            .iter()
129            .position(|(key, _)| matches!(key.untag_ref(), Value::String(key) if key == self))
130    }
131}
132
133impl Index for String {
134    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value> {
135        self.as_str().index_into(value)
136    }
137
138    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
139        self.as_str().index_into_mut(value)
140    }
141
142    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value {
143        self.as_str().index_or_insert(value)
144    }
145
146    fn mapping_position(&self, mapping: &Mapping) -> Option<usize> {
147        self.as_str().mapping_position(mapping)
148    }
149}
150
151impl<T> Index for &T
152where
153    T: ?Sized + Index,
154{
155    fn index_into<'a>(&self, value: &'a Value) -> Option<&'a Value> {
156        (**self).index_into(value)
157    }
158
159    fn index_into_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
160        (**self).index_into_mut(value)
161    }
162
163    fn index_or_insert<'a>(&self, value: &'a mut Value) -> &'a mut Value {
164        (**self).index_or_insert(value)
165    }
166
167    fn mapping_position(&self, mapping: &Mapping) -> Option<usize> {
168        (**self).mapping_position(mapping)
169    }
170}
171
172struct Type<'a>(&'a Value);
173
174impl fmt::Display for Type<'_> {
175    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
176        formatter.write_str(match self.0 {
177            Value::Null => "null",
178            Value::Bool(_) => "boolean",
179            Value::Number(_) => "number",
180            Value::String(_) => "string",
181            Value::Sequence(_) => "sequence",
182            Value::Mapping(_) => "mapping",
183            Value::Tagged(_) => "tagged value",
184        })
185    }
186}
187
188impl<I> ops::Index<I> for Value
189where
190    I: Index,
191{
192    type Output = Value;
193
194    fn index(&self, index: I) -> &Self::Output {
195        static NULL: Value = Value::Null;
196        index.index_into(self).unwrap_or(&NULL)
197    }
198}
199
200impl<I> ops::IndexMut<I> for Value
201where
202    I: Index,
203{
204    fn index_mut(&mut self, index: I) -> &mut Self::Output {
205        index.index_or_insert(self)
206    }
207}