xee_interpreter/function/
map.rs

1use std::rc::Rc;
2
3use ahash::{HashMap, HashMapExt};
4use xee_schema_type::Xs;
5use xee_xpath_ast::ast;
6use xot::Xot;
7
8use crate::{atomic, context, error, sequence, string};
9
10/// An XPath Map (a collection of key-value pairs).
11#[derive(Debug, Clone, PartialEq)]
12pub enum Map {
13    Empty(EmptyMap),
14    One(OneMap),
15    Many(ManyMap),
16}
17
18impl Map {
19    pub(crate) fn new(entries: Vec<(atomic::Atomic, sequence::Sequence)>) -> error::Result<Self> {
20        match entries.len() {
21            0 => Ok(Self::Empty(EmptyMap)),
22            1 => {
23                let (key, value) = entries.into_iter().next().unwrap();
24                let map_key = atomic::MapKey::new(key.clone())?;
25                Ok(Self::One(
26                    OneMapValue {
27                        map_key,
28                        key_value: (key, value),
29                    }
30                    .into(),
31                ))
32            }
33            _ => Ok(Self::Many(ManyMap::new(entries)?)),
34        }
35    }
36
37    fn from_map(map: HashMap<atomic::MapKey, (atomic::Atomic, sequence::Sequence)>) -> Self {
38        match map.len() {
39            0 => Self::Empty(EmptyMap),
40            1 => {
41                let (map_key, (key, value)) = map.into_iter().next().unwrap();
42                Self::One(
43                    OneMapValue {
44                        map_key,
45                        key_value: (key, value),
46                    }
47                    .into(),
48                )
49            }
50            _ => Self::Many(ManyMap(Rc::new(map))),
51        }
52    }
53
54    pub(crate) fn combine(
55        maps: impl Iterator<Item = error::Result<Map>>,
56        combine: impl Fn(sequence::Sequence, sequence::Sequence) -> error::Result<sequence::Sequence>,
57    ) -> error::Result<Map> {
58        let mut result = HashMap::new();
59        for map in maps {
60            for (map_key, (key, value)) in map?.full_entries() {
61                let map_key = map_key.clone();
62                let entry = result.remove(&map_key);
63                let value = if let Some((_, a)) = entry {
64                    combine(a, value.clone())?
65                } else {
66                    value.clone()
67                };
68                result.insert(map_key, (key.clone(), value));
69            }
70        }
71        Ok(Map::from_map(result))
72    }
73
74    pub(crate) fn len(&self) -> usize {
75        match self {
76            Map::Empty(map) => map.len(),
77            Map::One(map) => map.len(),
78            Map::Many(map) => map.len(),
79        }
80    }
81    pub(crate) fn is_empty(&self) -> bool {
82        match self {
83            Map::Empty(map) => map.is_empty(),
84            Map::One(map) => map.is_empty(),
85            Map::Many(map) => map.is_empty(),
86        }
87    }
88    pub(crate) fn get(&self, key: &atomic::Atomic) -> Option<&sequence::Sequence> {
89        match self {
90            Map::Empty(map) => map.get(key),
91            Map::One(map) => map.get(key),
92            Map::Many(map) => map.get(key),
93        }
94    }
95    pub(crate) fn keys(&self) -> Box<dyn Iterator<Item = &atomic::Atomic> + '_> {
96        match self {
97            Map::Empty(map) => Box::new(map.keys()),
98            Map::One(map) => Box::new(map.keys()),
99            Map::Many(map) => Box::new(map.keys()),
100        }
101    }
102    pub(crate) fn entries(
103        &self,
104    ) -> Box<dyn Iterator<Item = (&atomic::Atomic, &sequence::Sequence)> + '_> {
105        match self {
106            Map::Empty(map) => Box::new(map.entries()),
107            Map::One(map) => Box::new(map.entries()),
108            Map::Many(map) => Box::new(map.entries()),
109        }
110    }
111
112    pub(crate) fn map_keys(&self) -> Box<dyn Iterator<Item = &'_ atomic::MapKey> + '_> {
113        match self {
114            Map::Empty(map) => Box::new(map.map_keys()),
115            Map::One(map) => Box::new(map.map_keys()),
116            Map::Many(map) => Box::new(map.map_keys()),
117        }
118    }
119
120    pub(crate) fn map_key_entries(
121        &self,
122    ) -> Box<dyn Iterator<Item = (&atomic::MapKey, &sequence::Sequence)> + '_> {
123        match self {
124            Map::Empty(map) => Box::new(map.map_key_entries()),
125            Map::One(map) => Box::new(map.map_key_entries()),
126            Map::Many(map) => Box::new(map.map_key_entries()),
127        }
128    }
129
130    pub(crate) fn full_entries(
131        &self,
132    ) -> Box<dyn Iterator<Item = (&atomic::MapKey, &(atomic::Atomic, sequence::Sequence))> + '_>
133    {
134        match self {
135            Map::Empty(map) => Box::new(map.full_entries()),
136            Map::One(map) => Box::new(map.full_entries()),
137            Map::Many(map) => Box::new(map.full_entries()),
138        }
139    }
140
141    pub(crate) fn get_as_type(
142        &self,
143        key: &atomic::Atomic,
144        occurrence: ast::Occurrence,
145        atomic_type: Xs,
146        static_context: &context::StaticContext,
147        xot: &Xot,
148    ) -> error::Result<Option<sequence::Sequence>> {
149        match self {
150            Map::Empty(map) => map.get_as_type(key, occurrence, atomic_type, static_context, xot),
151            Map::One(map) => map.get_as_type(key, occurrence, atomic_type, static_context, xot),
152            Map::Many(map) => map.get_as_type(key, occurrence, atomic_type, static_context, xot),
153        }
154    }
155
156    pub(crate) fn deep_equal(
157        &self,
158        other: &Map,
159        collation: &string::Collation,
160        default_offset: chrono::FixedOffset,
161        xot: &Xot,
162    ) -> error::Result<bool> {
163        match (self, other) {
164            (Map::Empty(_), Map::Empty(_)) => Ok(true),
165            (Map::Empty(_), _) => Ok(false),
166            (_, Map::Empty(_)) => Ok(false),
167            (Map::One(map), Map::One(other)) => {
168                map.deep_equal(other, collation, default_offset, xot)
169            }
170            (Map::One(map), Map::Many(other)) => {
171                map.deep_equal(other, collation, default_offset, xot)
172            }
173            (Map::Many(map), Map::Many(other)) => {
174                map.deep_equal(other, collation, default_offset, xot)
175            }
176            (Map::Many(map), Map::One(other)) => {
177                map.deep_equal(other, collation, default_offset, xot)
178            }
179        }
180    }
181
182    pub fn display_representation(&self, xot: &Xot, context: &context::DynamicContext) -> String {
183        match self {
184            Map::Empty(map) => map.display_representation(xot, context),
185            Map::One(map) => map.display_representation(xot, context),
186            Map::Many(map) => map.display_representation(xot, context),
187        }
188    }
189
190    pub(crate) fn put(
191        &self,
192        key: atomic::Atomic,
193        value: &sequence::Sequence,
194    ) -> error::Result<Self> {
195        Ok(match self {
196            Map::Empty(_) => {
197                // if we add a key to an empty map we get a OneMap
198                let map_key = atomic::MapKey::new(key.clone())?;
199                Map::One(
200                    OneMapValue {
201                        map_key,
202                        key_value: (key, value.clone()),
203                    }
204                    .into(),
205                )
206            }
207            Map::One(one) => {
208                let map_key = atomic::MapKey::new(key.clone())?;
209                if one.0.map_key == map_key {
210                    // we merely update the value
211                    Map::One(
212                        OneMapValue {
213                            map_key,
214                            key_value: (key.clone(), value.clone()),
215                        }
216                        .into(),
217                    )
218                } else {
219                    // if we add a key to a one map we get a ManyMap
220                    let entries = vec![
221                        (one.0.key_value.0.clone(), one.0.key_value.1.clone()),
222                        (key, value.clone()),
223                    ];
224                    Map::Many(ManyMap::try_from(entries)?)
225                }
226            }
227            // since at most we add keys, this cannot turn into a non-many map
228            Map::Many(map) => Map::Many(map.put(key, value)?),
229        })
230    }
231
232    pub(crate) fn remove_keys(
233        &self,
234        keys: impl Iterator<Item = error::Result<atomic::Atomic>>,
235    ) -> error::Result<Self> {
236        Ok(match self {
237            Map::Empty(_) => Map::Empty(EmptyMap),
238            Map::One(map) => {
239                for key in keys {
240                    let map_key = atomic::MapKey::new(key?.clone())?;
241                    if map.0.map_key == map_key {
242                        return Ok(Map::Empty(EmptyMap));
243                    }
244                }
245                Map::One(map.clone())
246            }
247            Map::Many(map) => Map::from_map(map.remove_keys(keys)?),
248        })
249    }
250}
251
252pub(crate) trait Mappable {
253    fn len(&self) -> usize;
254    fn is_empty(&self) -> bool;
255
256    // get a key by underlying map key
257    fn get_by_map_key(&self, map_key: &atomic::MapKey) -> Option<&sequence::Sequence>;
258
259    /// get map keys
260    fn map_keys(&self) -> impl Iterator<Item = &'_ atomic::MapKey> + '_;
261
262    // get map entries, key is map key
263    fn map_key_entries(&self) -> impl Iterator<Item = (&atomic::MapKey, &sequence::Sequence)> + '_;
264
265    fn full_entries(
266        &self,
267    ) -> impl Iterator<Item = (&atomic::MapKey, &(atomic::Atomic, sequence::Sequence))> + '_;
268
269    // get a key by atomic
270    fn get(&self, key: &atomic::Atomic) -> Option<&sequence::Sequence> {
271        let map_key = atomic::MapKey::new(key.clone()).ok()?;
272        self.get_by_map_key(&map_key)
273    }
274
275    // get atomic keys
276    fn keys(&self) -> impl Iterator<Item = &atomic::Atomic> + '_;
277
278    // get entries with atomic key and value
279    fn entries(&self) -> impl Iterator<Item = (&atomic::Atomic, &sequence::Sequence)> + '_;
280
281    // get a key by atomic and convert to a specific type
282    fn get_as_type(
283        &self,
284        key: &atomic::Atomic,
285        occurrence: ast::Occurrence,
286        atomic_type: Xs,
287        static_context: &context::StaticContext,
288        xot: &Xot,
289    ) -> error::Result<Option<sequence::Sequence>> {
290        let value = self.get(key);
291        let value = match value {
292            Some(value) => value,
293            None => return Ok(None),
294        };
295        let sequence_type = ast::SequenceType::Item(ast::Item {
296            occurrence,
297            item_type: ast::ItemType::AtomicOrUnionType(atomic_type),
298        });
299        // TODO: is value clone really needed?
300        Ok(Some(
301            value.clone().sequence_type_matching_function_conversion(
302                &sequence_type,
303                static_context,
304                xot,
305                // typed function tests can't be invoked
306                &|_function| unreachable!(),
307            )?,
308        ))
309    }
310
311    // deep equal compare between two mappables
312    fn deep_equal(
313        &self,
314        other: &impl Mappable,
315        collation: &string::Collation,
316        default_offset: chrono::FixedOffset,
317        xot: &Xot,
318    ) -> error::Result<bool> {
319        if self.len() != other.len() {
320            return Ok(false);
321        }
322        for (map_key, value) in self.map_key_entries() {
323            let other_value = other.get_by_map_key(map_key);
324            if let Some(other_value) = other_value {
325                if !value.deep_equal(other_value, collation, default_offset, xot)? {
326                    return Ok(false);
327                }
328            } else {
329                return Ok(false);
330            }
331        }
332        Ok(true)
333    }
334
335    fn display_representation(&self, xot: &Xot, context: &context::DynamicContext) -> String {
336        let mut entries = self
337            .entries()
338            .map(|(key, value)| {
339                format!(
340                    "{}: {}",
341                    key.xpath_representation(),
342                    value.display_representation(xot, context)
343                )
344            })
345            .collect::<Vec<_>>();
346        entries.sort();
347        format!("map {{\n{}\n}}", entries.join(",\n"))
348    }
349}
350
351// empty map
352#[derive(Debug, Clone, PartialEq)]
353pub struct EmptyMap;
354
355impl Mappable for EmptyMap {
356    fn len(&self) -> usize {
357        0
358    }
359
360    fn is_empty(&self) -> bool {
361        true
362    }
363
364    fn get_by_map_key(&self, _map_key: &atomic::MapKey) -> Option<&sequence::Sequence> {
365        None
366    }
367
368    fn map_keys(&self) -> impl Iterator<Item = &'_ atomic::MapKey> + '_ {
369        std::iter::empty()
370    }
371
372    fn map_key_entries(&self) -> impl Iterator<Item = (&atomic::MapKey, &sequence::Sequence)> + '_ {
373        std::iter::empty()
374    }
375
376    fn full_entries(
377        &self,
378    ) -> impl Iterator<Item = (&atomic::MapKey, &(atomic::Atomic, sequence::Sequence))> + '_ {
379        std::iter::empty()
380    }
381
382    fn keys(&self) -> impl Iterator<Item = &atomic::Atomic> + '_ {
383        std::iter::empty()
384    }
385
386    fn entries(&self) -> impl Iterator<Item = (&atomic::Atomic, &sequence::Sequence)> + '_ {
387        std::iter::empty()
388    }
389}
390
391#[derive(Debug, Clone, PartialEq)]
392pub struct OneMap(Box<OneMapValue>);
393
394#[derive(Debug, Clone, PartialEq)]
395struct OneMapValue {
396    map_key: atomic::MapKey,
397    key_value: (atomic::Atomic, sequence::Sequence),
398}
399
400impl From<OneMapValue> for OneMap {
401    fn from(value: OneMapValue) -> Self {
402        Self(Box::new(value))
403    }
404}
405
406impl Mappable for OneMap {
407    fn len(&self) -> usize {
408        1
409    }
410
411    fn is_empty(&self) -> bool {
412        false
413    }
414
415    fn get_by_map_key(&self, map_key: &atomic::MapKey) -> Option<&sequence::Sequence> {
416        if &self.0.map_key == map_key {
417            Some(&self.0.key_value.1)
418        } else {
419            None
420        }
421    }
422
423    fn map_keys(&self) -> impl Iterator<Item = &'_ atomic::MapKey> + '_ {
424        std::iter::once(&self.0.map_key)
425    }
426
427    fn map_key_entries(&self) -> impl Iterator<Item = (&atomic::MapKey, &sequence::Sequence)> + '_ {
428        std::iter::once((&self.0.map_key, &self.0.key_value.1))
429    }
430
431    fn full_entries(
432        &self,
433    ) -> impl Iterator<Item = (&atomic::MapKey, &(atomic::Atomic, sequence::Sequence))> + '_ {
434        std::iter::once((&self.0.map_key, &self.0.key_value))
435    }
436
437    fn keys(&self) -> impl Iterator<Item = &atomic::Atomic> + '_ {
438        std::iter::once(&self.0.key_value.0)
439    }
440
441    fn entries(&self) -> impl Iterator<Item = (&atomic::Atomic, &sequence::Sequence)> + '_ {
442        std::iter::once((&self.0.key_value.0, &self.0.key_value.1))
443    }
444}
445
446// a normal map uses a hashmap to store > 1 key-value pairs
447#[derive(Debug, Clone, PartialEq)]
448pub struct ManyMap(Rc<HashMap<atomic::MapKey, (atomic::Atomic, sequence::Sequence)>>);
449
450impl ManyMap {
451    fn new(entries: Vec<(atomic::Atomic, sequence::Sequence)>) -> error::Result<Self> {
452        let mut map = HashMap::new();
453        for (key, value) in entries {
454            let map_key = atomic::MapKey::new(key.clone())?;
455            if map.contains_key(&map_key) {
456                return Err(error::Error::XQDY0137);
457            }
458            map.insert(map_key, (key, value));
459        }
460        Ok(Self(Rc::new(map)))
461    }
462
463    pub(crate) fn put(
464        &self,
465        key: atomic::Atomic,
466        value: &sequence::Sequence,
467    ) -> error::Result<Self> {
468        let mut map = self.0.as_ref().clone();
469        let map_key = atomic::MapKey::new(key.clone())?;
470        map.insert(map_key, (key, value.clone()));
471        Ok(Self(Rc::new(map)))
472    }
473
474    pub(crate) fn remove_keys(
475        &self,
476        keys: impl Iterator<Item = error::Result<atomic::Atomic>>,
477    ) -> error::Result<HashMap<atomic::MapKey, (atomic::Atomic, sequence::Sequence)>> {
478        let mut map = self.0.as_ref().clone();
479        for key in keys {
480            let map_key = atomic::MapKey::new(key?.clone()).unwrap();
481            map.remove(&map_key);
482        }
483        Ok(map)
484    }
485}
486
487impl Mappable for ManyMap {
488    fn len(&self) -> usize {
489        self.0.len()
490    }
491
492    fn is_empty(&self) -> bool {
493        self.0.is_empty()
494    }
495
496    fn get_by_map_key(&self, map_key: &atomic::MapKey) -> Option<&sequence::Sequence> {
497        self.0.get(map_key).map(|(_, v)| v)
498    }
499
500    fn map_keys(&self) -> impl Iterator<Item = &'_ atomic::MapKey> + '_ {
501        self.0.keys()
502    }
503
504    fn map_key_entries(&self) -> impl Iterator<Item = (&atomic::MapKey, &sequence::Sequence)> + '_ {
505        self.0.iter().map(|(k, (_, v))| (k, v))
506    }
507
508    fn full_entries(
509        &self,
510    ) -> impl Iterator<Item = (&atomic::MapKey, &(atomic::Atomic, sequence::Sequence))> + '_ {
511        self.0.iter()
512    }
513
514    fn keys(&self) -> impl Iterator<Item = &atomic::Atomic> + '_ {
515        self.0.values().map(|(k, _)| k)
516    }
517
518    fn entries(&self) -> impl Iterator<Item = (&atomic::Atomic, &sequence::Sequence)> + '_ {
519        self.0.iter().map(|(_, (k, v))| (k, v))
520    }
521}
522
523impl TryFrom<Vec<(atomic::Atomic, sequence::Sequence)>> for ManyMap {
524    type Error = error::Error;
525    fn try_from(vec: Vec<(atomic::Atomic, sequence::Sequence)>) -> error::Result<Self> {
526        Self::new(vec)
527    }
528}