1use crate::{
4 tt::prelude::*,
5 zero::{LabelSegment, QualifiedLabel, QualifiedName},
6};
7
8#[derive(Clone)]
13pub enum DtryEntry<T> {
14 File(T),
16 SubDir(Dtry<T>),
18}
19
20impl<T> DtryEntry<T> {
21 pub fn map<S>(&self, f: &impl Fn(&T) -> S) -> DtryEntry<S> {
24 match self {
25 DtryEntry::File(x) => DtryEntry::File(f(x)),
26 DtryEntry::SubDir(d) => DtryEntry::SubDir(d.map(f)),
27 }
28 }
29
30 fn singleton(path: &[(FieldName, LabelSegment)], val: T) -> Self {
31 if path.is_empty() {
32 DtryEntry::File(val)
33 } else {
34 DtryEntry::SubDir(Dtry::singleton(path, val))
35 }
36 }
37}
38
39impl<T: Clone> DtryEntry<T> {
40 fn flatten_into(
41 &self,
42 namespace: QualifiedName,
43 label_namespace: QualifiedLabel,
44 out: &mut Vec<(QualifiedName, QualifiedLabel, T)>,
45 ) {
46 match self {
47 DtryEntry::File(x) => out.push((namespace, label_namespace, x.clone())),
48 DtryEntry::SubDir(d) => d.flatten_into(namespace, label_namespace, out),
49 }
50 }
51}
52
53#[derive(Clone)]
69pub struct Dtry<T>(Row<DtryEntry<T>>);
70
71impl<T> Dtry<T> {
72 pub fn map<S>(&self, f: &impl Fn(&T) -> S) -> Dtry<S> {
75 Dtry(self.0.iter().map(|(name, (label, e))| (*name, (*label, e.map(f)))).collect())
76 }
77
78 pub fn empty() -> Dtry<T> {
80 Dtry(Row::empty())
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.0.is_empty()
86 }
87
88 pub fn entries(&self) -> impl Iterator<Item = (&FieldName, &(LabelSegment, DtryEntry<T>))> {
90 self.0.iter()
91 }
92
93 pub fn entry(&self, field: &FieldName) -> Option<&DtryEntry<T>> {
95 self.0.get(*field)
96 }
97
98 pub fn singleton(path: &[(FieldName, LabelSegment)], val: T) -> Self {
100 assert!(!path.is_empty());
101 let ((field, label), path) = (path[0], &path[1..]);
102 Dtry([(field, (label, DtryEntry::singleton(path, val)))].into_iter().collect())
103 }
104}
105
106impl<T: Clone> Dtry<T> {
107 pub fn flatten(&self) -> Vec<(QualifiedName, QualifiedLabel, T)> {
110 let mut out = Vec::new();
111 self.flatten_into(vec![].into(), vec![].into(), &mut out);
112 out
113 }
114
115 fn flatten_into(
116 &self,
117 namespace: QualifiedName,
118 label_namespace: QualifiedLabel,
119 out: &mut Vec<(QualifiedName, QualifiedLabel, T)>,
120 ) {
121 for (field, (label, entry)) in self.entries() {
122 entry.flatten_into(namespace.snoc(*field), label_namespace.snoc(*label), out)
123 }
124 }
125}
126
127impl<T> From<IndexMap<FieldName, (LabelSegment, DtryEntry<T>)>> for Dtry<T> {
128 fn from(value: IndexMap<FieldName, (LabelSegment, DtryEntry<T>)>) -> Self {
129 Self(value.into())
130 }
131}