datex_core/values/core_values/
map.rs

1use super::super::core_value_trait::CoreValueTrait;
2use crate::traits::structural_eq::StructuralEq;
3use crate::values::core_value::CoreValue;
4use crate::values::value::Value;
5use crate::values::value_container::ValueContainer;
6use indexmap::IndexMap;
7use std::collections::HashMap;
8use std::fmt::{self, Display};
9use std::hash::{Hash, Hasher};
10
11#[derive(Clone, Debug, Eq, PartialEq)]
12pub enum Map {
13    // most general case, allows all types of keys and values, and dynamic size
14    Dynamic(IndexMap<ValueContainer, ValueContainer>),
15    // for fixed-size maps with known keys and values on construction
16    Fixed(Vec<(ValueContainer, ValueContainer)>),
17    // for maps with string keys
18    Structural(Vec<(String, ValueContainer)>), // for structural maps with string keys
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub enum MapAccessError {
23    KeyNotFound,
24    Immutable,
25}
26
27impl Display for MapAccessError {
28    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29        match self {
30            MapAccessError::KeyNotFound => {
31                write!(f, "Key not found in fixed map")
32            }
33            MapAccessError::Immutable => {
34                write!(f, "Map is immutable")
35            }
36        }
37    }
38}
39
40impl Default for Map {
41    fn default() -> Self {
42        Map::Dynamic(IndexMap::new())
43    }
44}
45
46impl Map {
47    pub fn new(entries: IndexMap<ValueContainer, ValueContainer>) -> Self {
48        Map::Dynamic(entries)
49    }
50
51    pub fn is_structural(&self) -> bool {
52        matches!(self, Map::Structural(_))
53    }
54
55    pub fn has_fixed_size(&self) -> bool {
56        matches!(self, Map::Fixed(_) | Map::Structural(_))
57    }
58
59    pub fn size(&self) -> usize {
60        match self {
61            Map::Dynamic(map) => map.len(),
62            Map::Fixed(vec) => vec.len(),
63            Map::Structural(vec) => vec.len(),
64        }
65    }
66
67    pub fn is_empty(&self) -> bool {
68        self.size() == 0
69    }
70
71    /// Gets a value in the map by reference.
72    /// Returns None if the key is not found.
73    pub fn get(&self, key: &ValueContainer) -> Option<&ValueContainer> {
74        match self {
75            Map::Dynamic(map) => map.get(key),
76            Map::Fixed(vec) => {
77                vec.iter().find(|(k, _)| k == key).map(|(_, v)| v)
78            }
79            Map::Structural(vec) => {
80                // only works if key is a string
81                if let ValueContainer::Value(Value {
82                    inner: CoreValue::Text(text),
83                    ..
84                }) = key
85                {
86                    vec.iter().find(|(k, _)| k == &text.0).map(|(_, v)| v)
87                } else {
88                    None
89                }
90            }
91        }
92    }
93
94    /// Gets a value in the map, where the key is a string.
95    /// Returns None if the key is not found
96    pub fn get_text(&self, key: &str) -> Option<&ValueContainer> {
97        match self {
98            Map::Dynamic(map) => {
99                map.get(&ValueContainer::from(key.to_string()))
100            }
101            Map::Fixed(vec) => vec
102                .iter()
103                .find(|(k, _)| {
104                    if let ValueContainer::Value(Value {
105                        inner: CoreValue::Text(text),
106                        ..
107                    }) = k
108                    {
109                        text.0 == key
110                    } else {
111                        false
112                    }
113                })
114                .map(|(_, v)| v),
115            Map::Structural(vec) => {
116                vec.iter().find(|(k, _)| k == key).map(|(_, v)| v)
117            }
118        }
119    }
120
121    /// Checks if the map contains the given key.
122    pub fn has(&self, key: &ValueContainer) -> bool {
123        match self {
124            Map::Dynamic(map) => map.contains_key(key),
125            Map::Fixed(vec) => vec.iter().any(|(k, _)| k == key),
126            Map::Structural(vec) => {
127                // only works if key is a string
128                if let ValueContainer::Value(Value {
129                    inner: CoreValue::Text(text),
130                    ..
131                }) = key
132                {
133                    vec.iter().any(|(k, _)| k == &text.0)
134                } else {
135                    false
136                }
137            }
138        }
139    }
140
141    /// Removes a key from the map, returning the value if it existed.
142    pub fn remove(
143        &mut self,
144        key: &ValueContainer,
145    ) -> Result<ValueContainer, MapAccessError> {
146        match self {
147            Map::Dynamic(map) => {
148                map.shift_remove(key).ok_or(MapAccessError::KeyNotFound)
149            }
150            Map::Fixed(_) | Map::Structural(_) => {
151                Err(MapAccessError::Immutable)
152            }
153        }
154    }
155
156    /// Clears all entries in the map, returning an error if the map is not dynamic.
157    pub fn clear(&mut self) -> Result<(), MapAccessError> {
158        match self {
159            Map::Dynamic(map) => {
160                map.clear();
161                Ok(())
162            }
163            Map::Fixed(_) | Map::Structural(_) => {
164                Err(MapAccessError::Immutable)
165            }
166        }
167    }
168
169    /// Gets a value in the map, taking ownership of the key.
170    pub fn get_owned<T: Into<ValueContainer>>(
171        &self,
172        key: T,
173    ) -> Option<&ValueContainer> {
174        self.get(&key.into())
175    }
176
177    /// Sets a value in the map, panicking if it fails.
178    pub(crate) fn set<K: Into<ValueContainer>, V: Into<ValueContainer>>(
179        &mut self,
180        key: K,
181        value: V,
182    ) {
183        self.try_set(key, value)
184            .expect("Setting value in map failed");
185    }
186
187    /// Sets a value in the map, returning an error if it fails.
188    /// This is the preferred way to set values in the map.
189    pub(crate) fn try_set<K: Into<ValueContainer>, V: Into<ValueContainer>>(
190        &mut self,
191        key: K,
192        value: V,
193    ) -> Result<(), MapAccessError> {
194        match self {
195            Map::Dynamic(map) => {
196                map.insert(key.into(), value.into());
197                Ok(())
198            }
199            Map::Fixed(vec) => {
200                let key = key.into();
201                if let Some((_, v)) = vec.iter_mut().find(|(k, _)| k == &key) {
202                    *v = value.into();
203                    Ok(())
204                } else {
205                    Err(MapAccessError::KeyNotFound)
206                }
207            }
208            Map::Structural(vec) => {
209                let key = key.into();
210                if let ValueContainer::Value(Value {
211                    inner: CoreValue::Text(text),
212                    ..
213                }) = key
214                {
215                    if let Some((_, v)) =
216                        vec.iter_mut().find(|(k, _)| k == &text.0)
217                    {
218                        *v = value.into();
219                        Ok(())
220                    } else {
221                        Err(MapAccessError::KeyNotFound)
222                    }
223                } else {
224                    Err(MapAccessError::KeyNotFound)
225                }
226            }
227        }
228    }
229}
230
231pub enum MapKey<'a> {
232    Text(&'a str),
233    Value(&'a ValueContainer),
234}
235
236impl<'a> From<MapKey<'a>> for ValueContainer {
237    fn from(key: MapKey) -> Self {
238        match key {
239            MapKey::Text(text) => ValueContainer::Value(Value::from(text)),
240            MapKey::Value(value) => value.clone(),
241        }
242    }
243}
244
245impl Hash for MapKey<'_> {
246    fn hash<H: Hasher>(&self, state: &mut H) {
247        match self {
248            MapKey::Text(text) => text.hash(state),
249            MapKey::Value(value) => value.hash(state),
250        }
251    }
252}
253
254impl StructuralEq for MapKey<'_> {
255    fn structural_eq(&self, other: &Self) -> bool {
256        match (self, other) {
257            (MapKey::Text(a), MapKey::Text(b)) => a == b,
258            (MapKey::Value(a), MapKey::Value(b)) => a.structural_eq(b),
259            (MapKey::Text(a), MapKey::Value(b))
260            | (MapKey::Value(b), MapKey::Text(a)) => {
261                if let ValueContainer::Value(Value {
262                    inner: CoreValue::Text(text),
263                    ..
264                }) = b
265                {
266                    a == &text.0
267                } else {
268                    false
269                }
270            }
271        }
272    }
273}
274
275impl Display for MapKey<'_> {
276    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277        match self {
278            // TODO #331: escape string
279            MapKey::Text(string) => write!(f, "\"{}\"", string),
280            MapKey::Value(value) => write!(f, "{value}"),
281        }
282    }
283}
284
285pub enum OwnedMapKey {
286    Text(String),
287    Value(ValueContainer),
288}
289
290impl From<OwnedMapKey> for ValueContainer {
291    fn from(key: OwnedMapKey) -> Self {
292        match key {
293            OwnedMapKey::Text(text) => ValueContainer::Value(Value::from(text)),
294            OwnedMapKey::Value(value) => value,
295        }
296    }
297}
298
299impl Display for OwnedMapKey {
300    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
301        match self {
302            OwnedMapKey::Text(text) => write!(f, "{text}"),
303            OwnedMapKey::Value(value) => write!(f, "{value}"),
304        }
305    }
306}
307
308pub struct MapIterator<'a> {
309    map: &'a Map,
310    index: usize,
311}
312
313impl<'a> Iterator for MapIterator<'a> {
314    type Item = (MapKey<'a>, &'a ValueContainer);
315
316    fn next(&mut self) -> Option<Self::Item> {
317        match self.map {
318            Map::Dynamic(map) => {
319                let item = map.iter().nth(self.index);
320                self.index += 1;
321                item.map(|(k, v)| {
322                    let key = match k {
323                        ValueContainer::Value(Value {
324                            inner: CoreValue::Text(text),
325                            ..
326                        }) => MapKey::Text(&text.0),
327                        _ => MapKey::Value(k),
328                    };
329                    (key, v)
330                })
331            }
332            Map::Fixed(vec) => {
333                if self.index < vec.len() {
334                    let item = &vec[self.index];
335                    self.index += 1;
336                    let key = match &item.0 {
337                        ValueContainer::Value(Value {
338                            inner: CoreValue::Text(text),
339                            ..
340                        }) => MapKey::Text(&text.0),
341                        _ => MapKey::Value(&item.0),
342                    };
343                    Some((key, &item.1))
344                } else {
345                    None
346                }
347            }
348            Map::Structural(vec) => {
349                if self.index < vec.len() {
350                    let item = &vec[self.index];
351                    self.index += 1;
352                    Some((MapKey::Text(&item.0), &item.1))
353                } else {
354                    None
355                }
356            }
357        }
358    }
359}
360
361pub enum MapMutIterator<'a> {
362    Dynamic(indexmap::map::IterMut<'a, ValueContainer, ValueContainer>),
363    Fixed(std::slice::IterMut<'a, (ValueContainer, ValueContainer)>),
364    Structural(std::slice::IterMut<'a, (String, ValueContainer)>),
365}
366
367impl<'a> Iterator for MapMutIterator<'a> {
368    type Item = (MapKey<'a>, &'a mut ValueContainer);
369
370    fn next(&mut self) -> Option<Self::Item> {
371        match self {
372            MapMutIterator::Dynamic(iter) => iter.next().map(|(k, v)| {
373                let key = match k {
374                    ValueContainer::Value(Value {
375                        inner: CoreValue::Text(text),
376                        ..
377                    }) => MapKey::Text(&text.0),
378                    _ => MapKey::Value(k),
379                };
380                (key, v)
381            }),
382            MapMutIterator::Fixed(iter) => iter.next().map(|(k, v)| {
383                let key = match k {
384                    ValueContainer::Value(Value {
385                        inner: CoreValue::Text(text),
386                        ..
387                    }) => MapKey::Text(&text.0),
388                    _ => MapKey::Value(k),
389                };
390                (key, v)
391            }),
392            MapMutIterator::Structural(iter) => {
393                iter.next().map(|(k, v)| (MapKey::Text(k.as_str()), v))
394            }
395        }
396    }
397}
398
399pub struct IntoMapIterator {
400    map: Map,
401    index: usize,
402}
403
404impl Iterator for IntoMapIterator {
405    type Item = (OwnedMapKey, ValueContainer);
406
407    fn next(&mut self) -> Option<Self::Item> {
408        // TODO #332: optimize to avoid cloning keys and values
409        match &self.map {
410            Map::Dynamic(map) => {
411                let item = map.iter().nth(self.index);
412                self.index += 1;
413                item.map(|(k, v)| {
414                    let key = match k {
415                        ValueContainer::Value(Value {
416                            inner: CoreValue::Text(text),
417                            ..
418                        }) => OwnedMapKey::Text(text.0.clone()),
419                        _ => OwnedMapKey::Value(k.clone()),
420                    };
421                    (key, v.clone())
422                })
423            }
424            Map::Fixed(vec) => {
425                if self.index < vec.len() {
426                    let item = &vec[self.index];
427                    self.index += 1;
428                    let key = match &item.0 {
429                        ValueContainer::Value(Value {
430                            inner: CoreValue::Text(text),
431                            ..
432                        }) => OwnedMapKey::Text(text.0.clone()),
433                        _ => OwnedMapKey::Value(item.0.clone()),
434                    };
435                    Some((key, item.1.clone()))
436                } else {
437                    None
438                }
439            }
440            Map::Structural(vec) => {
441                if self.index < vec.len() {
442                    let item = &vec[self.index];
443                    self.index += 1;
444                    Some((OwnedMapKey::Text(item.0.clone()), item.1.clone()))
445                } else {
446                    None
447                }
448            }
449        }
450    }
451}
452
453impl StructuralEq for Map {
454    fn structural_eq(&self, other: &Self) -> bool {
455        if self.size() != other.size() {
456            return false;
457        }
458        for ((key, value), (other_key, other_value)) in
459            self.into_iter().zip(other.into_iter())
460        {
461            if !key.structural_eq(&other_key)
462                || !value.structural_eq(other_value)
463            {
464                return false;
465            }
466        }
467        true
468    }
469}
470
471impl Hash for Map {
472    fn hash<H: Hasher>(&self, state: &mut H) {
473        for (k, v) in self.into_iter() {
474            k.hash(state);
475            v.hash(state);
476        }
477    }
478}
479
480impl CoreValueTrait for Map {}
481
482impl Display for Map {
483    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
484        write!(f, "{{")?;
485        for (i, (key, value)) in self.into_iter().enumerate() {
486            if i > 0 {
487                write!(f, ", ")?;
488            }
489            write!(f, "{key}: {value}")?;
490        }
491        write!(f, "}}")
492    }
493}
494
495impl<K, V> From<HashMap<K, V>> for Map
496where
497    K: Into<ValueContainer>,
498    V: Into<ValueContainer>,
499{
500    fn from(map: HashMap<K, V>) -> Self {
501        Map::new(map.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
502    }
503}
504
505impl IntoIterator for Map {
506    type Item = (OwnedMapKey, ValueContainer);
507    type IntoIter = IntoMapIterator;
508
509    fn into_iter(self) -> Self::IntoIter {
510        IntoMapIterator {
511            map: self,
512            index: 0,
513        }
514    }
515}
516
517impl<'a> IntoIterator for &'a Map {
518    type Item = (MapKey<'a>, &'a ValueContainer);
519    type IntoIter = MapIterator<'a>;
520
521    fn into_iter(self) -> Self::IntoIter {
522        MapIterator {
523            map: self,
524            index: 0,
525        }
526    }
527}
528
529impl<'a> IntoIterator for &'a mut Map {
530    type Item = (MapKey<'a>, &'a mut ValueContainer);
531    type IntoIter = MapMutIterator<'a>;
532
533    fn into_iter(self) -> Self::IntoIter {
534        match self {
535            Map::Dynamic(map) => MapMutIterator::Dynamic(map.iter_mut()),
536            Map::Fixed(vec) => MapMutIterator::Fixed(vec.iter_mut()),
537            Map::Structural(vec) => MapMutIterator::Structural(vec.iter_mut()),
538        }
539    }
540}
541
542impl From<Vec<(ValueContainer, ValueContainer)>> for Map {
543    /// Create a dynamic map from a vector of value containers.
544    fn from(vec: Vec<(ValueContainer, ValueContainer)>) -> Self {
545        Map::new(vec.into_iter().collect())
546    }
547}
548
549impl From<Vec<(String, ValueContainer)>> for Map {
550    /// Create a dynamic map from a vector of string keys and value containers.
551    fn from(vec: Vec<(String, ValueContainer)>) -> Self {
552        Map::new(
553            vec.into_iter()
554                .map(|(k, v)| (k.into(), v))
555                .collect::<IndexMap<ValueContainer, ValueContainer>>(),
556        )
557    }
558}
559
560impl<K, V> FromIterator<(K, V)> for Map
561where
562    K: Into<ValueContainer>,
563    V: Into<ValueContainer>,
564{
565    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
566        Map::Dynamic(
567            iter.into_iter()
568                .map(|(k, v)| (k.into(), v.into()))
569                .collect(),
570        )
571    }
572}
573
574impl From<IndexMap<ValueContainer, ValueContainer>> for Map {
575    fn from(map: IndexMap<ValueContainer, ValueContainer>) -> Self {
576        Map::new(map)
577    }
578}
579impl From<IndexMap<String, ValueContainer>> for Map {
580    fn from(map: IndexMap<String, ValueContainer>) -> Self {
581        Map::new(
582            map.into_iter()
583                .map(|(k, v)| (k.into(), v))
584                .collect::<IndexMap<ValueContainer, ValueContainer>>(),
585        )
586    }
587}
588
589impl TryFrom<CoreValue> for Map {
590    type Error = String;
591
592    fn try_from(value: CoreValue) -> Result<Self, Self::Error> {
593        if let CoreValue::Map(map) = value {
594            Ok(map)
595        } else {
596            Err(format!("Expected CoreValue::Map, found {value:?}"))
597        }
598    }
599}
600
601#[cfg(test)]
602mod tests {
603    use crate::values::core_values::decimal::typed_decimal::TypedDecimal;
604    use crate::values::core_values::map::Map;
605    use crate::values::value_container::ValueContainer;
606    use datex_core::values::core_values::decimal::Decimal;
607
608    #[test]
609    fn test_map() {
610        let mut map = Map::default();
611        map.set("key1", 42);
612        map.set("key2", "value2");
613        assert_eq!(map.size(), 2);
614        assert_eq!(map.get_owned("key1").unwrap().to_string(), "42");
615        assert_eq!(map.get_owned("key2").unwrap().to_string(), "\"value2\"");
616        assert_eq!(map.to_string(), r#"{"key1": 42, "key2": "value2"}"#);
617    }
618
619    #[test]
620    fn test_duplicate_keys() {
621        let mut map = Map::default();
622        map.set("key1", 42);
623        map.set("key1", "new_value");
624        assert_eq!(map.size(), 1);
625        assert_eq!(map.get_owned("key1").unwrap().to_string(), "\"new_value\"");
626    }
627
628    #[test]
629    fn test_ref_keys() {
630        let mut map = Map::default();
631        let key = ValueContainer::new_reference(ValueContainer::from(42));
632        map.set(key.clone(), "value");
633        // same reference should be found
634        assert_eq!(map.size(), 1);
635        assert!(map.has(&key));
636        assert_eq!(map.get(&key).unwrap().to_string(), "\"value\"");
637
638        // new reference with same value should not be found
639        let new_key = ValueContainer::new_reference(ValueContainer::from(42));
640        assert!(!map.has(&new_key));
641        assert!(map.get(&new_key).is_none());
642    }
643
644    #[test]
645    fn test_decimal_nan_value_key() {
646        let mut map = Map::default();
647        let nan_value = ValueContainer::from(Decimal::NaN);
648        map.set(nan_value.clone(), "value");
649        // same NaN value should be found
650        assert_eq!(map.size(), 1);
651        assert!(map.has(&nan_value));
652
653        // new NaN value should also be found
654        let new_nan_value = ValueContainer::from(Decimal::NaN);
655        assert!(map.has(&new_nan_value));
656
657        // adding new_nan_value should not increase size
658        map.set(new_nan_value.clone(), "new_value");
659        assert_eq!(map.size(), 1);
660    }
661
662    #[test]
663    fn test_float_nan_value_key() {
664        let mut map = Map::default();
665        let nan_value = ValueContainer::from(f64::NAN);
666        map.set(nan_value.clone(), "value");
667        // same NaN value should be found
668        assert_eq!(map.size(), 1);
669        assert!(map.has(&nan_value));
670
671        // new f64 NaN value should also be found
672        let new_nan_value = ValueContainer::from(f64::NAN);
673        assert!(map.has(&new_nan_value));
674
675        // new f32 NaN should not be found
676        let float32_nan_value = ValueContainer::from(f32::NAN);
677        assert!(!map.has(&float32_nan_value));
678
679        // adding new_nan_value should not increase size
680        map.set(new_nan_value.clone(), "new_value");
681        assert_eq!(map.size(), 1);
682    }
683
684    #[test]
685    fn test_decimal_zero_value_key() {
686        let mut map = Map::default();
687        let zero_value = ValueContainer::from(Decimal::Zero);
688        map.set(zero_value.clone(), "value");
689        // same Zero value should be found
690        assert_eq!(map.size(), 1);
691        assert!(map.has(&zero_value));
692
693        // new Zero value should also be found
694        let new_zero_value = ValueContainer::from(Decimal::Zero);
695        println!("new_zero_value: {:?}", new_zero_value);
696        assert!(map.has(&new_zero_value));
697
698        // new NegZero value should also be found
699        let neg_zero_value = ValueContainer::from(Decimal::NegZero);
700        assert!(map.has(&neg_zero_value));
701
702        // adding neg_zero_value should not increase size
703        map.set(neg_zero_value.clone(), "new_value");
704        assert_eq!(map.size(), 1);
705    }
706
707    #[test]
708    fn test_float_zero_value_key() {
709        let mut map = Map::default();
710        let zero_value = ValueContainer::from(0.0f64);
711        map.set(zero_value.clone(), "value");
712        // same 0.0 value should be found
713        assert_eq!(map.size(), 1);
714        assert!(map.has(&zero_value));
715        // new 0.0 value should also be found
716        let new_zero_value = ValueContainer::from(0.0f64);
717        assert!(map.has(&new_zero_value));
718        // new -0.0 value should also be found
719        let neg_zero_value = ValueContainer::from(-0.0f64);
720        assert!(map.has(&neg_zero_value));
721
722        // adding neg_zero_value should not increase size
723        map.set(neg_zero_value.clone(), "new_value");
724        assert_eq!(map.size(), 1);
725
726        // new 0.0f32 value should not be found
727        let float32_zero_value = ValueContainer::from(0.0f32);
728        assert!(!map.has(&float32_zero_value));
729    }
730
731    #[test]
732    fn test_typed_big_decimal_key() {
733        let mut map = Map::default();
734        let zero_big_decimal =
735            ValueContainer::from(TypedDecimal::Decimal(Decimal::Zero));
736        map.set(zero_big_decimal.clone(), "value");
737        // same Zero value should be found
738        assert_eq!(map.size(), 1);
739        assert!(map.has(&zero_big_decimal));
740        // new Zero value should also be found
741        let new_zero_big_decimal =
742            ValueContainer::from(TypedDecimal::Decimal(Decimal::Zero));
743        assert!(map.has(&new_zero_big_decimal));
744        // new NegZero value should also be found
745        let neg_zero_big_decimal =
746            ValueContainer::from(TypedDecimal::Decimal(Decimal::NegZero));
747        assert!(map.has(&neg_zero_big_decimal));
748
749        // adding neg_zero_big_decimal should not increase size
750        map.set(neg_zero_big_decimal.clone(), "new_value");
751        assert_eq!(map.size(), 1);
752    }
753}