Skip to main content

hara_native/lang/data/
sorted_map.rs

1//! Persistent sorted map: a weight-recorded red-black tree ported from
2//! `java/src/main/java/hara/lang/data/SortedMap.java`.
3//!
4//! Leaf modelling: Java uses two non-null leaf sentinels (`EMPTY_NODE`,
5//! colour BLACK, and `DOUBLE_EMPTY_NODE`, colour DOUBLE_BLACK; both size 0)
6//! so the delete rebalancer can push a "double black" up from a removed
7//! leaf. Rust has no null links, so the child link itself is the three-state
8//! enum [`Link`]: `Empty`/`DoubleEmpty` are the two size-0 leaves and
9//! `Full(Rc<Node>)` is an internal node. Every colour test in
10//! `balance`/`rotate` is then a direct transcription of the Java code.
11
12use std::cell::Cell;
13use std::cmp::Ordering;
14use std::rc::Rc;
15
16use crate::lang::hash::JavaHash;
17use crate::lang::protocol::{
18    HashType, IAssoc, IColl, IConj, ICount, IDisplay, IDissoc, IEmpty, IEquality, IFind, IHash,
19    IIndexedKV, ILookup, IMetadata, IMutable, INth, IObjType, IPersistent, IToMutable,
20    IToPersistent, MetaType, ObjType,
21};
22
23/// Java `SortedMap.Color`; DOUBLE_BLACK only exists transiently during delete.
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25enum Color {
26    Red,
27    Black,
28    DoubleBlack,
29}
30use Color::{Black, DoubleBlack, Red};
31
32/// Child link: the two size-0 leaf sentinels or an internal node.
33#[derive(Debug, Clone)]
34enum Link<K, V> {
35    /// Java `Node.EMPTY_NODE` (BLACK, size 0).
36    Empty,
37    /// Java `Node.DOUBLE_EMPTY_NODE` (DOUBLE_BLACK, size 0).
38    DoubleEmpty,
39    Full(Rc<Node<K, V>>),
40}
41
42#[derive(Debug, Clone)]
43pub struct Node<K, V> {
44    pub key: K,
45    pub value: V,
46    color: Color,
47    left: Link<K, V>,
48    right: Link<K, V>,
49    size: usize,
50}
51
52impl<K, V> Link<K, V> {
53    fn color(&self) -> Color {
54        match self {
55            Link::Empty => Black,
56            Link::DoubleEmpty => DoubleBlack,
57            Link::Full(node) => node.color,
58        }
59    }
60    fn size(&self) -> usize {
61        match self {
62            Link::Full(node) => node.size,
63            _ => 0,
64        }
65    }
66}
67
68/// Java `S.node`: weight-recorded constructor, size = l.size + r.size + 1.
69fn node<K, V>(color: Color, left: Link<K, V>, key: K, value: V, right: Link<K, V>) -> Link<K, V> {
70    Link::Full(Rc::new(Node {
71        size: left.size() + right.size() + 1,
72        color,
73        left,
74        key,
75        value,
76        right,
77    }))
78}
79fn red<K, V>(left: Link<K, V>, key: K, value: V, right: Link<K, V>) -> Link<K, V> {
80    node(Red, left, key, value, right)
81}
82fn black<K, V>(left: Link<K, V>, key: K, value: V, right: Link<K, V>) -> Link<K, V> {
83    node(Black, left, key, value, right)
84}
85
86/// Java `Node.redden`: BLACK with two BLACK children becomes RED (delete prep).
87fn redden<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
88    match link {
89        Link::Full(n)
90            if n.color == Black && n.left.color() == Black && n.right.color() == Black =>
91        {
92            red(
93                n.left.clone(),
94                n.key.clone(),
95                n.value.clone(),
96                n.right.clone(),
97            )
98        }
99        _ => link.clone(),
100    }
101}
102/// Java `Node.blacken`: RED becomes BLACK.
103fn blacken<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
104    match link {
105        Link::Full(n) if n.color == Red => black(
106            n.left.clone(),
107            n.key.clone(),
108            n.value.clone(),
109            n.right.clone(),
110        ),
111        _ => link.clone(),
112    }
113}
114/// Java `Node.unblacken`: DOUBLE_BLACK becomes BLACK (also maps the
115/// double-empty leaf back to the plain empty leaf).
116fn unblacken<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
117    match link {
118        Link::DoubleEmpty => Link::Empty,
119        Link::Full(n) if n.color == DoubleBlack => black(
120            n.left.clone(),
121            n.key.clone(),
122            n.value.clone(),
123            n.right.clone(),
124        ),
125        _ => link.clone(),
126    }
127}
128
129/// Java `Node.put` with assoc's merge `(o, n) -> n`: recursive put, root
130/// blackened on the way out.
131fn put<K: Clone + Ord, V: Clone>(root: &Link<K, V>, key: K, value: V) -> Link<K, V> {
132    blacken(&put_rec(root, key, value))
133}
134fn put_rec<K: Clone + Ord, V: Clone>(link: &Link<K, V>, key: K, value: V) -> Link<K, V> {
135    match link {
136        // empty slot -> RED node (BLACK when the slot was double-empty)
137        Link::Empty => red(Link::Empty, key, value, Link::Empty),
138        Link::DoubleEmpty => black(Link::Empty, key, value, Link::Empty),
139        Link::Full(n) => match key.cmp(&n.key) {
140            Ordering::Less => balance(node(
141                n.color,
142                put_rec(&n.left, key, value),
143                n.key.clone(),
144                n.value.clone(),
145                n.right.clone(),
146            )),
147            Ordering::Greater => balance(node(
148                n.color,
149                n.left.clone(),
150                n.key.clone(),
151                n.value.clone(),
152                put_rec(&n.right, key, value),
153            )),
154            Ordering::Equal => node(n.color, n.left.clone(), key, value, n.right.clone()),
155        },
156    }
157}
158
159/// Java `Node.remove`: redden the root, recursive remove; an unchanged size
160/// means the key was absent, so keep the original (non-reddened) root.
161fn remove<K: Clone + Ord, V: Clone>(root: &Link<K, V>, key: &K) -> Link<K, V> {
162    let result = remove_rec(&redden(root), key);
163    if result.size() == root.size() {
164        root.clone()
165    } else {
166        result
167    }
168}
169fn remove_rec<K: Clone + Ord, V: Clone>(link: &Link<K, V>, key: &K) -> Link<K, V> {
170    let Link::Full(n) = link else {
171        return link.clone();
172    };
173    match key.cmp(&n.key) {
174        Ordering::Less => rotate(node(
175            n.color,
176            remove_rec(&n.left, key),
177            n.key.clone(),
178            n.value.clone(),
179            n.right.clone(),
180        )),
181        Ordering::Greater => rotate(node(
182            n.color,
183            n.left.clone(),
184            n.key.clone(),
185            n.value.clone(),
186            remove_rec(&n.right, key),
187        )),
188        Ordering::Equal => {
189            if n.size == 1 {
190                // leaf removal: RED leaves vanish, BLACK leaves go double-black
191                if n.color == Black {
192                    Link::DoubleEmpty
193                } else {
194                    Link::Empty
195                }
196            } else if n.right.size() == 0 {
197                blacken(&n.left)
198            } else {
199                let min = leftmost(&n.right);
200                rotate(node(
201                    n.color,
202                    n.left.clone(),
203                    min.key.clone(),
204                    min.value.clone(),
205                    remove_min(&n.right),
206                ))
207            }
208        }
209    }
210}
211
212/// Java `S.min`: leftmost node of a non-empty subtree.
213fn leftmost<K, V>(link: &Link<K, V>) -> &Rc<Node<K, V>> {
214    let Link::Full(n) = link else {
215        unreachable!("min of an empty subtree")
216    };
217    match &n.left {
218        Link::Full(_) => leftmost(&n.left),
219        _ => n,
220    }
221}
222
223/// Java `Node.removeMin`: mirror of `remove_rec`, rotating on the way up.
224fn remove_min<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
225    let Link::Full(n) = link else {
226        return link.clone();
227    };
228    if n.left.size() == 0 {
229        return match n.color {
230            Red => Link::Empty,
231            _ if n.right.size() == 0 => Link::DoubleEmpty,
232            _ => blacken(&n.right),
233        };
234    }
235    rotate(node(
236        n.color,
237        remove_min(&n.left),
238        n.key.clone(),
239        n.value.clone(),
240        n.right.clone(),
241    ))
242}
243
244/// Java `Node.balance`: BLACK -> balanceBlack, DOUBLE_BLACK ->
245/// balanceDoubleBlack, RED and the leaves pass through.
246fn balance<K: Clone, V: Clone>(link: Link<K, V>) -> Link<K, V> {
247    let Link::Full(_) = link else {
248        return link;
249    };
250    match link.color() {
251        Black => balance_black(&link),
252        DoubleBlack => balance_double_black(&link),
253        Red => link,
254    }
255}
256
257/// Java `Node.balanceBlack`: the four classic Okasaki red-red cases.
258fn balance_black<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
259    let Link::Full(n) = link else {
260        return link.clone();
261    };
262    if let Link::Full(l) = &n.left {
263        if l.color == Red {
264            // (B (R (R a x b) y c) z d) -> (R (B a x b) y (B c z d))
265            if let Link::Full(ll) = &l.left {
266                if ll.color == Red {
267                    return red(
268                        blacken(&l.left),
269                        l.key.clone(),
270                        l.value.clone(),
271                        black(
272                            l.right.clone(),
273                            n.key.clone(),
274                            n.value.clone(),
275                            n.right.clone(),
276                        ),
277                    );
278                }
279            }
280            // (B (R a x (R b y c)) z d) -> (R (B a x b) y (B c z d))
281            if let Link::Full(lr) = &l.right {
282                if lr.color == Red {
283                    return red(
284                        black(
285                            l.left.clone(),
286                            l.key.clone(),
287                            l.value.clone(),
288                            lr.left.clone(),
289                        ),
290                        lr.key.clone(),
291                        lr.value.clone(),
292                        black(
293                            lr.right.clone(),
294                            n.key.clone(),
295                            n.value.clone(),
296                            n.right.clone(),
297                        ),
298                    );
299                }
300            }
301        }
302    }
303    if let Link::Full(r) = &n.right {
304        if r.color == Red {
305            // (B a x (R (R b y c) z d)) -> (R (B a x b) y (B c z d))
306            if let Link::Full(rl) = &r.left {
307                if rl.color == Red {
308                    return red(
309                        black(
310                            n.left.clone(),
311                            n.key.clone(),
312                            n.value.clone(),
313                            rl.left.clone(),
314                        ),
315                        rl.key.clone(),
316                        rl.value.clone(),
317                        black(
318                            rl.right.clone(),
319                            r.key.clone(),
320                            r.value.clone(),
321                            r.right.clone(),
322                        ),
323                    );
324                }
325            }
326            // (B a x (R b y (R c z d))) -> (R (B a x b) y (B c z d))
327            if let Link::Full(rr) = &r.right {
328                if rr.color == Red {
329                    return red(
330                        black(
331                            n.left.clone(),
332                            n.key.clone(),
333                            n.value.clone(),
334                            r.left.clone(),
335                        ),
336                        r.key.clone(),
337                        r.value.clone(),
338                        blacken(&r.right),
339                    );
340                }
341            }
342        }
343    }
344    link.clone()
345}
346
347/// Java `Node.balanceDoubleBlack`: the two red-red cases under a double black.
348fn balance_double_black<K: Clone, V: Clone>(link: &Link<K, V>) -> Link<K, V> {
349    let Link::Full(n) = link else {
350        return link.clone();
351    };
352    // (BB (R a x (R b y c)) z d) -> (B (B a x b) y (B c z d))
353    if let Link::Full(l) = &n.left {
354        if l.color == Red {
355            if let Link::Full(lr) = &l.right {
356                if lr.color == Red {
357                    return black(
358                        black(
359                            l.left.clone(),
360                            l.key.clone(),
361                            l.value.clone(),
362                            lr.left.clone(),
363                        ),
364                        lr.key.clone(),
365                        lr.value.clone(),
366                        black(
367                            lr.right.clone(),
368                            n.key.clone(),
369                            n.value.clone(),
370                            n.right.clone(),
371                        ),
372                    );
373                }
374            }
375        }
376    }
377    // (BB a x (R (R b y c) z d)) -> (B (B a x b) y (B c z d))
378    if let Link::Full(r) = &n.right {
379        if r.color == Red {
380            if let Link::Full(rl) = &r.left {
381                if rl.color == Red {
382                    return black(
383                        black(
384                            n.left.clone(),
385                            n.key.clone(),
386                            n.value.clone(),
387                            rl.left.clone(),
388                        ),
389                        rl.key.clone(),
390                        rl.value.clone(),
391                        black(
392                            rl.right.clone(),
393                            r.key.clone(),
394                            r.value.clone(),
395                            r.right.clone(),
396                        ),
397                    );
398                }
399            }
400        }
401    }
402    link.clone()
403}
404
405/// Java `Node.rotate`: the double-black rebalancer, six pattern cases, each
406/// ending in `balance`. Called on every return path of remove/removeMin.
407fn rotate<K: Clone, V: Clone>(link: Link<K, V>) -> Link<K, V> {
408    let Link::Full(n) = &link else {
409        return link;
410    };
411    match n.color {
412        Red => {
413            // (R (BB? a-x-b) y (B c z d)) -> (balance (B (R (-B a-x-b) y c) z d))
414            if n.left.color() == DoubleBlack && n.right.color() == Black {
415                let Link::Full(r) = &n.right else {
416                    unreachable!("sibling of a double black must be an internal node")
417                };
418                return balance(black(
419                    red(
420                        unblacken(&n.left),
421                        n.key.clone(),
422                        n.value.clone(),
423                        r.left.clone(),
424                    ),
425                    r.key.clone(),
426                    r.value.clone(),
427                    r.right.clone(),
428                ));
429            }
430            // (R (B a x b) y (BB? c-z-d)) -> (balance (B a x (R b y (-B c-z-d))))
431            if n.right.color() == DoubleBlack && n.left.color() == Black {
432                let Link::Full(l) = &n.left else {
433                    unreachable!("sibling of a double black must be an internal node")
434                };
435                return balance(black(
436                    l.left.clone(),
437                    l.key.clone(),
438                    l.value.clone(),
439                    red(
440                        l.right.clone(),
441                        n.key.clone(),
442                        n.value.clone(),
443                        unblacken(&n.right),
444                    ),
445                ));
446            }
447        }
448        Black => {
449            // (B (BB? a-x-b) y (B c z d)) -> (balance (BB (R (-B a-x-b) y c) z d))
450            if n.left.color() == DoubleBlack && n.right.color() == Black {
451                let Link::Full(r) = &n.right else {
452                    unreachable!("sibling of a double black must be an internal node")
453                };
454                return balance(node(
455                    DoubleBlack,
456                    red(
457                        unblacken(&n.left),
458                        n.key.clone(),
459                        n.value.clone(),
460                        r.left.clone(),
461                    ),
462                    r.key.clone(),
463                    r.value.clone(),
464                    r.right.clone(),
465                ));
466            }
467            // (B (B a x b) y (BB? c-z-d)) -> (balance (BB a x (R b y (-B c-z-d))))
468            if n.left.color() == Black && n.right.color() == DoubleBlack {
469                let Link::Full(l) = &n.left else {
470                    unreachable!("sibling of a double black must be an internal node")
471                };
472                return balance(node(
473                    DoubleBlack,
474                    l.left.clone(),
475                    l.key.clone(),
476                    l.value.clone(),
477                    red(
478                        l.right.clone(),
479                        n.key.clone(),
480                        n.value.clone(),
481                        unblacken(&n.right),
482                    ),
483                ));
484            }
485            // (B (BB? a-w-b) x (R (B c y d) z e))
486            // -> (B (balance (B (R (-B a-w-b) x c) y d)) z e)
487            if n.left.color() == DoubleBlack && n.right.color() == Red {
488                let Link::Full(r) = &n.right else {
489                    unreachable!("sibling of a double black must be an internal node")
490                };
491                if let Link::Full(rl) = &r.left {
492                    if rl.color == Black {
493                        return black(
494                            balance(black(
495                                red(
496                                    unblacken(&n.left),
497                                    n.key.clone(),
498                                    n.value.clone(),
499                                    rl.left.clone(),
500                                ),
501                                rl.key.clone(),
502                                rl.value.clone(),
503                                rl.right.clone(),
504                            )),
505                            r.key.clone(),
506                            r.value.clone(),
507                            r.right.clone(),
508                        );
509                    }
510                }
511            }
512            // (B (R a w (B b x c)) y (BB? d-z-e))
513            // -> (B a w (balance (B b x (R c y (-B d-z-e)))))
514            if n.left.color() == Red && n.right.color() == DoubleBlack {
515                let Link::Full(l) = &n.left else {
516                    unreachable!("sibling of a double black must be an internal node")
517                };
518                if let Link::Full(lr) = &l.right {
519                    if lr.color == Black {
520                        return black(
521                            l.left.clone(),
522                            l.key.clone(),
523                            l.value.clone(),
524                            balance(black(
525                                lr.left.clone(),
526                                lr.key.clone(),
527                                lr.value.clone(),
528                                red(
529                                    lr.right.clone(),
530                                    n.key.clone(),
531                                    n.value.clone(),
532                                    unblacken(&n.right),
533                                ),
534                            )),
535                        );
536                    }
537                }
538            }
539        }
540        DoubleBlack => {}
541    }
542    link.clone()
543}
544
545/// Java `Node.floorIndex`: rank of the greatest key <= probe, None if none.
546fn floor_index<K: Ord, V>(link: &Link<K, V>, key: &K, offset: usize) -> Option<usize> {
547    let Link::Full(n) = link else {
548        return None;
549    };
550    match key.cmp(&n.key) {
551        Ordering::Greater => {
552            floor_index(&n.right, key, offset + n.left.size() + 1).or(Some(offset + n.left.size()))
553        }
554        Ordering::Less => floor_index(&n.left, key, offset),
555        Ordering::Equal => Some(offset + n.left.size()),
556    }
557}
558
559/// Java `Node.ceilIndex`: rank of the smallest key >= probe, None if none.
560fn ceil_index<K: Ord, V>(link: &Link<K, V>, key: &K, offset: usize) -> Option<usize> {
561    let Link::Full(n) = link else {
562        return None;
563    };
564    match key.cmp(&n.key) {
565        Ordering::Greater => ceil_index(&n.right, key, offset + n.left.size() + 1),
566        Ordering::Less => ceil_index(&n.left, key, offset).or(Some(offset + n.left.size())),
567        Ordering::Equal => Some(offset + n.left.size()),
568    }
569}
570
571/// Java `Node.slice`: keep nodes with min <= k <= max, pruning the rest
572/// (the static `S.slice` in Java is a dead stub and is not ported).
573fn slice<K: Clone + Ord, V: Clone>(link: &Link<K, V>, min: &K, max: &K) -> Link<K, V> {
574    let Link::Full(n) = link else {
575        return link.clone();
576    };
577    match (n.key.cmp(min), n.key.cmp(max)) {
578        (Ordering::Less, _) => slice(&n.right, min, max),
579        (_, Ordering::Greater) => slice(&n.left, min, max),
580        _ => rotate(node(
581            n.color,
582            slice(&n.left, min, max),
583            n.key.clone(),
584            n.value.clone(),
585            slice(&n.right, min, max),
586        )),
587    }
588}
589
590/// Java `Node.mapValues`: same shape and colours, mapped values.
591fn map_values<K: Clone, V, U>(link: &Link<K, V>, f: &impl Fn(&K, &V) -> U) -> Link<K, U> {
592    match link {
593        Link::Empty => Link::Empty,
594        Link::DoubleEmpty => Link::DoubleEmpty,
595        Link::Full(n) => node(
596            n.color,
597            map_values(&n.left, f),
598            n.key.clone(),
599            f(&n.key, &n.value),
600            map_values(&n.right, f),
601        ),
602    }
603}
604
605/// Java `Node.checkInvariant`: black-height and no-red-red validation, plus
606/// the weight record (size field). Panics on any violation.
607#[cfg(test)]
608fn check_invariant<K, V>(link: &Link<K, V>) -> usize {
609    assert_ne!(link.color(), DoubleBlack, "double black left in tree");
610    let Link::Full(n) = link else {
611        return 1;
612    };
613    assert!(
614        n.color != Red || (n.left.color() != Red && n.right.color() != Red),
615        "red-red violation"
616    );
617    let left_depth = check_invariant(&n.left);
618    let right_depth = check_invariant(&n.right);
619    assert_eq!(left_depth, right_depth, "black-height violation");
620    assert_eq!(
621        n.size,
622        n.left.size() + n.right.size() + 1,
623        "size record violation"
624    );
625    left_depth + usize::from(n.color == Black)
626}
627
628#[derive(Debug, Clone)]
629pub struct Standard<K, V> {
630    metadata: Option<Rc<crate::lang::data::Metadata>>,
631    root: Link<K, V>,
632}
633impl<K, V> Default for Standard<K, V> {
634    fn default() -> Self {
635        Self {
636            metadata: None,
637            root: Link::Empty,
638        }
639    }
640}
641impl<K: Clone + Ord, V: Clone> Standard<K, V> {
642    pub fn new() -> Self {
643        Self::default()
644    }
645    pub fn len(&self) -> usize {
646        self.root.size()
647    }
648    pub fn is_empty(&self) -> bool {
649        self.root.size() == 0
650    }
651    pub fn get(&self, key: &K) -> Option<&V> {
652        self.find_entry(key).map(|(_, value)| value)
653    }
654    /// Java `S.find`.
655    pub fn find_entry(&self, key: &K) -> Option<(&K, &V)> {
656        let mut cursor = &self.root;
657        while let Link::Full(current) = cursor {
658            match key.cmp(&current.key) {
659                Ordering::Less => cursor = &current.left,
660                Ordering::Greater => cursor = &current.right,
661                Ordering::Equal => return Some((&current.key, &current.value)),
662            }
663        }
664        None
665    }
666    pub fn assoc_value(&self, key: K, value: V) -> Self {
667        Self {
668            metadata: self.metadata.clone(),
669            root: put(&self.root, key, value),
670        }
671    }
672    pub fn dissoc_value(&self, key: &K) -> Self {
673        Self {
674            metadata: self.metadata.clone(),
675            root: remove(&self.root, key),
676        }
677    }
678    pub fn iter(&self) -> Iter<'_, K, V> {
679        Iter::new(&self.root)
680    }
681    /// Java `Base.nth` (order-statistic select), bounds-checked.
682    pub fn nth_entry(&self, mut index: usize) -> Option<&Node<K, V>> {
683        let mut cursor = &self.root;
684        while let Link::Full(current) = cursor {
685            let left_size = current.left.size();
686            if index < left_size {
687                cursor = &current.left;
688            } else if index == left_size {
689                return Some(current);
690            } else {
691                index -= left_size + 1;
692                cursor = &current.right;
693            }
694        }
695        None
696    }
697    /// Java `S.indexOf` (order-statistic rank).
698    pub fn index_of_key(&self, key: &K) -> Option<usize> {
699        let mut offset = 0;
700        let mut cursor = &self.root;
701        while let Link::Full(current) = cursor {
702            match key.cmp(&current.key) {
703                Ordering::Less => cursor = &current.left,
704                Ordering::Greater => {
705                    offset += current.left.size() + 1;
706                    cursor = &current.right;
707                }
708                Ordering::Equal => return Some(offset + current.left.size()),
709            }
710        }
711        None
712    }
713    /// Java `Base.inclusiveFloorIndex`.
714    pub fn inclusive_floor_index(&self, key: &K) -> Option<usize> {
715        floor_index(&self.root, key, 0)
716    }
717    /// Java `Base.ceilIndex`.
718    pub fn ceil_index(&self, key: &K) -> Option<usize> {
719        ceil_index(&self.root, key, 0)
720    }
721    pub fn slice(&self, min: &K, max: &K) -> Self {
722        Self {
723            metadata: self.metadata.clone(),
724            root: slice(&self.root, min, max),
725        }
726    }
727    pub fn map_values<U: Clone>(&self, f: impl Fn(&K, &V) -> U) -> Standard<K, U> {
728        Standard {
729            metadata: self.metadata.clone(),
730            root: map_values(&self.root, &f),
731        }
732    }
733}
734impl<K: Clone + Ord, V: Clone> FromIterator<(K, V)> for Standard<K, V> {
735    fn from_iter<T: IntoIterator<Item = (K, V)>>(it: T) -> Self {
736        it.into_iter()
737            .fold(Self::new(), |m, (k, v)| m.assoc_value(k, v))
738    }
739}
740impl<K: Clone + Ord, V: Clone> ICount for Standard<K, V> {
741    fn count(&self) -> usize {
742        self.len()
743    }
744}
745impl<K: Clone + Ord, V: Clone> IFind<K> for Standard<K, V> {
746    type Output = (K, V);
747    fn find(&self, k: &K) -> Option<Self::Output> {
748        self.find_entry(k).map(|(k, v)| (k.clone(), v.clone()))
749    }
750}
751impl<K: Clone + Ord, V: Clone> ILookup<K, V> for Standard<K, V> {
752    type Keys = std::vec::IntoIter<K>;
753    type Values = std::vec::IntoIter<V>;
754    fn keys(&self) -> Self::Keys {
755        self.iter()
756            .map(|(k, _)| k.clone())
757            .collect::<Vec<_>>()
758            .into_iter()
759    }
760    fn vals(&self) -> Self::Values {
761        self.iter()
762            .map(|(_, v)| v.clone())
763            .collect::<Vec<_>>()
764            .into_iter()
765    }
766}
767impl<K: Clone + Ord, V: Clone> IAssoc<K, V> for Standard<K, V> {
768    type Output = Self;
769    fn assoc(&self, k: K, v: V) -> Self {
770        self.assoc_value(k, v)
771    }
772}
773impl<K: Clone + Ord, V: Clone> IDissoc<K> for Standard<K, V> {
774    type Output = Self;
775    fn dissoc(&self, k: &K) -> Self {
776        self.dissoc_value(k)
777    }
778}
779impl<K: Clone + Ord, V: Clone> INth<Node<K, V>> for Standard<K, V> {
780    fn nth(&self, index: usize) -> Option<&Node<K, V>> {
781        self.nth_entry(index)
782    }
783}
784impl<K: Clone + Ord, V: Clone + PartialEq> IIndexedKV<K, V> for Standard<K, V> {
785    fn index_of_key(&self, key: &K) -> Option<usize> {
786        Standard::index_of_key(self, key)
787    }
788    fn index_of_val(&self, value: &V) -> Option<usize> {
789        self.iter().position(|(_, candidate)| candidate == value)
790    }
791}
792impl<K: Clone + Ord, V: Clone> IEmpty for Standard<K, V> {
793    type Output = Self;
794    fn empty(&self) -> Self {
795        Self::new().with_meta(self.metadata.clone())
796    }
797}
798impl<K: Clone + Ord, V: Clone> IMetadata for Standard<K, V> {
799    type Metadata = Rc<crate::lang::data::Metadata>;
800    fn meta(&self) -> Option<&Self::Metadata> {
801        self.metadata.as_ref()
802    }
803    fn with_meta(&self, metadata: Option<Self::Metadata>) -> Self {
804        Self {
805            metadata,
806            ..self.clone()
807        }
808    }
809
810    fn metatype(&self) -> MetaType {
811        MetaType::Map
812    }
813}
814impl<K: Clone + Ord, V: Clone> IPersistent for Standard<K, V> {}
815impl<K: Clone + Ord, V: Clone> IntoIterator for Standard<K, V> {
816    type Item = (K, V);
817    type IntoIter = std::vec::IntoIter<(K, V)>;
818    fn into_iter(self) -> Self::IntoIter {
819        self.iter()
820            .map(|(k, v)| (k.clone(), v.clone()))
821            .collect::<Vec<_>>()
822            .into_iter()
823    }
824}
825impl<K: Clone + Ord, V: Clone> IConj<(K, V)> for Standard<K, V> {
826    type Output = Self;
827    fn conj(&self, (k, v): (K, V)) -> Self {
828        self.assoc_value(k, v)
829    }
830}
831impl<K: Clone + Ord, V: Clone + PartialEq> IEquality for Standard<K, V> {
832    fn equality(&self, other: &Self) -> bool {
833        self.len() == other.len() && self.iter().all(|(k, v)| other.get(k) == Some(v))
834    }
835}
836impl<K: Clone + Ord + std::fmt::Debug, V: Clone + std::fmt::Debug> IDisplay for Standard<K, V> {
837    fn display(&self) -> String {
838        format!(
839            "{{{}}}",
840            self.iter()
841                .map(|(k, v)| format!("{k:?} {v:?}"))
842                .collect::<Vec<_>>()
843                .join(" ")
844        )
845    }
846}
847impl<K: Clone + Ord + std::hash::Hash + JavaHash, V: Clone + std::hash::Hash + JavaHash> IHash
848    for Standard<K, V>
849{
850    fn hash_calc(&self, hash_type: HashType) -> u64 {
851        // Same composition as the hash map (Java IMapType → IUnOrderedType):
852        // "::MAP" seed, sum of ordered-entry hashes (see lang::hash).
853        crate::lang::hash::compose_unordered(
854            "MAP",
855            self.iter().map(|(k, v)| {
856                crate::lang::hash::compose_entry(k.java_hash(hash_type), v.java_hash(hash_type))
857            }),
858        ) as u64
859    }
860}
861impl<K: Clone + Ord + std::fmt::Debug, V: Clone + std::fmt::Debug> IObjType for Standard<K, V> {
862    fn obj_type(&self) -> ObjType {
863        ObjType::Map
864    }
865}
866impl<K, V> IColl<(K, V)> for Standard<K, V>
867where
868    K: Clone + Ord + std::hash::Hash + JavaHash + std::fmt::Debug,
869    V: Clone + PartialEq + std::hash::Hash + JavaHash + std::fmt::Debug,
870{
871    fn start_string(&self) -> &'static str {
872        "{"
873    }
874    fn end_string(&self) -> &'static str {
875        "}"
876    }
877}
878impl<K: Clone + Ord, V: Clone> IToMutable for Standard<K, V> {
879    type Mutable = Mutable<K, V>;
880    fn to_mutable(&self) -> Self::Mutable {
881        Mutable {
882            editable: Cell::new(true),
883            map: self.clone(),
884        }
885    }
886}
887
888/// In-order iterator over an explicit stack (Java uses a fixed [64] stack
889/// and precomputes depth; a Vec stack is the Rust-idiomatic equivalent).
890pub struct Iter<'a, K, V> {
891    stack: Vec<&'a Node<K, V>>,
892}
893impl<'a, K, V> Iter<'a, K, V> {
894    fn new(root: &'a Link<K, V>) -> Self {
895        let mut it = Self { stack: Vec::new() };
896        it.push_left(root);
897        it
898    }
899    fn push_left(&mut self, mut link: &'a Link<K, V>) {
900        while let Link::Full(current) = link {
901            self.stack.push(&**current);
902            link = &current.left;
903        }
904    }
905}
906impl<'a, K, V> Iterator for Iter<'a, K, V> {
907    type Item = (&'a K, &'a V);
908    fn next(&mut self) -> Option<Self::Item> {
909        let n = self.stack.pop()?;
910        self.push_left(&n.right);
911        Some((&n.key, &n.value))
912    }
913}
914
915#[derive(Debug, Clone)]
916pub struct Mutable<K, V> {
917    editable: Cell<bool>,
918    map: Standard<K, V>,
919}
920impl<K: Clone + Ord, V: Clone> Mutable<K, V> {
921    fn check(&self) {
922        assert!(
923            self.editable.get(),
924            "mutable sorted map used after to_persistent"
925        )
926    }
927    pub fn assoc(&mut self, k: K, v: V) -> &mut Self {
928        self.check();
929        self.map = self.map.assoc_value(k, v);
930        self
931    }
932    pub fn dissoc(&mut self, k: &K) -> &mut Self {
933        self.check();
934        self.map = self.map.dissoc_value(k);
935        self
936    }
937}
938impl<K: Clone + Ord, V: Clone> std::ops::Deref for Mutable<K, V> {
939    type Target = Standard<K, V>;
940    fn deref(&self) -> &Self::Target {
941        self.check();
942        &self.map
943    }
944}
945impl<K, V> IMutable for Mutable<K, V> {}
946impl<K: Clone + Ord, V: Clone> IToPersistent for Mutable<K, V> {
947    type Persistent = Standard<K, V>;
948    fn to_persistent(&mut self) -> Self::Persistent {
949        self.check();
950        self.editable.set(false);
951        self.map.clone()
952    }
953}
954
955#[cfg(test)]
956mod tests {
957    use super::{check_invariant, Link, Standard};
958    use std::collections::BTreeMap;
959
960    /// splitmix64: deterministic RNG for the churn fuzzes (no new crates).
961    struct Rng(u64);
962    impl Rng {
963        fn next(&mut self) -> u64 {
964            self.0 = self.0.wrapping_add(0x9E3779B97F4A7C15);
965            let mut z = self.0;
966            z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
967            z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
968            z ^ (z >> 31)
969        }
970        fn below(&mut self, n: u64) -> u64 {
971            self.next() % n
972        }
973    }
974
975    #[test]
976    fn tree_updates_slices_maps_empty_and_mutable_preserve_metadata() {
977        use crate::lang::protocol::{IEmpty, IMetadata, IToMutable, IToPersistent};
978        let map = [(1, 10), (2, 20), (3, 30)]
979            .into_iter()
980            .collect::<Standard<_, _>>()
981            .with_meta(Some(crate::lang::data::Metadata::document("doc")));
982        assert_eq!(
983            map.assoc_value(4, 40).meta().map(|m| m.doc().unwrap()),
984            Some("doc")
985        );
986        assert_eq!(
987            map.dissoc_value(&1).meta().map(|m| m.doc().unwrap()),
988            Some("doc")
989        );
990        assert_eq!(
991            map.slice(&1, &2).meta().map(|m| m.doc().unwrap()),
992            Some("doc")
993        );
994        assert_eq!(
995            map.map_values(|_, value| value + 1)
996                .meta()
997                .map(|m| m.doc().unwrap()),
998            Some("doc")
999        );
1000        assert_eq!(map.empty().meta().map(|m| m.doc().unwrap()), Some("doc"));
1001        let mut mutable = map.to_mutable();
1002        mutable.assoc(4, 40);
1003        assert_eq!(
1004            mutable.to_persistent().meta().map(|m| m.doc().unwrap()),
1005            Some("doc")
1006        );
1007    }
1008
1009    #[test]
1010    fn stays_sorted_indexed_and_persistent() {
1011        let a = [(5, "e"), (1, "a"), (3, "c"), (2, "b"), (4, "d")]
1012            .into_iter()
1013            .collect::<Standard<_, _>>();
1014        assert_eq!(
1015            a.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
1016            vec![1, 2, 3, 4, 5]
1017        );
1018        assert_eq!(a.index_of_key(&3), Some(2));
1019        assert_eq!(a.nth_entry(2).map(|node| node.key), Some(3));
1020        assert_eq!(a.inclusive_floor_index(&0), None);
1021        assert_eq!(a.inclusive_floor_index(&6), Some(4));
1022        assert_eq!(a.ceil_index(&0), Some(0));
1023        let b = a.dissoc_value(&3);
1024        assert!(b.get(&3).is_none());
1025        assert!(a.get(&3).is_some());
1026    }
1027
1028    #[test]
1029    fn churn_matches_btree_map_model() {
1030        for seed in 0..4u64 {
1031            let mut rng = Rng(seed);
1032            let mut map = Standard::new();
1033            let mut model = BTreeMap::new();
1034            for step in 0..2000 {
1035                let key = rng.below(400) as i64;
1036                if rng.below(5) < 3 {
1037                    let value = rng.next() as i64;
1038                    map = map.assoc_value(key, value);
1039                    model.insert(key, value);
1040                } else {
1041                    map = map.dissoc_value(&key);
1042                    model.remove(&key);
1043                }
1044                check_invariant(&map.root);
1045                assert_eq!(map.len(), model.len(), "seed {seed} step {step}");
1046                assert_eq!(map.get(&key), model.get(&key), "seed {seed} step {step}");
1047                if step % 100 == 99 {
1048                    assert!(
1049                        map.iter().eq(model.iter()),
1050                        "seed {seed} step {step} contents"
1051                    );
1052                }
1053            }
1054            assert!(map.iter().eq(model.iter()), "seed {seed} final contents");
1055        }
1056    }
1057
1058    #[test]
1059    fn rank_ops_match_btree_map_model() {
1060        let mut rng = Rng(42);
1061        let mut map = Standard::new();
1062        let mut model = BTreeMap::new();
1063        for _ in 0..300 {
1064            let key = rng.below(200) as i64;
1065            map = map.assoc_value(key, key * 10);
1066            model.insert(key, key * 10);
1067        }
1068        let keys: Vec<i64> = model.keys().copied().collect();
1069        // present and absent probes, below/above/between the key range
1070        for probe in -5..205i64 {
1071            assert_eq!(
1072                map.index_of_key(&probe),
1073                keys.iter().position(|k| *k == probe),
1074                "index_of {probe}"
1075            );
1076            assert_eq!(
1077                map.inclusive_floor_index(&probe),
1078                keys.iter().rposition(|k| *k <= probe),
1079                "floor {probe}"
1080            );
1081            assert_eq!(
1082                map.ceil_index(&probe),
1083                keys.iter().position(|k| *k >= probe),
1084                "ceil {probe}"
1085            );
1086        }
1087        for (i, key) in keys.iter().enumerate() {
1088            assert_eq!(map.nth_entry(i).map(|node| node.key), Some(*key), "nth {i}");
1089            assert_eq!(
1090                map.nth_entry(i).map(|node| node.value),
1091                Some(*key * 10),
1092                "nth value {i}"
1093            );
1094        }
1095        assert!(map.nth_entry(keys.len()).is_none());
1096    }
1097
1098    #[test]
1099    fn slice_matches_btree_range_and_stays_usable() {
1100        let mut rng = Rng(7);
1101        let mut map = Standard::new();
1102        let mut model = BTreeMap::new();
1103        for _ in 0..200 {
1104            let key = rng.below(500) as i64;
1105            map = map.assoc_value(key, key);
1106            model.insert(key, key);
1107        }
1108        for _ in 0..200 {
1109            let a = rng.below(550) as i64 - 25;
1110            let b = rng.below(550) as i64 - 25;
1111            let (min, max) = if a <= b { (a, b) } else { (b, a) };
1112            let sliced = map.slice(&min, &max);
1113            assert_eq!(
1114                sliced.len(),
1115                model.range(min..=max).count(),
1116                "slice [{min},{max}]"
1117            );
1118            assert!(
1119                sliced.iter().eq(model.range(min..=max)),
1120                "slice [{min},{max}] contents"
1121            );
1122            // a sliced map keeps accepting assoc (BST order is preserved even
1123            // where pruning relaxed the black-height record, as in Java)
1124            let mut grown = sliced;
1125            let mut grown_model: BTreeMap<i64, i64> =
1126                model.range(min..=max).map(|(k, v)| (*k, *v)).collect();
1127            for _ in 0..20 {
1128                let key = rng.below(550) as i64 - 25;
1129                grown = grown.assoc_value(key, key);
1130                grown_model.insert(key, key);
1131            }
1132            assert!(
1133                grown.iter().eq(grown_model.iter()),
1134                "slice [{min},{max}] grown"
1135            );
1136        }
1137        assert!(map.slice(&1000, &2000).is_empty());
1138    }
1139
1140    #[test]
1141    fn map_values_maps_every_entry_preserving_order() {
1142        use crate::lang::protocol::IMetadata;
1143        let map = (0..50i64)
1144            .map(|k| (k, k))
1145            .collect::<Standard<_, _>>()
1146            .with_meta(Some(crate::lang::data::Metadata::document("doc")));
1147        let mapped = map.map_values(|k, v| v + k);
1148        check_invariant(&mapped.root);
1149        assert!(mapped
1150            .iter()
1151            .map(|(k, v)| (*k, *v))
1152            .eq((0..50i64).map(|k| (k, k + k))));
1153        assert_eq!(mapped.meta().map(|m| m.doc().unwrap()), Some("doc"));
1154    }
1155
1156    #[test]
1157    fn sequential_deletes_force_double_black_paths() {
1158        // ascending insert + descending delete is the classic double-black workout
1159        let mut map = Standard::new();
1160        for key in 0..400i64 {
1161            map = map.assoc_value(key, key);
1162            check_invariant(&map.root);
1163        }
1164        for key in (0..400i64).rev() {
1165            map = map.dissoc_value(&key);
1166            check_invariant(&map.root);
1167            assert_eq!(map.len() as i64, key);
1168            assert!(map.get(&key).is_none());
1169            if key % 50 == 0 {
1170                assert!(map.iter().map(|(k, _)| *k).eq(0..key));
1171            }
1172        }
1173        assert!(map.is_empty());
1174        assert!(matches!(map.root, Link::Empty));
1175    }
1176
1177    #[test]
1178    fn random_delete_order_down_to_empty() {
1179        let mut rng = Rng(99);
1180        let mut keys: Vec<i64> = (0..300).collect();
1181        for i in (1..keys.len()).rev() {
1182            let j = rng.below(i as u64 + 1) as usize;
1183            keys.swap(i, j);
1184        }
1185        let mut map: Standard<i64, i64> = (0..300i64).map(|k| (k, k)).collect();
1186        let mut model: BTreeMap<i64, i64> = (0..300i64).map(|k| (k, k)).collect();
1187        for key in keys {
1188            map = map.dissoc_value(&key);
1189            model.remove(&key);
1190            check_invariant(&map.root);
1191            assert_eq!(map.len(), model.len());
1192            if map.len() % 50 == 0 {
1193                assert!(map.iter().eq(model.iter()));
1194            }
1195        }
1196        assert!(map.is_empty());
1197        assert!(matches!(map.root, Link::Empty));
1198    }
1199
1200    #[test]
1201    fn iterator_yields_sorted_order_and_exhausts() {
1202        let map: Standard<i64, i64> = [(3, 3), (1, 1), (2, 2)].into_iter().collect();
1203        let mut it = map.iter();
1204        assert_eq!(it.next(), Some((&1, &1)));
1205        assert_eq!(it.next(), Some((&2, &2)));
1206        assert_eq!(it.next(), Some((&3, &3)));
1207        assert_eq!(it.next(), None);
1208        assert_eq!(it.next(), None);
1209        let empty: Standard<i64, i64> = Standard::new();
1210        assert_eq!(empty.iter().next(), None);
1211        // deep trees iterate without recursion
1212        let big: Standard<i64, i64> = (0..10_000i64).map(|k| (k, k)).collect();
1213        assert!(big.iter().map(|(k, _)| *k).eq(0..10_000));
1214        assert_eq!(big.len(), 10_000);
1215    }
1216
1217    #[test]
1218    fn transient_round_trip_matches_persistent() {
1219        use crate::lang::protocol::{IToMutable, IToPersistent};
1220        let mut rng = Rng(5);
1221        let mut persistent = Standard::new();
1222        let mut transient = Standard::new().to_mutable();
1223        for _ in 0..500 {
1224            let key = rng.below(300) as i64;
1225            if rng.below(2) == 0 {
1226                persistent = persistent.assoc_value(key, key);
1227                transient.assoc(key, key);
1228            } else {
1229                persistent = persistent.dissoc_value(&key);
1230                transient.dissoc(&key);
1231            }
1232        }
1233        let back = transient.to_persistent();
1234        assert_eq!(back.len(), persistent.len());
1235        assert!(back.iter().eq(persistent.iter()));
1236        check_invariant(&back.root);
1237    }
1238}