Skip to content

Commit 2594fdd

Browse files
authored
[Rust] Fix missing HashSet implementations and tests (#4523)
1 parent 4a1edb3 commit 2594fdd

11 files changed

Lines changed: 340 additions & 197 deletions

File tree

src/Fable.Cli/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
* [Beam] Fix `List.Cons` call replacement and test (by @ncave)
1313
* [Beam/Dart/Python/TypeScript] Fix `Array.Equals` to use reference equality instead of structural equality (by @ncave)
1414
* [Dart/Python/TypeScript/Rust] Fix `Seq.foldBack2` for sequences with different lengths (by @ncave)
15+
* [Rust] Fix `Array/HashMap/HashSet` internal representation (by @ncave)
16+
* [Rust] Fix missing `HashSet` implementations and tests (by @ncave)
1517
* [Python] Fix missing `Array` module implementations and tests (by @ncave)
1618
* [Python] Fix object expressions implementing interfaces with `[<CLIEvent>]` members no longer produce unimplementable abstract Protocol members (fixes #3039)
1719
* [Python] Fix `DateTime.TryParse` incorrectly assigning `DateTimeKind.Local` to naive datetime strings (should be `DateTimeKind.Unspecified`) (fixes #3654)

src/Fable.Compiler/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
* [Beam] Fix `List.Cons` call replacement and test (by @ncave)
1313
* [Beam/Dart/Python/TypeScript] Fix `Array.Equals` to use reference equality instead of structural equality (by @ncave)
1414
* [Dart/Python/TypeScript/Rust] Fix `Seq.foldBack2` for sequences with different lengths (by @ncave)
15+
* [Rust] Fix `Array/HashMap/HashSet` internal representation (by @ncave)
16+
* [Rust] Fix missing `HashSet` implementations and tests (by @ncave)
1517
* [Python] Fix missing `Array` module implementations and tests (by @ncave)
1618
* [Python] Fix object expressions implementing interfaces with `[<CLIEvent>]` members no longer produce unimplementable abstract Protocol members (fixes #3039)
1719
* [Python] Fix `DateTime.TryParse` incorrectly assigning `DateTimeKind.Local` to naive datetime strings (should be `DateTimeKind.Unspecified`) (fixes #3654)

src/Fable.Transforms/Rust/Replacements.fs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,15 +2368,13 @@ let hashSets (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op
23682368
| "GetEnumerator", Some c ->
23692369
let ar = Helper.LibCall(com, "HashSet", "entries", t, [ c ])
23702370
Helper.LibCall(com, "Seq", "Enumerable::ofArray", t, [ ar ], ?loc = r) |> Some
2371-
| ("IsProperSubsetOf" | "IsProperSupersetOf" | "UnionWith" | "IntersectWith" | "ExceptWith" | "IsSubsetOf" | "IsSupersetOf" as meth),
2372-
Some c ->
2373-
let meth = Naming.lowerFirst meth
2374-
Helper.LibCall(com, "Set", meth, t, c :: args, ?loc = r) |> Some
2375-
// TODO!!!
2376-
// | "CopyTo"
2377-
// | "SetEquals"
2378-
// | "Overlaps"
2379-
// | "SymmetricExceptWith"
2371+
| "CopyTo", Some c ->
2372+
let meth = i.CompiledName |> toLowerFirstWithArgsCountSuffix (c :: args)
2373+
makeLibModuleCall com r t i "HashSet" meth thisArg args |> Some
2374+
| ("UnionWith" | "IntersectWith" | "ExceptWith" | "SymmetricExceptWith" | "Overlaps" | "SetEquals"), Some _
2375+
| ("IsProperSubsetOf" | "IsProperSupersetOf" | "IsSubsetOf" | "IsSupersetOf"), Some _ ->
2376+
let meth = Naming.lowerFirst i.CompiledName
2377+
makeLibModuleCall com r t i "HashSet" meth thisArg args |> Some
23802378
| meth, _ ->
23812379
let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst
23822380
makeLibModuleCall com r t i "HashSet" meth thisArg args |> Some

src/fable-library-rust/src/HashMap.rs

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,49 +10,50 @@ pub mod HashMap_ {
1010
use std::collections;
1111

1212
use crate::NativeArray_::{array_from, Array};
13-
use crate::Native_::{default_eq_comparer, mkRefMut, seq_to_iter};
13+
use crate::Native_::{default_eq_comparer, seq_to_iter};
1414
use crate::Native_::{HashKey, LrcPtr, MutCell, Seq, Vec};
1515
use crate::System::Collections::Generic::IEqualityComparer_1;
1616

1717
use core::fmt::{Debug, Display, Formatter, Result};
1818
use core::hash::{Hash, Hasher};
1919

20-
type MutHashMap<K, V> = MutCell<collections::HashMap<HashKey<K>, V>>;
21-
2220
#[derive(Clone)] //, Debug, Default, PartialEq, PartialOrd, Eq, Hash, Ord)]
23-
pub struct HashMap<K: Clone, V: Clone> {
24-
hash_map: LrcPtr<MutHashMap<K, V>>,
21+
pub struct MutHashMap<K: Clone, V: Clone> {
22+
hash_map: MutCell<collections::HashMap<HashKey<K>, V>>,
2523
comparer: LrcPtr<dyn IEqualityComparer_1<K>>,
2624
}
2725

28-
// impl<K, V: Clone> Default for HashMap<K, V>
29-
// where
30-
// K: Clone + Hash + PartialEq + 'static,
31-
// {
32-
// fn default() -> HashMap<K, V> {
33-
// new_empty()
34-
// }
35-
// }
26+
pub type HashMap<K, V> = LrcPtr<MutHashMap<K, V>>;
3627

37-
impl<K: Clone, V: Clone> core::ops::Deref for HashMap<K, V> {
38-
type Target = LrcPtr<MutHashMap<K, V>>;
28+
impl<K: Clone, V: Clone> core::ops::Deref for MutHashMap<K, V> {
29+
type Target = MutCell<collections::HashMap<HashKey<K>, V>>;
3930
fn deref(&self) -> &Self::Target {
4031
&self.hash_map
4132
}
4233
}
4334

44-
impl<K: Clone + Debug, V: Clone + Debug> Debug for HashMap<K, V> {
35+
impl<K: Clone + Debug, V: Clone + Debug> Debug for MutHashMap<K, V> {
4536
fn fmt(&self, f: &mut Formatter) -> Result {
4637
write!(f, "{:?}", self.hash_map) //TODO:
4738
}
4839
}
4940

50-
impl<K: Clone + Debug, V: Clone + Debug> Display for HashMap<K, V> {
41+
impl<K: Clone + Debug, V: Clone + Debug> Display for MutHashMap<K, V> {
5142
fn fmt(&self, f: &mut Formatter) -> Result {
5243
write!(f, "{:?}", self.hash_map) //TODO:
5344
}
5445
}
5546

47+
fn make_hash_map<K: Clone, V: Clone>(
48+
hash_map: collections::HashMap<HashKey<K>, V>,
49+
comparer: LrcPtr<dyn IEqualityComparer_1<K>>,
50+
) -> HashMap<K, V> {
51+
LrcPtr::new(MutHashMap {
52+
hash_map: MutCell::new(hash_map),
53+
comparer,
54+
})
55+
}
56+
5657
fn from_iter<K: Clone + 'static, V: Clone, I: Iterator<Item = (K, V)>>(
5758
iter: I,
5859
comparer: LrcPtr<dyn IEqualityComparer_1<K>>,
@@ -61,10 +62,7 @@ pub mod HashMap_ {
6162
let key = HashKey::new(k, comparer.clone());
6263
(key, v)
6364
});
64-
HashMap {
65-
hash_map: mkRefMut(collections::HashMap::from_iter(it)),
66-
comparer: comparer.clone(),
67-
}
65+
make_hash_map(collections::HashMap::from_iter(it), comparer.clone())
6866
}
6967

7068
fn to_iter<K: Clone, V: Clone>(map: &HashMap<K, V>) -> impl Iterator<Item = (K, V)> + '_ {
@@ -75,39 +73,33 @@ pub mod HashMap_ {
7573
where
7674
K: Clone + Hash + PartialEq + 'static,
7775
{
78-
HashMap {
79-
hash_map: mkRefMut(collections::HashMap::new()),
80-
comparer: default_eq_comparer::<K>(),
81-
}
76+
make_hash_map(collections::HashMap::new(), default_eq_comparer::<K>())
8277
}
8378

8479
pub fn new_with_capacity<K, V: Clone>(capacity: i32) -> HashMap<K, V>
8580
where
8681
K: Clone + Hash + PartialEq + 'static,
8782
{
88-
HashMap {
89-
hash_map: mkRefMut(collections::HashMap::with_capacity(capacity as usize)),
90-
comparer: default_eq_comparer::<K>(),
91-
}
83+
make_hash_map(
84+
collections::HashMap::with_capacity(capacity as usize),
85+
default_eq_comparer::<K>(),
86+
)
9287
}
9388

9489
pub fn new_with_comparer<K: Clone, V: Clone>(
9590
comparer: LrcPtr<dyn IEqualityComparer_1<K>>,
9691
) -> HashMap<K, V> {
97-
HashMap {
98-
hash_map: mkRefMut(collections::HashMap::new()),
99-
comparer,
100-
}
92+
make_hash_map(collections::HashMap::new(), comparer)
10193
}
10294

10395
pub fn new_with_capacity_comparer<K: Clone, V: Clone>(
10496
capacity: i32,
10597
comparer: LrcPtr<dyn IEqualityComparer_1<K>>,
10698
) -> HashMap<K, V> {
107-
HashMap {
108-
hash_map: mkRefMut(collections::HashMap::with_capacity(capacity as usize)),
99+
make_hash_map(
100+
collections::HashMap::with_capacity(capacity as usize),
109101
comparer,
110-
}
102+
)
111103
}
112104

113105
pub fn new_from_enumerable<K, V: Clone + 'static>(seq: Seq<(K, V)>) -> HashMap<K, V>

src/fable-library-rust/src/HashSet.rs

Lines changed: 121 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,100 +9,102 @@ pub mod HashSet_ {
99
#[cfg(not(feature = "no_std"))]
1010
use std::collections;
1111

12+
use crate::Global_::SR::indexOutOfBounds;
1213
use crate::NativeArray_::{array_from, Array};
13-
use crate::Native_::{default_eq_comparer, mkRefMut, seq_to_iter};
14+
use crate::Native_::{default_eq_comparer, seq_to_iter};
1415
use crate::Native_::{HashKey, LrcPtr, MutCell, Seq, Vec};
1516
use crate::System::Collections::Generic::IEqualityComparer_1;
1617

1718
use core::fmt::{Debug, Display, Formatter, Result};
1819
use core::hash::Hash;
1920

20-
type MutHashSet<T> = MutCell<collections::HashSet<HashKey<T>>>;
21-
2221
#[derive(Clone)] //, Debug, Default, PartialEq, PartialOrd, Eq, Hash, Ord)]
23-
pub struct HashSet<T: Clone> {
24-
hash_set: LrcPtr<MutHashSet<T>>,
22+
pub struct MutHashSet<T: Clone> {
23+
hash_set: MutCell<collections::HashSet<HashKey<T>>>,
2524
comparer: LrcPtr<dyn IEqualityComparer_1<T>>,
2625
}
2726

28-
// impl<T> Default for HashSet<T>
29-
// where
30-
// T: Clone + Hash + PartialEq + 'static,
31-
// {
32-
// fn default() -> HashSet<T> {
33-
// new_empty()
34-
// }
35-
// }
27+
pub type HashSet<T> = LrcPtr<MutHashSet<T>>;
3628

37-
impl<T: Clone> core::ops::Deref for HashSet<T> {
38-
type Target = LrcPtr<MutHashSet<T>>;
29+
impl<T: Clone> core::ops::Deref for MutHashSet<T> {
30+
type Target = MutCell<collections::HashSet<HashKey<T>>>;
3931
fn deref(&self) -> &Self::Target {
4032
&self.hash_set
4133
}
4234
}
4335

44-
impl<T: Clone + Debug> Debug for HashSet<T> {
36+
impl<T: Clone + Debug> Debug for MutHashSet<T> {
4537
fn fmt(&self, f: &mut Formatter) -> Result {
4638
write!(f, "{:?}", self.hash_set) //TODO:
4739
}
4840
}
4941

50-
impl<T: Clone + Debug> Display for HashSet<T> {
42+
impl<T: Clone + Debug> Display for MutHashSet<T> {
5143
fn fmt(&self, f: &mut Formatter) -> Result {
5244
write!(f, "{:?}", self.hash_set) //TODO:
5345
}
5446
}
5547

48+
fn make_hash_set<T: Clone>(
49+
hash_set: collections::HashSet<HashKey<T>>,
50+
comparer: LrcPtr<dyn IEqualityComparer_1<T>>,
51+
) -> HashSet<T> {
52+
LrcPtr::new(MutHashSet {
53+
hash_set: MutCell::new(hash_set),
54+
comparer,
55+
})
56+
}
57+
5658
fn from_iter<T: Clone + 'static, I: Iterator<Item = T>>(
5759
iter: I,
5860
comparer: LrcPtr<dyn IEqualityComparer_1<T>>,
5961
) -> HashSet<T> {
6062
let it = iter.map(|v| HashKey::new(v, comparer.clone()));
61-
HashSet {
62-
hash_set: mkRefMut(collections::HashSet::from_iter(it)),
63-
comparer,
64-
}
63+
make_hash_set(collections::HashSet::from_iter(it), comparer)
6564
}
6665

6766
fn to_iter<T: Clone>(set: &HashSet<T>) -> impl Iterator<Item = T> + '_ {
6867
set.iter().map(|k| k.key.clone())
6968
}
7069

70+
fn seq_to_hash_set<T: Clone + 'static>(
71+
seq: Seq<T>,
72+
comparer: LrcPtr<dyn IEqualityComparer_1<T>>,
73+
) -> collections::HashSet<HashKey<T>> {
74+
seq_to_iter(seq)
75+
.map(|v| HashKey::new(v, comparer.clone()))
76+
.collect()
77+
}
78+
7179
pub fn new_empty<T>() -> HashSet<T>
7280
where
7381
T: Clone + Hash + PartialEq + 'static,
7482
{
75-
HashSet {
76-
hash_set: mkRefMut(collections::HashSet::new()),
77-
comparer: default_eq_comparer::<T>(),
78-
}
83+
make_hash_set(collections::HashSet::new(), default_eq_comparer::<T>())
7984
}
8085

8186
pub fn new_with_capacity<T>(capacity: i32) -> HashSet<T>
8287
where
8388
T: Clone + Hash + PartialEq + 'static,
8489
{
85-
HashSet {
86-
hash_set: mkRefMut(collections::HashSet::with_capacity(capacity as usize)),
87-
comparer: default_eq_comparer::<T>(),
88-
}
90+
make_hash_set(
91+
collections::HashSet::with_capacity(capacity as usize),
92+
default_eq_comparer::<T>(),
93+
)
8994
}
9095

9196
pub fn new_with_comparer<T: Clone>(comparer: LrcPtr<dyn IEqualityComparer_1<T>>) -> HashSet<T> {
92-
HashSet {
93-
hash_set: mkRefMut(collections::HashSet::new()),
94-
comparer,
95-
}
97+
make_hash_set(collections::HashSet::new(), comparer)
9698
}
9799

98100
pub fn new_with_capacity_comparer<T: Clone>(
99101
capacity: i32,
100102
comparer: LrcPtr<dyn IEqualityComparer_1<T>>,
101103
) -> HashSet<T> {
102-
HashSet {
103-
hash_set: mkRefMut(collections::HashSet::with_capacity(capacity as usize)),
104+
make_hash_set(
105+
collections::HashSet::with_capacity(capacity as usize),
104106
comparer,
105-
}
107+
)
106108
}
107109

108110
pub fn new_from_enumerable<T>(seq: Seq<T>) -> HashSet<T>
@@ -146,6 +148,89 @@ pub mod HashSet_ {
146148
set.get_mut().clear();
147149
}
148150

151+
pub fn unionWith<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) {
152+
let other = seq_to_hash_set(other, set.comparer.clone());
153+
let hash_set = set.get_mut();
154+
for key in other {
155+
hash_set.insert(key);
156+
}
157+
}
158+
159+
pub fn intersectWith<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) {
160+
let other = seq_to_hash_set(other, set.comparer.clone());
161+
set.get_mut().retain(|key| other.contains(key));
162+
}
163+
164+
pub fn exceptWith<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) {
165+
let other = seq_to_hash_set(other, set.comparer.clone());
166+
let hash_set = set.get_mut();
167+
for key in other {
168+
hash_set.remove(&key);
169+
}
170+
}
171+
172+
pub fn symmetricExceptWith<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) {
173+
let other = seq_to_hash_set(other, set.comparer.clone());
174+
let hash_set = set.get_mut();
175+
for key in other {
176+
if !hash_set.remove(&key) {
177+
hash_set.insert(key);
178+
}
179+
}
180+
}
181+
182+
pub fn overlaps<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
183+
let other = seq_to_hash_set(other, set.comparer.clone());
184+
set.iter().any(|key| other.contains(key))
185+
}
186+
187+
pub fn setEquals<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
188+
let other = seq_to_hash_set(other, set.comparer.clone());
189+
set.len() == other.len() && set.is_subset(&other)
190+
}
191+
192+
pub fn copyTo<T: Clone>(set: HashSet<T>, dest: Array<T>) {
193+
copyTo2(set, dest, 0)
194+
}
195+
196+
pub fn copyTo2<T: Clone>(set: HashSet<T>, dest: Array<T>, destIndex: i32) {
197+
let count = set.len() as i32;
198+
copyTo3(set, dest, destIndex, count)
199+
}
200+
201+
pub fn copyTo3<T: Clone>(set: HashSet<T>, dest: Array<T>, destIndex: i32, count: i32) {
202+
let set_len = set.len() as i32;
203+
let dest_len = dest.len() as i32;
204+
if destIndex < 0 || count < 0 || count > set_len || destIndex + count > dest_len {
205+
panic!("{}", indexOutOfBounds());
206+
}
207+
let mut dest = dest.get_mut();
208+
let it = to_iter(&set).take(count as usize);
209+
for (offset, item) in it.enumerate() {
210+
dest[destIndex as usize + offset] = item;
211+
}
212+
}
213+
214+
pub fn isSubsetOf<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
215+
let other = seq_to_hash_set(other, set.comparer.clone());
216+
set.is_subset(&other)
217+
}
218+
219+
pub fn isSupersetOf<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
220+
let other = seq_to_hash_set(other, set.comparer.clone());
221+
set.is_superset(&other)
222+
}
223+
224+
pub fn isProperSubsetOf<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
225+
let other = seq_to_hash_set(other, set.comparer.clone());
226+
set.len() < other.len() && set.is_subset(&other)
227+
}
228+
229+
pub fn isProperSupersetOf<T: Clone + 'static>(set: HashSet<T>, other: Seq<T>) -> bool {
230+
let other = seq_to_hash_set(other, set.comparer.clone());
231+
set.len() > other.len() && set.is_superset(&other)
232+
}
233+
149234
pub fn entries<T: Clone>(set: HashSet<T>) -> Array<T> {
150235
array_from(Vec::from_iter(to_iter(&set)))
151236
}

0 commit comments

Comments
 (0)