Skip to main content

ratio_metadata/
category.rs

1//! # Metadata category store module
2//!
3//! A category store is a store for a certain category of metadata, such as names, kinds, labels,
4//! weights, or annotations. It contains a field name interner that does the heavy lifting of
5//! reducing the need to clone field names (except once for reverse indexing), and exposes different
6//! methods for different types of values such as names and kinds for "single value" options, sets
7//! such as labels, and maps such as weights and annotations.
8//!
9//! ## License
10//!
11//! This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
12//! If a copy of the MPL was not distributed with this file,
13//! You can obtain one at <https://mozilla.org/MPL/2.0/>.
14//!
15//! **Code examples both in the docstrings and rendered documentation are free to use.**
16
17use std::borrow::{Borrow, Cow};
18use std::collections::{BTreeMap, BTreeSet};
19use std::fmt::Debug;
20use std::iter::once;
21
22use slotmap::{Key, SecondaryMap};
23
24use crate::interner::{DenseSlottedBTreeInterner, Interner};
25
26/// Storage of a certain categories of metadata.
27#[derive(Clone, Debug)]
28#[cfg_attr(
29    feature = "serde",
30    derive(serde::Serialize, serde::Deserialize),
31    serde(default, rename_all = "camelCase")
32)]
33#[cfg_attr(feature = "reactive", derive(reactive_stores::Store))]
34pub struct Category<ObjKey, Value, FieldKey, Field>
35where
36    ObjKey: Key,
37    FieldKey: Key,
38    Field: Clone + Debug + Ord,
39{
40    /// External keys to values expressed as collections or values using inner field keys.
41    values: SecondaryMap<ObjKey, Value>,
42
43    /// Internal keys to external keys that use them.
44    objects_by_field: SecondaryMap<FieldKey, BTreeSet<ObjKey>>,
45
46    /// Field name interner of the category store.
47    field_interner: DenseSlottedBTreeInterner<FieldKey, Field>,
48}
49
50impl<ObjKey, Value, FieldKey, Field> Default for Category<ObjKey, Value, FieldKey, Field>
51where
52    ObjKey: Key,
53    FieldKey: Key,
54    Field: Clone + Debug + Ord,
55{
56    fn default() -> Self {
57        Self {
58            values: SecondaryMap::default(),
59            objects_by_field: SecondaryMap::default(),
60            field_interner: DenseSlottedBTreeInterner::default(),
61        }
62    }
63}
64
65/// Behavior for any Category store.
66impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
67where
68    ObjKey: Key,
69    FieldKey: Key,
70    Field: Clone + Debug + Ord,
71{
72    /// Create a new category store.
73    pub fn new() -> Self {
74        Self::default()
75    }
76
77    /// Interned key for a field name.
78    /// Returns `None` if the field name is unknown (not interned).
79    pub fn field_key_interned(&self, name: &Field) -> Option<FieldKey> {
80        self.field_interner.get_key(name)
81    }
82
83    /// Intern a field name and return the key.
84    pub fn field_key(&mut self, name: Cow<'_, Field>) -> FieldKey {
85        self.field_interner.intern(name)
86    }
87
88    /// Obtain a reference to an interned field name via its key.
89    pub fn field_name(&self, key: FieldKey) -> Option<&Field> {
90        self.field_interner.get_value(key)
91    }
92
93    /// Number of tracked objects.
94    pub fn num_objects(&self) -> usize {
95        self.values.len()
96    }
97
98    /// All object keys in store.
99    pub fn object_keys(&self) -> impl Iterator<Item = ObjKey> {
100        self.values.keys()
101    }
102
103    /// Number of tracked fields.
104    pub fn num_fields(&self) -> usize {
105        self.field_interner.len()
106    }
107
108    /// All field names in store.
109    pub fn field_names(&self) -> impl Iterator<Item = &Field> {
110        self.field_interner.values()
111    }
112
113    /// All field keys by field name.
114    pub fn field_keys(&self) -> impl Iterator<Item = FieldKey> {
115        self.field_interner.keys()
116    }
117
118    /// All field names and keys in store.
119    pub fn field_items(&self) -> impl Iterator<Item = (FieldKey, &Field)> {
120        self.field_interner.items()
121    }
122
123    /// Get the current value expressed in internal keys.
124    pub fn object_value(&self, obj: ObjKey) -> Option<&Value> {
125        self.values.get(obj)
126    }
127
128    /// Get all objects which have a certain field.
129    pub fn objects_with_field(&self, field: FieldKey) -> Option<&BTreeSet<ObjKey>> {
130        self.objects_by_field.get(field)
131    }
132
133    /// Get all objects which have a certain field name.
134    pub fn objects_with_field_name(&self, name: &Field) -> Option<&BTreeSet<ObjKey>> {
135        let key = self.field_key_interned(name)?;
136        self.objects_with_field(key)
137    }
138
139    /// Whether this manager tracks this object.
140    pub fn contains_object(&self, obj: ObjKey) -> bool {
141        self.values.contains_key(obj)
142    }
143
144    /// Whether this field key is being tracked by this category.
145    /// Should hold as long as the key is valid.
146    pub fn contains_field(&self, field: FieldKey) -> bool {
147        self.objects_by_field.contains_key(field)
148    }
149
150    /// Whether this field name is being tracked by this category.
151    pub fn contains_field_name<Name: Borrow<Field>>(&self, name: Name) -> bool {
152        self.field_interner.contains_value(name.borrow())
153    }
154
155    /// Whether an object has this field set.
156    pub fn object_contains_field(&self, obj: ObjKey, field: FieldKey) -> bool {
157        self.objects_with_field(field)
158            .map(|objs| objs.contains(&obj))
159            .unwrap_or_default()
160    }
161}
162
163/// Behavior for any category store with field-key encoded values.
164impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
165where
166    ObjKey: Key,
167    FieldKey: Key,
168    Field: Clone + Debug + Ord,
169    Value: FieldValue<FieldKey>,
170{
171    /// Clean the innards of this store, clearing the fields which are not assigned to any
172    /// objects from the reverse index and field name interner.
173    pub fn clean(&mut self) {
174        self.values.retain(|_, fields| fields.should_retain());
175
176        let unused = self
177            .field_interner
178            .keys()
179            .filter(|&field| match self.objects_by_field.get(field) {
180                Some(objects) => objects.is_empty(),
181                None => true,
182            })
183            .collect::<Vec<_>>();
184
185        for field in unused {
186            self.objects_by_field.remove(field);
187            self.field_interner.remove_key(field);
188        }
189    }
190
191    /// Get a value entry by its object key.
192    fn object_value_entry(&mut self, obj: ObjKey) -> Option<&mut Value> {
193        self.values.entry(obj).map(|entry| entry.or_default())
194    }
195
196    /// Get a objects entry by field.
197    fn objects_by_field_entry(&mut self, field: FieldKey) -> Option<&mut BTreeSet<ObjKey>> {
198        self.objects_by_field
199            .entry(field)
200            .map(|entry| entry.or_default())
201    }
202
203    /// Forget an object's entire value, removing all fields from it and itself from all fields.
204    /// Returns whether anything was removed.
205    pub fn remove_object(&mut self, obj: ObjKey) -> Option<Value> {
206        self.values.remove(obj).inspect(|value| {
207            value.fields().for_each(|field| {
208                self.remove_object_from_field_objects(field, obj);
209            });
210        })
211    }
212
213    /// Add an object to the field reverse search.
214    fn add_object_to_field_objects(&mut self, field: FieldKey, obj: ObjKey) -> bool {
215        self.objects_by_field_entry(field)
216            .map(|objects| objects.insert(obj))
217            .unwrap_or_default()
218    }
219
220    /// Remove an object from the reverse field search.
221    /// Removes the reverse search entry if it was the last object.
222    /// Does not remove it from the interned value, as to not invalidate any interned key.
223    /// Returns whether anything was removed.
224    /// Private method, as users should turn to `remove_field_from_object`.
225    fn remove_object_from_field_objects(&mut self, field: FieldKey, obj: ObjKey) -> bool {
226        let (is_empty, removed) = self
227            .objects_by_field
228            .get_mut(field)
229            .map(|objects| {
230                let removed = objects.remove(&obj);
231                (objects.is_empty(), removed)
232            })
233            .unwrap_or_default();
234        if is_empty {
235            self.objects_by_field.remove(field);
236        }
237        removed
238    }
239
240    /// Set an object value, replacing any pre-existing value.
241    pub fn insert_object_value(&mut self, obj: ObjKey, value: Value) {
242        self.remove_object(obj);
243        value.fields().for_each(|field| {
244            self.objects_by_field
245                .entry(field)
246                .map(|entry| entry.or_default().insert(obj));
247        });
248        self.values.insert(obj, value);
249    }
250
251    /// All fields attached to an object.
252    pub fn object_fields(&self, obj: ObjKey) -> impl Iterator<Item = FieldKey> {
253        self.values
254            .get(obj)
255            .into_iter()
256            .flat_map(|value| value.fields())
257    }
258
259    /// All field names attached to an object.
260    pub fn object_field_names(&self, obj: ObjKey) -> impl Iterator<Item = &Field> {
261        self.object_fields(obj).flat_map(|key| self.field_name(key))
262    }
263}
264
265/// Behavior for any category store with field-key encoded values *without* sub-values.
266impl<ObjKey, Value, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
267where
268    ObjKey: Key,
269    FieldKey: Key,
270    Field: Clone + Debug + Ord,
271    Value: FieldValue<FieldKey> + FieldWithoutSubValue<FieldKey>,
272{
273    /// Insert a field name for an object.
274    pub fn insert_field_name_for_object(&mut self, obj: ObjKey, name: Cow<'_, Field>) -> bool {
275        let field = self.field_key(name);
276        self.insert_field_for_object(obj, field)
277    }
278
279    /// Insert a field key for an object.
280    pub fn insert_field_for_object(&mut self, obj: ObjKey, field: FieldKey) -> bool {
281        self.add_object_to_field_objects(field, obj);
282        self.object_value_entry(obj)
283            .map(|value| value.insert_field(field))
284            .unwrap_or_default()
285    }
286
287    /// Remove a field name from the store from all objects by its name.
288    /// Returns whether it had to be removed.
289    pub fn remove_field_name(&mut self, name: &Field) -> Option<FieldKey> {
290        self.field_key_interned(name).map(|field| {
291            self.remove_field(field);
292            field
293        })
294    }
295
296    /// Remove a field entirely from the store from all objects.
297    /// Returns whether it had to be removed.
298    pub fn remove_field(&mut self, field: FieldKey) -> Option<Field> {
299        self.objects_by_field
300            .remove(field)
301            .into_iter()
302            .for_each(|objects| {
303                objects.into_iter().for_each(|obj| {
304                    self.remove_field_from_object(obj, field);
305                });
306            });
307        self.field_interner.remove_key(field)
308    }
309
310    /// Remove a field by its name from an object.
311    /// Returns whether anything was actually removed.
312    pub fn remove_field_name_from_object(&mut self, obj: ObjKey, field: &Field) -> bool {
313        self.field_key_interned(field)
314            .map(|field| self.remove_field_from_object(obj, field))
315            .unwrap_or_default()
316    }
317
318    /// Remove a field from an object.
319    /// Returns whether anything was actually removed.
320    pub fn remove_field_from_object(&mut self, obj: ObjKey, field: FieldKey) -> bool {
321        let retain = self
322            .values
323            .get_mut(obj)
324            .map(|value| {
325                value.remove_field(field);
326                value.should_retain()
327            })
328            .unwrap_or_default();
329
330        if !retain {
331            self.values.remove(obj);
332        }
333
334        self.remove_object_from_field_objects(field, obj)
335    }
336}
337
338/// Behavior for any category store with field-key encoded values *with* sub-values.
339impl<ObjKey, Value, SubValue, FieldKey, Field> Category<ObjKey, Value, FieldKey, Field>
340where
341    ObjKey: Key,
342    FieldKey: Key,
343    Field: Clone + Debug + Ord,
344    Value: FieldValue<FieldKey> + FieldWithSubValue<FieldKey, SubValue = SubValue>,
345{
346    /// Insert a field sub-value by its name for an object.
347    /// Returns the previous value if any.
348    pub fn insert_field_name_value_for_object(
349        &mut self,
350        obj: ObjKey,
351        field: Cow<Field>,
352        sub_value: SubValue,
353    ) -> Option<SubValue> {
354        let field = self.field_key(field);
355
356        self.insert_field_value_for_object(obj, field, sub_value)
357    }
358
359    /// Insert a field sub-value for an object by its field key.
360    /// Returns the previous value if any.
361    pub fn insert_field_value_for_object(
362        &mut self,
363        obj: ObjKey,
364        field: FieldKey,
365        sub_value: SubValue,
366    ) -> Option<SubValue> {
367        self.add_object_to_field_objects(field, obj);
368        self.object_value_entry(obj)
369            .and_then(|value| value.insert_field_value(field, sub_value))
370    }
371
372    /// Remove a field from all objects.
373    pub fn remove_field_name_values(&mut self, name: &Field) -> Option<FieldKey> {
374        self.field_key_interned(name).map(move |field| {
375            self.remove_field_values(field);
376            field
377        })
378    }
379
380    /// Remove field values from all objects.
381    pub fn remove_field_values(&mut self, field: FieldKey) -> Option<Field> {
382        self.objects_by_field
383            .remove(field)
384            .into_iter()
385            .flat_map(|objects| objects.into_iter())
386            .for_each(|obj| {
387                self.remove_field_value_from_object(obj, field);
388            });
389
390        self.field_interner.remove_key(field)
391    }
392
393    /// Remove a field sub-value by its name from an object.
394    /// Returns whether anything was actually removed.
395    pub fn remove_field_name_value_from_object(
396        &mut self,
397        obj: ObjKey,
398        name: &Field,
399    ) -> Option<SubValue> {
400        self.field_key_interned(name)
401            .and_then(|field| self.remove_field_value_from_object(obj, field))
402    }
403
404    /// Remove a field from an object.
405    /// Returns whether anything was actually removed.
406    pub fn remove_field_value_from_object(
407        &mut self,
408        obj: ObjKey,
409        field: FieldKey,
410    ) -> Option<SubValue> {
411        self.remove_object_from_field_objects(field, obj);
412
413        let (retain, sub_value) = self
414            .values
415            .get_mut(obj)
416            .map(|value| {
417                let sub_value = value.remove_field_value(field);
418                (value.should_retain(), sub_value)
419            })
420            .unwrap_or_default();
421
422        if !retain {
423            self.values.remove(obj);
424        }
425
426        sub_value
427    }
428
429    /// Get a field sub-value for an object by its field key.
430    pub fn field_value_for_object(&self, obj: ObjKey, field: FieldKey) -> Option<&SubValue> {
431        self.values
432            .get(obj)
433            .and_then(|value| value.field_value(field))
434    }
435
436    /// Get a field sub-value by its name for an object.
437    pub fn field_name_value_for_object(&self, obj: ObjKey, field: &Field) -> Option<&SubValue> {
438        self.field_key_interned(field)
439            .and_then(|field| self.field_value_for_object(obj, field))
440    }
441}
442
443/// Behavior for a value based on interned field keys.
444pub trait FieldValue<FieldKey>: Default {
445    /// Whether to retain this value.
446    fn should_retain(&self) -> bool;
447
448    /// All involved fields for this value.
449    fn fields(&self) -> impl Iterator<Item = FieldKey>;
450}
451impl<FieldKey: Key> FieldValue<FieldKey> for FieldKey {
452    fn should_retain(&self) -> bool {
453        self.is_null()
454    }
455    fn fields(&self) -> impl Iterator<Item = FieldKey> {
456        once(*self)
457    }
458}
459impl<FieldKey: Key> FieldValue<FieldKey> for Option<FieldKey> {
460    fn should_retain(&self) -> bool {
461        self.is_some()
462    }
463
464    fn fields(&self) -> impl Iterator<Item = FieldKey> {
465        self.iter().copied()
466    }
467}
468impl<FieldKey: Key> FieldValue<FieldKey> for BTreeSet<FieldKey> {
469    fn should_retain(&self) -> bool {
470        !self.is_empty()
471    }
472
473    fn fields(&self) -> impl Iterator<Item = FieldKey> {
474        self.iter().copied()
475    }
476}
477impl<FieldKey: Key, SubValue> FieldValue<FieldKey> for BTreeMap<FieldKey, SubValue> {
478    fn should_retain(&self) -> bool {
479        !self.is_empty()
480    }
481
482    fn fields(&self) -> impl Iterator<Item = FieldKey> {
483        self.keys().copied()
484    }
485}
486
487/// Behavior for a value without sub-values per interned field key such as `Option<FieldKey>` and
488/// `BTreeSet<FieldKey>`.
489pub trait FieldWithoutSubValue<FieldKey: Key> {
490    /// Set or insert this field in the value. Returns whether it was newly inserted.
491    fn insert_field(&mut self, field: FieldKey) -> bool;
492
493    /// Remove field. Returns if anything was removed.
494    fn remove_field(&mut self, field: FieldKey) -> bool;
495}
496
497impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for FieldKey {
498    fn insert_field(&mut self, mut field: FieldKey) -> bool {
499        if self == &field {
500            false
501        } else {
502            std::mem::swap(self, &mut field);
503            true
504        }
505    }
506    fn remove_field(&mut self, field: FieldKey) -> bool {
507        if self == &field {
508            std::mem::take(self);
509            true
510        } else {
511            false
512        }
513    }
514}
515impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for Option<FieldKey> {
516    fn insert_field(&mut self, field: FieldKey) -> bool {
517        if self == &Some(field) {
518            false
519        } else {
520            self.replace(field);
521            true
522        }
523    }
524
525    fn remove_field(&mut self, field: FieldKey) -> bool {
526        if self.as_ref() == Some(&field) {
527            self.take().is_some()
528        } else {
529            false
530        }
531    }
532}
533impl<FieldKey: Key> FieldWithoutSubValue<FieldKey> for BTreeSet<FieldKey> {
534    fn insert_field(&mut self, field: FieldKey) -> bool {
535        self.insert(field)
536    }
537
538    fn remove_field(&mut self, field: FieldKey) -> bool {
539        self.remove(&field)
540    }
541}
542impl<FieldKey: Key, SubValue: Default> FieldWithoutSubValue<FieldKey>
543    for BTreeMap<FieldKey, SubValue>
544{
545    fn insert_field(&mut self, field: FieldKey) -> bool {
546        self.insert(field, SubValue::default()).is_none()
547    }
548
549    fn remove_field(&mut self, field: FieldKey) -> bool {
550        self.remove(&field).is_some()
551    }
552}
553
554/// Behavior for a value with sub-values for interned field keys.
555pub trait FieldWithSubValue<FieldKey: Key> {
556    type SubValue;
557
558    /// Access a field's sub-value for it's interned field key.
559    fn field_value(&self, field: FieldKey) -> Option<&Self::SubValue>;
560
561    /// Insert a field's sub-value for it's interned field key.
562    fn insert_field_value(
563        &mut self,
564        field: FieldKey,
565        value: Self::SubValue,
566    ) -> Option<Self::SubValue>;
567
568    /// Remove a sub-value for an interned field key.
569    fn remove_field_value(&mut self, field: FieldKey) -> Option<Self::SubValue>;
570}
571impl<FieldKey: Key, SubValue> FieldWithSubValue<FieldKey> for BTreeMap<FieldKey, SubValue> {
572    type SubValue = SubValue;
573
574    fn field_value(&self, field: FieldKey) -> Option<&SubValue> {
575        self.get(&field)
576    }
577
578    fn insert_field_value(&mut self, field: FieldKey, value: SubValue) -> Option<SubValue> {
579        self.insert(field, value)
580    }
581
582    fn remove_field_value(&mut self, field: FieldKey) -> Option<SubValue> {
583        self.remove(&field)
584    }
585}
586
587/// Behavior for a category store whose values are just a single optional field key.
588impl<ObjKey, FieldKey, Field> Category<ObjKey, FieldKey, FieldKey, Field>
589where
590    ObjKey: Key,
591    FieldKey: Key,
592    Field: Clone + Debug + Ord,
593{
594    /// Get the current value expressed in terms of the external name.
595    pub fn value_name_of_object(&self, obj: ObjKey) -> Option<&Field> {
596        let key = self.object_value(obj)?;
597        self.field_name(*key)
598    }
599
600    /// Set the value expressed in terms of the external name.
601    pub fn set_value_name_of_object(&mut self, obj: ObjKey, value: Option<Cow<Field>>) {
602        if let Some(field) = value {
603            let field = self.field_key(field);
604            self.insert_object_value(obj, field);
605        } else {
606            self.remove_object(obj);
607        }
608    }
609}
610
611/// Behavior for a category store whose values are just a single optional field key.
612impl<ObjKey, FieldKey, Field> Category<ObjKey, Option<FieldKey>, FieldKey, Field>
613where
614    ObjKey: Key,
615    FieldKey: Key,
616    Field: Clone + Debug + Ord,
617{
618    /// Get the current value expressed in terms of the external name.
619    pub fn value_name_of_object(&self, obj: ObjKey) -> Option<&Field> {
620        let key = self.object_value(obj)?.as_ref()?;
621        self.field_name(*key)
622    }
623
624    /// Set the value expressed in terms of the external name.
625    pub fn set_value_name_of_object(&mut self, obj: ObjKey, value: Option<Cow<Field>>) {
626        if let Some(field) = value {
627            let field = self.field_key(field);
628            self.insert_object_value(obj, Some(field));
629        } else {
630            self.remove_object(obj);
631        }
632    }
633}
634
635/// Behavior for a category store whose values are a BTreeSet.
636impl<ObjKey, FieldKey, Field> Category<ObjKey, BTreeSet<FieldKey>, FieldKey, Field>
637where
638    ObjKey: Key,
639    FieldKey: Key,
640    Field: Clone + Debug + Ord,
641{
642    /// Get the current value expressed in references to field names.
643    pub fn named_value_of_object(&self, obj: ObjKey) -> BTreeSet<&Field> {
644        self.object_value(obj)
645            .into_iter()
646            .flat_map(|set| set.iter())
647            .flat_map(|key| self.field_name(*key))
648            .collect()
649    }
650}
651
652/// Behavior for a category store whose values are a BTreeMap with SubValues.
653impl<ObjKey, FieldKey, Field, SubValue>
654    Category<ObjKey, BTreeMap<FieldKey, SubValue>, FieldKey, Field>
655where
656    ObjKey: Key,
657    FieldKey: Key,
658    Field: Clone + Debug + Ord,
659{
660    /// Get the current value expressed in references to field names and values.
661    pub fn named_value_of_object(&self, obj: ObjKey) -> BTreeMap<&Field, &SubValue> {
662        self.object_value(obj)
663            .into_iter()
664            .flat_map(|mapping| mapping.iter())
665            .flat_map(|(key, value)| self.field_name(*key).map(|field| (field, value)))
666            .collect()
667    }
668}