Skip to content

Commit c1c7ae3

Browse files
authored
[JS/TS] Added missing IReadOnlyCollection helpers (#3953)
1 parent 122083b commit c1c7ae3

File tree

14 files changed

+142
-33
lines changed

14 files changed

+142
-33
lines changed

src/Fable.Cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
* [Rust] Updated string comparisons (by @ncave)
1414
* [Rust] Fixed derived traits mapping (by @ncave)
1515
* [JS/TS] Added missing ICollection helpers (#3914) (by @ncave)
16+
* [JS/TS] Added missing IReadOnlyCollection helpers (by @ncave)
1617

1718
## 4.23.0 - 2024-10-28
1819

src/Fable.Transforms/Replacements.fs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,7 @@ let collections (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisA
26972697
| ("get_Count" | "get_IsReadOnly" | "Add" | "Remove" | "Clear" | "Contains" | "CopyTo") as meth, Some ar ->
26982698
let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst
26992699
Helper.LibCall(com, "CollectionUtil", meth, t, ar :: args, ?loc = r) |> Some
2700+
| "GetEnumerator", Some callee -> getEnumerator com r t callee |> Some
27002701
| _ -> None
27012702

27022703
let conditionalWeakTable (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
@@ -3983,8 +3984,6 @@ let private replacedModules =
39833984
Types.conditionalWeakTable, conditionalWeakTable
39843985
Types.ienumerableGeneric, enumerables
39853986
Types.ienumerable, enumerables
3986-
Types.valueCollection, enumerables
3987-
Types.keyCollection, enumerables
39883987
"System.Collections.Generic.Dictionary`2.Enumerator", enumerators
39893988
"System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator", enumerators
39903989
"System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator", enumerators
@@ -3994,6 +3993,9 @@ let private replacedModules =
39943993
Types.resizeArray, resizeArrays
39953994
"System.Collections.Generic.IList`1", resizeArrays
39963995
"System.Collections.IList", resizeArrays
3996+
Types.valueCollection, collections
3997+
Types.keyCollection, collections
3998+
Types.ireadonlycollection, collections
39973999
Types.icollectionGeneric, collections
39984000
Types.icollection, collections
39994001
"System.Collections.Generic.CollectionExtensions", collectionExtensions

src/Fable.Transforms/Rust/Fable2Rust.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ module TypeInfo =
362362
[ ty ] |> makeImportType com ctx "Native" "Arc"
363363

364364
let makeBoxTy com ctx (ty: Rust.Ty) : Rust.Ty =
365-
[ ty ] |> makeImportType com ctx "Native" "Box"
365+
[ ty ] |> makeImportType com ctx "Native" (rawIdent "Box")
366366

367367
let makeMutTy com ctx (ty: Rust.Ty) : Rust.Ty =
368368
[ ty ] |> makeImportType com ctx "Native" "MutCell"
@@ -1511,7 +1511,7 @@ module Util =
15111511
[ value ] |> makeNew com ctx "Native" "Arc"
15121512

15131513
let makeBoxValue com ctx (value: Rust.Expr) =
1514-
[ value ] |> makeNew com ctx "Native" "Box"
1514+
[ value ] |> makeNew com ctx "Native" (rawIdent "Box")
15151515

15161516
let makeMutValue com ctx (value: Rust.Expr) =
15171517
[ value ] |> makeNew com ctx "Native" "MutCell"

src/Fable.Transforms/Transforms.Util.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ module Types =
327327
[<Literal>]
328328
let idictionary = "System.Collections.Generic.IDictionary`2"
329329

330+
[<Literal>]
331+
let ireadonlycollection = "System.Collections.Generic.IReadOnlyCollection`1"
332+
330333
[<Literal>]
331334
let ireadonlydictionary = "System.Collections.Generic.IReadOnlyDictionary`2"
332335

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub mod Exception_ {
2-
use crate::Native_::{Any, Box_, Func0, LrcPtr};
2+
use crate::Native_::{Any, Box, Func0, LrcPtr};
33
use crate::String_::{fromSlice, string};
44
use crate::System::Exception;
55
use crate::Util_::new_Exception;

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub mod Native_ {
1010

1111
// re-export at module level
1212
// pub use alloc::borrow::Cow;
13-
pub use alloc::boxed::Box as Box_;
13+
pub use alloc::boxed::Box;
1414
pub use alloc::rc::Rc;
1515
pub use alloc::string::{String, ToString};
1616
pub use alloc::sync::Arc;
@@ -163,6 +163,15 @@ pub mod Native_ {
163163
)
164164
}
165165

166+
#[cfg(feature = "no_std")]
167+
pub fn get_args(argc: isize, argv: *const *const u8) -> impl Iterator<Item = &'static str> {
168+
(0..argc as usize).map(move |i| unsafe {
169+
let curr_argv = argv.add(i).read_volatile();
170+
let c_str = core::ffi::CStr::from_ptr(curr_argv as *const _);
171+
c_str.to_str().unwrap()
172+
})
173+
}
174+
166175
// -----------------------------------------------------------
167176
// IEqualityComparer key wrapper
168177
// -----------------------------------------------------------

src/fable-library-ts/CollectionUtil.ts

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@ export function count<T>(col: Iterable<T>): number {
44
if (typeof (col as any)["System.Collections.Generic.ICollection`1.get_Count"] === "function") {
55
return (col as any)["System.Collections.Generic.ICollection`1.get_Count"](); // collection
66
} else {
7-
if (isArrayLike(col)) {
8-
return col.length; // resize array
7+
if (typeof (col as any)["System.Collections.Generic.IReadOnlyCollection`1.get_Count"] === "function") {
8+
return (col as any)["System.Collections.Generic.IReadOnlyCollection`1.get_Count"](); // collection
99
} else {
10-
if (typeof (col as any).size === "number") {
11-
return (col as any).size; // map, set
10+
if (isArrayLike(col)) {
11+
return col.length; // array, resize array
1212
} else {
13-
let count = 0;
14-
for (const _ of col) {
15-
count++;
13+
if (typeof (col as any).size === "number") {
14+
return (col as any).size; // map, set
15+
} else {
16+
let count = 0;
17+
for (const _ of col) {
18+
count++;
19+
}
20+
return count; // other collections
1621
}
17-
return count;
1822
}
1923
}
2024
}
@@ -24,7 +28,16 @@ export function isReadOnly<T>(col: Iterable<T>): boolean {
2428
if (typeof (col as any)["System.Collections.Generic.ICollection`1.get_IsReadOnly"] === "function") {
2529
return (col as any)["System.Collections.Generic.ICollection`1.get_IsReadOnly"](); // collection
2630
} else {
27-
return false;
31+
if (isArrayLike(col)) {
32+
return ArrayBuffer.isView(col); // true for typed arrays, false for other arrays
33+
} else {
34+
if (typeof (col as any).size === "number") {
35+
return false; // map, set
36+
} else {
37+
return true; // other collections
38+
}
39+
}
40+
2841
}
2942
}
3043

@@ -45,7 +58,7 @@ export function contains<T>(col: Iterable<T>, item: T): boolean {
4558
return (col as any)["System.Collections.Generic.ICollection`1.Contains2B595"](item); // collection
4659
} else {
4760
if (isArrayLike(col)) {
48-
let i = col.findIndex(x => equals(x, item)); // resize array
61+
let i = col.findIndex(x => equals(x, item)); // array, resize array
4962
return i >= 0;
5063
} else {
5164
if (typeof (col as any).has === "function") {
@@ -55,7 +68,7 @@ export function contains<T>(col: Iterable<T>, item: T): boolean {
5568
return (col as any).has(item); // set
5669
}
5770
} else {
58-
return false; // unknown collection
71+
return false; // other collections
5972
}
6073
}
6174
}
@@ -66,7 +79,11 @@ export function add<T>(col: Iterable<T>, item: T): void {
6679
return (col as any)["System.Collections.Generic.ICollection`1.Add2B595"](item); // collection
6780
} else {
6881
if (isArrayLike(col)) {
69-
col.push(item); // resize array
82+
if (ArrayBuffer.isView(col)) {
83+
// TODO: throw for typed arrays?
84+
} else {
85+
col.push(item); // array, resize array
86+
}
7087
} else {
7188
if (typeof (col as any).add === "function") {
7289
return (col as any).add(item); // set
@@ -80,7 +97,7 @@ export function add<T>(col: Iterable<T>, item: T): void {
8097
throw new Error("An item with the same key has already been added. Key: " + item[0]);
8198
}
8299
} else {
83-
// unknown collection
100+
// TODO: throw for other collections?
84101
}
85102
}
86103
}
@@ -92,12 +109,17 @@ export function remove<T>(col: Iterable<T>, item: T): boolean {
92109
return (col as any)["System.Collections.Generic.ICollection`1.Remove2B595"](item); // collection
93110
} else {
94111
if (isArrayLike(col)) {
95-
let i = col.findIndex(x => equals(x, item));
96-
if (i >= 0) {
97-
col.splice(i, 1); // resize array
98-
return true;
99-
} else {
112+
if (ArrayBuffer.isView(col)) {
113+
// TODO: throw for typed arrays
100114
return false;
115+
} else {
116+
let i = col.findIndex(x => equals(x, item));
117+
if (i >= 0) {
118+
col.splice(i, 1); // array, resize array
119+
return true;
120+
} else {
121+
return false;
122+
}
101123
}
102124
} else {
103125
if (typeof (col as any).delete === "function") {
@@ -111,7 +133,8 @@ export function remove<T>(col: Iterable<T>, item: T): boolean {
111133
return (col as any).delete(item); // set
112134
}
113135
} else {
114-
return false; // unknown collection
136+
// TODO: throw for other collections?
137+
return false; // other collections
115138
}
116139
}
117140
}
@@ -122,12 +145,16 @@ export function clear<T>(col: Iterable<T>): void {
122145
return (col as any)["System.Collections.Generic.ICollection`1.Clear"](); // collection
123146
} else {
124147
if (isArrayLike(col)) {
125-
col.splice(0); // resize array
148+
if (ArrayBuffer.isView(col)) {
149+
// TODO: throw for typed arrays?
150+
} else {
151+
col.splice(0); // array, resize array
152+
}
126153
} else {
127154
if (typeof (col as any).clear === "function") {
128155
(col as any).clear(); // map, set
129156
} else {
130-
// unknown collection
157+
// TODO: throw for other collections?
131158
}
132159
}
133160
}

tests/Js/Main/ArrayTests.fs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ let tests =
6969
ParamArrayTest.Add(let ar = [|1;2;3|] in sideEffect ar; ar)
7070
|> equal 9
7171

72-
#if FABLE_COMPILER && FABLE_TYPED_ARRAYS
72+
#if FABLE_COMPILER_JAVASCRIPT
7373
testCase "Typed Arrays work" <| fun () ->
7474
let xs = [| 1; 2; 3; |]
7575
let ys = [| 1.; 2.; 3.; |]
@@ -1236,10 +1236,19 @@ let tests =
12361236
System.Array.Resize(&xs, 0)
12371237
xs |> equal [||]
12381238

1239-
// testCase "Array ICollection.IsReadOnly works" <| fun _ ->
1240-
// let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
1241-
// let coll = xs :> ICollection<_>
1242-
// coll.IsReadOnly |> equal false
1239+
testCase "Array IReadOnlyCollection.Count works" <| fun _ ->
1240+
let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
1241+
let coll = xs :> IReadOnlyCollection<_>
1242+
coll.Count |> equal 3
1243+
1244+
testCase "Array ICollection.IsReadOnly works" <| fun _ ->
1245+
let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
1246+
let coll = xs :> ICollection<_>
1247+
#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT
1248+
coll.IsReadOnly |> equal false // Arrays are the same as ResizeArrays
1249+
#else
1250+
coll.IsReadOnly |> equal true
1251+
#endif
12431252

12441253
testCase "Array ICollection.Count works" <| fun _ ->
12451254
let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
@@ -1259,4 +1268,36 @@ let tests =
12591268
let ys = [| ("D", 4); ("E", 5); ("F", 6) |]
12601269
coll.CopyTo(ys, 0)
12611270
ys = xs |> equal true
1271+
1272+
testCase "Array IReadOnlyCollection.Count with typed arrays works" <| fun _ ->
1273+
let xs = [| 1; 2; 3 |]
1274+
let coll = xs :> IReadOnlyCollection<_>
1275+
coll.Count |> equal 3
1276+
1277+
testCase "Array ICollection.IsReadOnly with typed arrays works" <| fun _ ->
1278+
let xs = [| 1; 2; 3 |]
1279+
let coll = xs :> ICollection<_>
1280+
#if FABLE_COMPILER_TYPESCRIPT
1281+
coll.IsReadOnly |> equal false // Arrays are the same as ResizeArrays
1282+
#else
1283+
coll.IsReadOnly |> equal true
1284+
#endif
1285+
1286+
testCase "Array ICollection.Count with typed arrays works" <| fun _ ->
1287+
let xs = [| 1; 2; 3 |]
1288+
let coll = xs :> ICollection<_>
1289+
coll.Count |> equal 3
1290+
1291+
testCase "Array ICollection.Contains with typed arrays works" <| fun _ ->
1292+
let xs = [| 1; 2; 3 |]
1293+
let coll = xs :> ICollection<_>
1294+
coll.Contains(4) |> equal false
1295+
coll.Contains(2) |> equal true
1296+
1297+
testCase "Array ICollection.CopyTo with typed arrays works" <| fun _ ->
1298+
let xs = [| 1; 2; 3 |]
1299+
let coll = xs :> ICollection<_>
1300+
let ys = [| 4; 5; 6 |]
1301+
coll.CopyTo(ys, 0)
1302+
ys = xs |> equal true
12621303
]

tests/Js/Main/DictionaryTests.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ let tests =
271271
table.add "C" 3
272272
table.Dic.Count |> equal 3
273273

274+
testCase "Dictionary IReadOnlyCollection.Count works" <| fun _ ->
275+
let xs = [| ("A", 1); ("B", 2); ("C", 3) |] |> Array.map KeyValuePair
276+
let coll = (Dictionary xs) :> IReadOnlyCollection<_>
277+
coll.Count |> equal 3
278+
274279
testCase "Dictionary ICollection.IsReadOnly works" <| fun _ ->
275280
let xs = [| ("A", 1); ("B", 2); ("C", 3) |] |> Array.map KeyValuePair
276281
let coll = (Dictionary xs) :> ICollection<KeyValuePair<_,_>>

tests/Js/Main/HashSetTests.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ let tests =
222222
apa.Contains ({ i = 5; s = "foo"}) |> equal true
223223
apa.Contains ({ i = 5; s = "fo"}) |> equal false
224224

225+
testCase "HashSet IReadOnlyCollection.Count works" <| fun _ ->
226+
let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
227+
let coll = (HashSet xs) :> IReadOnlyCollection<_>
228+
coll.Count |> equal 3
229+
225230
testCase "HashSet ICollection.IsReadOnly works" <| fun _ ->
226231
let xs = [| ("A", 1); ("B", 2); ("C", 3) |]
227232
let coll = (HashSet xs) :> ICollection<_>

0 commit comments

Comments
 (0)