catlog/tt/util/
row.rs

1//! Rows.
2use crate::{tt::prelude::*, zero::LabelSegment};
3use std::ops::Index;
4
5/// A cheaply cloneable, insertion-ordered map from `FieldName` to `T`.
6///
7/// Also stores a "label" for each entry, which may not be the same as the
8/// FieldName in the case that the FieldName is a UUID.
9///
10/// This is called "row" because it's a short name, and it corresponds to the idea
11/// of a row in a database, which is a map from fields to values.
12///
13/// Create this using the [FromIterator] implementation.
14#[derive(Clone, PartialEq, Eq)]
15pub struct Row<T>(Rc<IndexMap<FieldName, (LabelSegment, T)>>);
16
17impl<T> Index<FieldName> for Row<T> {
18    type Output = T;
19    fn index(&self, index: FieldName) -> &Self::Output {
20        self.get(index).unwrap()
21    }
22}
23
24impl<T> Row<T> {
25    /// Lookup the field `name` if it exists.
26    ///
27    /// Also see the [Index] implementation, which just `unwrap`s this.
28    pub fn get(&self, name: FieldName) -> Option<&T> {
29        self.0.get(&name).map(|p| &p.1)
30    }
31
32    /// Iterate through the fields in insertion order.
33    pub fn iter(&self) -> impl Iterator<Item = (&FieldName, &(LabelSegment, T))> {
34        self.0.iter()
35    }
36
37    /// Return the number of fields.
38    pub fn len(&self) -> usize {
39        self.0.len()
40    }
41
42    /// Return whether the row is empty (Clippy wants this).
43    pub fn is_empty(&self) -> bool {
44        self.0.is_empty()
45    }
46
47    /// Return whether the row contains the given field
48    pub fn has(&self, field_name: FieldName) -> bool {
49        self.0.contains_key(&field_name)
50    }
51
52    /// Produce the empty row.
53    pub fn empty() -> Self {
54        Self(Rc::new(IndexMap::new()))
55    }
56
57    /// Map a function to produce a new row.
58    pub fn map<S>(&self, f: impl Fn(&T) -> S) -> Row<S> {
59        self.iter().map(|(name, (label, x))| (*name, (*label, f(x)))).collect()
60    }
61}
62
63impl<T: Clone> Row<T> {
64    ///  Insert a new field
65    ///
66    /// Uses [Rc::make_mut] to mutate in place if there are no other references to self,
67    /// otherwise performs a clone.
68    pub fn insert(mut self, field: FieldName, label: LabelSegment, value: T) -> Self {
69        Rc::make_mut(&mut self.0).insert(field, (label, value));
70        self
71    }
72}
73
74impl<T> FromIterator<(FieldName, (LabelSegment, T))> for Row<T> {
75    fn from_iter<I>(iter: I) -> Self
76    where
77        I: IntoIterator<Item = (FieldName, (LabelSegment, T))>,
78    {
79        Row(Rc::new(iter.into_iter().collect()))
80    }
81}
82
83impl<T> From<IndexMap<FieldName, (LabelSegment, T)>> for Row<T> {
84    fn from(value: IndexMap<FieldName, (LabelSegment, T)>) -> Self {
85        Self(Rc::new(value))
86    }
87}