ADR-386: drain() Is on Every Map and Set, as on Vec and HashMap

Status: Accepted (#1130) Date: November 1, 2026 (architect’s decision under the owner’s rule of 2026-10-31, docs/supervisor.md, Language decisions: an extension nobody pays for who does not use it, in the form the language already has) Answers: the C1b move (547e6462, ledger_items_stored) found that a collections::BTreeMap has no drain() (NK1171), so its fold borrowed each unit’s map and cloned every set it took over Related: ADR-094 D4 (a for lends; drain takes the elements away), ADR-collections-1 (the maps and sets of std::collections), ADR-384 (the last std counterparts a C1 move needed), Part III 17.1

1. Question

Vec::drain and collections::HashMap::drain are in the ledger (std.contracts): a for over them binds owned elements and the container goes with them. BTreeMap, HashSet and BTreeSet have no such entry, so a program that wants to take a sorted map’s values over must clone them. Is drain() on them, and what does it mean?

2. Decision

D1 - drain() takes every element out of a map or set

m.drain() on a collections::BTreeMap[K, V] is a Seq[(K, V)] sync sized, on a HashSet[T] or a BTreeSet[T] a Seq[T] sync sized, with the signature HashMap::drain has: the receiver is taken (self, not ref), so what a for over it binds is the program’s own, and a key, a value or an element may be handed to something that keeps it. The two sorted containers hand their elements out in key order and say ends as well, as their iter does.

D2 - Lowering

HashSet lowers to Rust’s drain(). Rust’s BTreeMap and BTreeSet have no stable drain: they lower to into_iter() of the container, or to std::mem::take(&mut m).into_iter() where the container is a place the program still names after the loop (a field, a let mut); either is what D1 means.

3. Why (the principles)

4. Not decided here

drain(range) on a Vec (no move has met it); retain beside it is ADR-collections-1’s.

This site is open source. Improve this page.