Skip to content

Commit 3b20bcb

Browse files
committed
Merge branch 'collection-recovery' of https://github.com/apasel422/rfcs
2 parents 0893030 + b8648e4 commit 3b20bcb

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

text/0000-set-recovery.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
- Feature Name: set_recovery
2+
- Start Date: 2015-07-08
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
8+
Add element-recovery methods to the set types in `std`.
9+
10+
# Motivation
11+
12+
Sets are sometimes used as a cache keyed on a certain property of a type, but programs may need to
13+
access the type's other properties for efficiency or functionality. The sets in `std` do not expose
14+
their elements (by reference or by value), making this use-case impossible.
15+
16+
Consider the following example:
17+
18+
```rust
19+
use std::collections::HashSet;
20+
use std::hash::{Hash, Hasher};
21+
22+
// The `Widget` type has two fields that are inseparable.
23+
#[derive(PartialEq, Eq, Hash)]
24+
struct Widget {
25+
foo: Foo,
26+
bar: Bar,
27+
}
28+
29+
#[derive(PartialEq, Eq, Hash)]
30+
struct Foo(&'static str);
31+
32+
#[derive(PartialEq, Eq, Hash)]
33+
struct Bar(u32);
34+
35+
// Widgets are normally considered equal if all their corresponding fields are equal, but we would
36+
// also like to maintain a set of widgets keyed only on their `bar` field. To this end, we create a
37+
// new type with custom `{PartialEq, Hash}` impls.
38+
struct MyWidget(Widget);
39+
40+
impl PartialEq for MyWidget {
41+
fn eq(&self, other: &Self) -> bool { self.0.bar == other.0.bar }
42+
}
43+
44+
impl Eq for MyWidget {}
45+
46+
impl Hash for MyWidget {
47+
fn hash<H: Hasher>(&self, h: &mut H) { self.0.bar.hash(h); }
48+
}
49+
50+
fn main() {
51+
// In our program, users are allowed to interactively query the set of widgets according to
52+
// their `bar` field, as well as insert, replace, and remove widgets.
53+
54+
let mut widgets = HashSet::new();
55+
56+
// Add some default widgets.
57+
widgets.insert(MyWidget(Widget { foo: Foo("iron"), bar: Bar(1) }));
58+
widgets.insert(MyWidget(Widget { foo: Foo("nickel"), bar: Bar(2) }));
59+
widgets.insert(MyWidget(Widget { foo: Foo("copper"), bar: Bar(3) }));
60+
61+
// At this point, the user enters commands and receives output like:
62+
//
63+
// ```
64+
// > get 1
65+
// Some(iron)
66+
// > get 4
67+
// None
68+
// > remove 2
69+
// removed nickel
70+
// > add 2 cobalt
71+
// added cobalt
72+
// > add 3 zinc
73+
// replaced copper with zinc
74+
// ```
75+
//
76+
// However, `HashSet` does not expose its elements via its `{contains, insert, remove}`
77+
// methods, instead providing only a boolean indicator of the elements's presence in the set,
78+
// preventing us from implementing the desired functionality.
79+
}
80+
```
81+
82+
# Detailed design
83+
84+
Add the following element-recovery methods to `std::collections::{BTreeSet, HashSet}`:
85+
86+
```rust
87+
impl<T> Set<T> {
88+
// Like `contains`, but returns a reference to the element if the set contains it.
89+
fn get<Q: ?Sized>(&self, element: &Q) -> Option<&T>;
90+
91+
// Like `remove`, but returns the element if the set contained it.
92+
fn take<Q: ?Sized>(&mut self, element: &Q) -> Option<T>;
93+
94+
// Like `insert`, but replaces the element with the given one and returns the previous element
95+
// if the set contained it.
96+
fn replace(&mut self, element: T) -> Option<T>;
97+
}
98+
```
99+
100+
# Drawbacks
101+
102+
This complicates the collection APIs.
103+
104+
# Alternatives
105+
106+
Do nothing.

0 commit comments

Comments
 (0)