Skip to main content

hara_native/lang/data/
set.rs

1use std::cell::Cell;
2use std::hash::Hash;
3
4use crate::lang::data::Map;
5use crate::lang::hash::JavaHash;
6use crate::lang::protocol::{
7    HashType, IColl, IConj, ICount, IDisplay, IDissoc, IEmpty, IEquality, IFind, IHash, IMetadata,
8    IMutable, IObjType, IPersistent, IToMutable, IToPersistent, ObjType,
9};
10
11#[derive(Debug, Clone)]
12pub struct Standard<E> {
13    lookup: Map<E, E>,
14}
15impl<E> Default for Standard<E> {
16    fn default() -> Self {
17        Self {
18            lookup: Map::default(),
19        }
20    }
21}
22impl<E: Clone + Eq + Hash> Standard<E> {
23    pub fn new() -> Self {
24        Self::default()
25    }
26    pub fn len(&self) -> usize {
27        self.lookup.len()
28    }
29    pub fn is_empty(&self) -> bool {
30        self.lookup.is_empty()
31    }
32    pub fn get(&self, value: &E) -> Option<&E> {
33        self.lookup.get(value)
34    }
35    pub fn contains(&self, value: &E) -> bool {
36        self.get(value).is_some()
37    }
38    pub fn conj_value(&self, value: E) -> Self {
39        Self {
40            lookup: self.lookup.assoc_value(value.clone(), value),
41        }
42    }
43    pub fn dissoc_value(&self, value: &E) -> Self {
44        Self {
45            lookup: self.lookup.dissoc_value(value),
46        }
47    }
48    pub fn iter(&self) -> impl Iterator<Item = &E> {
49        self.lookup.entries().into_iter().map(|(key, _)| key)
50    }
51}
52impl<E: Clone + Eq + Hash> FromIterator<E> for Standard<E> {
53    fn from_iter<T: IntoIterator<Item = E>>(iter: T) -> Self {
54        iter.into_iter()
55            .fold(Self::new(), |set, value| set.conj_value(value))
56    }
57}
58impl<E: Clone + Eq + Hash> IntoIterator for Standard<E> {
59    type Item = E;
60    type IntoIter = std::vec::IntoIter<E>;
61    fn into_iter(self) -> Self::IntoIter {
62        self.iter().cloned().collect::<Vec<_>>().into_iter()
63    }
64}
65impl<E: Clone + Eq + Hash> From<Vec<E>> for Standard<E> {
66    fn from(values: Vec<E>) -> Self {
67        values.into_iter().collect()
68    }
69}
70impl<E: Clone + Eq + Hash> PartialEq for Standard<E> {
71    fn eq(&self, other: &Self) -> bool {
72        self.len() == other.len() && self.iter().all(|v| other.get(v).is_some())
73    }
74}
75impl<E: Clone + Eq + Hash> ICount for Standard<E> {
76    fn count(&self) -> usize {
77        self.len()
78    }
79}
80impl<E: Clone + Eq + Hash> IFind<E> for Standard<E> {
81    type Output = E;
82    fn find(&self, key: &E) -> Option<E> {
83        self.get(key).cloned()
84    }
85}
86impl<E: Clone + Eq + Hash> IConj<E> for Standard<E> {
87    type Output = Self;
88    fn conj(&self, value: E) -> Self {
89        self.conj_value(value)
90    }
91}
92impl<E: Clone + Eq + Hash> IDissoc<E> for Standard<E> {
93    type Output = Self;
94    fn dissoc(&self, key: &E) -> Self {
95        self.dissoc_value(key)
96    }
97}
98impl<E: Clone + Eq + Hash> IEmpty for Standard<E> {
99    type Output = Self;
100    fn empty(&self) -> Self {
101        Self {
102            lookup: self.lookup.empty(),
103        }
104    }
105}
106impl<E: Clone + Eq + Hash> IMetadata for Standard<E> {
107    type Metadata = std::rc::Rc<crate::lang::data::Metadata>;
108    fn meta(&self) -> Option<&Self::Metadata> {
109        self.lookup.meta()
110    }
111    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
112        Self {
113            lookup: self.lookup.with_meta(metadata),
114        }
115    }
116}
117impl<E: Clone + Eq + Hash> IPersistent for Standard<E> {}
118impl<E: Clone + Eq + Hash> IEquality for Standard<E> {
119    fn equality(&self, other: &Self) -> bool {
120        self == other
121    }
122}
123impl<E: Clone + Eq + Hash + std::fmt::Debug> IDisplay for Standard<E> {
124    fn display(&self) -> String {
125        format!(
126            "#{{{}}}",
127            self.iter()
128                .map(|v| format!("{v:?}"))
129                .collect::<Vec<_>>()
130                .join(" ")
131        )
132    }
133}
134impl<E: Clone + Eq + Hash + JavaHash> IHash for Standard<E> {
135    fn hash_calc(&self, hash_type: HashType) -> u64 {
136        // Java ISetType → IUnOrderedType: order-insensitive sum,
137        // "::SET" seed (see lang::hash).
138        crate::lang::hash::compose_unordered("SET", self.iter().map(|v| v.java_hash(hash_type)))
139            as u64
140    }
141}
142impl<E: Clone + Eq + Hash + std::fmt::Debug> IObjType for Standard<E> {
143    fn obj_type(&self) -> ObjType {
144        ObjType::Set
145    }
146}
147impl<E> IColl<E> for Standard<E>
148where
149    E: Clone + Eq + Hash + JavaHash + std::fmt::Debug,
150{
151    fn start_string(&self) -> &'static str {
152        "#{"
153    }
154    fn end_string(&self) -> &'static str {
155        "}"
156    }
157}
158impl<E: Clone + Eq + Hash> IToMutable for Standard<E> {
159    type Mutable = Mutable<E>;
160    fn to_mutable(&self) -> Mutable<E> {
161        Mutable {
162            editable: Cell::new(true),
163            set: self.clone(),
164        }
165    }
166}
167#[derive(Debug, Clone)]
168pub struct Mutable<E> {
169    editable: Cell<bool>,
170    set: Standard<E>,
171}
172impl<E: Clone + Eq + Hash> Mutable<E> {
173    fn check(&self) {
174        assert!(self.editable.get(), "mutable set used after to_persistent")
175    }
176    pub fn conj(&mut self, value: E) -> &mut Self {
177        self.check();
178        self.set = self.set.conj_value(value);
179        self
180    }
181    pub fn dissoc(&mut self, value: &E) -> &mut Self {
182        self.check();
183        self.set = self.set.dissoc_value(value);
184        self
185    }
186}
187impl<E: Clone + Eq + Hash> std::ops::Deref for Mutable<E> {
188    type Target = Standard<E>;
189    fn deref(&self) -> &Self::Target {
190        self.check();
191        &self.set
192    }
193}
194impl<E> IMutable for Mutable<E> {}
195impl<E: Clone + Eq + Hash> IToPersistent for Mutable<E> {
196    type Persistent = Standard<E>;
197    fn to_persistent(&mut self) -> Standard<E> {
198        self.check();
199        self.editable.set(false);
200        self.set.clone()
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::Standard;
207    #[test]
208    fn persistent_operations_preserve_metadata() {
209        use crate::lang::protocol::{IEmpty, IMetadata};
210        let set = Standard::from(vec![1, 2])
211            .with_meta(Some(crate::lang::data::Metadata::document("doc")));
212        for value in [set.conj_value(3), set.dissoc_value(&1), set.empty()] {
213            assert_eq!(value.meta().map(|m| m.doc().unwrap()), Some("doc"));
214        }
215    }
216
217    #[test]
218    fn is_map_backed_unique_and_persistent() {
219        let a = [1, 2, 2].into_iter().collect::<Standard<_>>();
220        let b = a.conj_value(3);
221        let c = b.dissoc_value(&2);
222        assert_eq!(a.len(), 2);
223        assert_eq!(b.len(), 3);
224        assert!(c.get(&2).is_none());
225        assert!(a.get(&2).is_some());
226    }
227}