@@ -4,18 +4,24 @@ const { proxyStateMap, snapCache } = unstable_getInternalStates()
44const maybeProxify = ( x : any ) => ( typeof x === 'object' ? proxy ( { x } ) . x : x )
55const isProxy = ( x : any ) => proxyStateMap . has ( x )
66
7+ type RSetLike < T > = { has ( value : T ) : boolean }
8+
79type InternalProxySet < T > = Set < T > & {
810 data : T [ ]
9- toJSON : object
11+ toJSON : ( ) => object
1012 index : number
1113 epoch : number
12- intersection : ( other : Set < T > ) => Set < T >
13- union : ( other : Set < T > ) => Set < T >
14- difference : ( other : Set < T > ) => Set < T >
15- symmetricDifference : ( other : Set < T > ) => Set < T >
16- isSubsetOf : ( other : Set < T > ) => boolean
17- isSupersetOf : ( other : Set < T > ) => boolean
18- isDisjointFrom : ( other : Set < T > ) => boolean
14+ intersection < U > ( other : RSetLike < U > ) : Set < T & U >
15+ intersection ( other : Set < T > ) : Set < T >
16+ union < U > ( other : RSetLike < U > ) : Set < T | U >
17+ union ( other : Set < T > ) : Set < T >
18+ difference < U > ( other : RSetLike < U > ) : Set < T >
19+ difference ( other : Set < T > ) : Set < T >
20+ symmetricDifference < U > ( other : RSetLike < U > ) : Set < T | U >
21+ symmetricDifference ( other : Set < T > ) : Set < T >
22+ isSubsetOf ( other : RSetLike < T > ) : boolean
23+ isSupersetOf ( other : RSetLike < T > ) : boolean
24+ isDisjointFrom ( other : RSetLike < T > ) : boolean
1925}
2026
2127/**
@@ -55,6 +61,7 @@ export const isProxySet = (obj: object): boolean => {
5561 * set: proxySet()
5662 * })
5763 */
64+
5865export function proxySet < T > ( initialValues ?: Iterable < T > | null ) {
5966 const initialData : T [ ] = [ ]
6067 const indexMap = new Map < T , number > ( )
@@ -84,6 +91,82 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
8491 }
8592 }
8693
94+ const hasIterator = ( o : unknown ) : o is Iterable < unknown > =>
95+ typeof o === 'object' && o !== null && Symbol . iterator in ( o as object )
96+
97+ const hasForEach = < U > ( o : RSetLike < U > ) : o is RSetLike < U > & { forEach : ( cb : ( v : U ) => void ) => void } =>
98+ typeof ( o as { forEach ?: unknown } ) . forEach === 'function'
99+
100+ const asIterable = < U > ( other : RSetLike < U > | Set < U > ) : Iterable < U > => {
101+ if ( hasIterator ( other ) ) return other as Iterable < U >
102+ if ( hasForEach ( other ) ) {
103+ const acc : U [ ] = [ ]
104+ other . forEach ( ( v ) => acc . push ( v ) )
105+ return acc
106+ }
107+ throw new TypeError ( 'Expected an iterable' )
108+ }
109+
110+ function intersectionImpl < T , U > ( this : InternalProxySet < T > , other : RSetLike < U > ) : Set < T & U >
111+ function intersectionImpl < T > ( this : InternalProxySet < T > , other : Set < T > ) : Set < T >
112+ function intersectionImpl < T > (
113+ this : InternalProxySet < T > ,
114+ other : RSetLike < unknown > | Set < T >
115+ ) : Set < unknown > {
116+ this . epoch
117+ const otherSet = proxySet ( asIterable ( other ) )
118+ const result = proxySet < T > ( )
119+ for ( const value of this . values ( ) ) {
120+ if ( otherSet . has ( value ) ) {
121+ result . add ( value )
122+ }
123+ }
124+ return proxySet ( result )
125+ }
126+
127+ function unionImpl < T , U > ( this : InternalProxySet < T > , other : RSetLike < U > ) : Set < T | U >
128+ function unionImpl < T > ( this : InternalProxySet < T > , other : Set < T > ) : Set < T >
129+ function unionImpl < T > (
130+ this : InternalProxySet < T > ,
131+ other : RSetLike < unknown > | Set < T >
132+ ) : Set < unknown > {
133+ this . epoch
134+ const otherSet = proxySet ( asIterable ( other ) )
135+ const result = proxySet < unknown > ( )
136+ for ( const v of this . values ( ) ) result . add ( v )
137+ for ( const v of otherSet . values ( ) ) result . add ( v )
138+ return proxySet ( result )
139+ }
140+
141+ function differenceImpl < T , U > ( this : InternalProxySet < T > , _other : RSetLike < U > ) : Set < T >
142+ function differenceImpl < T > ( this : InternalProxySet < T > , other : Set < T > ) : Set < T >
143+ function differenceImpl < T > (
144+ this : InternalProxySet < T > ,
145+ other : RSetLike < unknown > | Set < T >
146+ ) : Set < T > {
147+ this . epoch
148+ const otherSet = proxySet ( asIterable ( other ) )
149+ const result = proxySet < T > ( )
150+ for ( const v of this . values ( ) ) if ( ! otherSet . has ( v ) ) result . add ( v )
151+ return proxySet ( result )
152+ }
153+
154+ function symmetricDifferenceImpl < T , U > ( this : InternalProxySet < T > , other : RSetLike < U > ) : Set < T | U >
155+ function symmetricDifferenceImpl < T > ( this : InternalProxySet < T > , other : Set < T > ) : Set < T >
156+ function symmetricDifferenceImpl < T > (
157+ this : InternalProxySet < T > ,
158+ other : RSetLike < unknown > | Set < T >
159+ ) : Set < unknown > {
160+ this . epoch
161+ const otherSet = proxySet ( asIterable ( other ) )
162+ const result = proxySet < unknown > ( )
163+ for ( const v of this . values ( ) ) if ( ! otherSet . has ( v ) ) result . add ( v )
164+ for ( const v of otherSet . values ( ) ) if ( ! this . has ( v as T ) ) result . add ( v )
165+ return proxySet ( result )
166+ }
167+
168+
169+
87170 const vObject : InternalProxySet < T > = {
88171 data : initialData ,
89172 index : initialIndex ,
@@ -97,7 +180,7 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
97180 has ( value : T ) {
98181 const map = getMapForThis ( this )
99182 const v = maybeProxify ( value )
100- this . epoch // touch property for tracking
183+ this . epoch
101184 return map . has ( v )
102185 } ,
103186 add ( value : T ) {
@@ -130,31 +213,31 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
130213 if ( ! isProxy ( this ) ) {
131214 throw new Error ( 'Cannot perform mutations on a snapshot' )
132215 }
133- this . data . length = 0 // empty array
216+ this . data . length = 0
134217 this . index = 0
135218 this . epoch ++
136219 indexMap . clear ( )
137220 } ,
138- forEach ( cb ) {
139- this . epoch // touch property for tracking
221+ forEach ( cb : ( value : T , valueAgain : T , set : Set < T > ) => void ) {
222+ this . epoch
140223 const map = getMapForThis ( this )
141224 map . forEach ( ( index ) => {
142225 cb ( this . data [ index ] ! , this . data [ index ] ! , this )
143226 } )
144227 } ,
145228 * values ( ) : SetIterator < T > {
146- this . epoch // touch property for tracking
229+ this . epoch
147230 const map = getMapForThis ( this )
148231 for ( const index of map . values ( ) ) {
149232 yield this . data [ index ] !
150233 }
151234 } ,
152235 keys ( ) : SetIterator < T > {
153- this . epoch // touch property for tracking
236+ this . epoch
154237 return this . values ( )
155238 } ,
156239 * entries ( ) : SetIterator < [ T , T ] > {
157- this . epoch // touch property for tracking
240+ this . epoch
158241 const map = getMapForThis ( this )
159242 for ( const index of map . values ( ) ) {
160243 const value = this . data [ index ] !
@@ -170,76 +253,25 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
170253 get [ Symbol . toStringTag ] ( ) {
171254 return 'Set'
172255 } ,
173- intersection ( other : Set < T > ) : Set < T > {
174- this . epoch // touch property for tracking
175- const otherSet = proxySet < T > ( other )
176- const resultSet = proxySet < T > ( )
177- for ( const value of this . values ( ) ) {
178- if ( otherSet . has ( value ) ) {
179- resultSet . add ( value )
180- }
181- }
182- return proxySet ( resultSet )
183- } ,
184- union ( other : Set < T > ) {
185- this . epoch // touch property for tracking
186- const resultSet = proxySet < T > ( )
187- const otherSet = proxySet < T > ( other )
188- for ( const value of this . values ( ) ) {
189- resultSet . add ( value )
190- }
191- for ( const value of otherSet ) {
192- resultSet . add ( value )
193- }
194- return proxySet ( resultSet )
195- } ,
196- difference ( other : Set < T > ) {
197- this . epoch // touch property for tracking
198- const resultSet = proxySet < T > ( )
199- const otherSet = proxySet < T > ( other )
200- for ( const value of this . values ( ) ) {
201- if ( ! otherSet . has ( value ) ) {
202- resultSet . add ( value )
203- }
204- }
205- return proxySet ( resultSet )
206- } ,
207- symmetricDifference ( other : Set < T > ) {
208- this . epoch // touch property for tracking
209- const resultSet = proxySet < T > ( )
210- const otherSet = proxySet < T > ( other )
211- for ( const value of this . values ( ) ) {
212- if ( ! otherSet . has ( value ) ) {
213- resultSet . add ( value )
214- }
215- }
216- for ( const value of otherSet . values ( ) ) {
217- if ( ! this . has ( value ) ) {
218- resultSet . add ( value )
219- }
220- }
221- return proxySet ( resultSet )
222- } ,
223- isSubsetOf ( other : Set < T > ) {
224- this . epoch // touch property for tracking
225- const otherSet = proxySet < T > ( other )
226- return (
227- this . size <= other . size &&
228- [ ...this . values ( ) ] . every ( ( value ) => otherSet . has ( value ) )
229- )
256+ intersection : intersectionImpl ,
257+ union : unionImpl ,
258+ difference : differenceImpl ,
259+ symmetricDifference : symmetricDifferenceImpl ,
260+ isSubsetOf ( other : RSetLike < T > ) {
261+ this . epoch
262+ for ( const v of this . values ( ) ) if ( ! other . has ( v ) ) return false
263+ return true
230264 } ,
231- isSupersetOf ( other : Set < T > ) {
232- this . epoch // touch property for tracking
233- const otherSet = proxySet < T > ( other )
234- return (
235- this . size >= other . size &&
236- [ ...otherSet ] . every ( ( value ) => this . has ( value ) )
237- )
265+ isSupersetOf ( other : RSetLike < T > ) {
266+ this . epoch
267+ const it = asIterable ( other )
268+ for ( const v of it ) if ( ! this . has ( v ) ) return false
269+ return true
238270 } ,
239- isDisjointFrom ( other : Set < T > ) : boolean {
240- this . epoch // touch property for tracking
241- const otherSet = proxySet < T > ( other )
242- return [ ... this . values ( ) ] . every ( ( value ) => ! otherSet . has ( value ) )
271+ isDisjointFrom ( other : RSetLike < T > ) {
272+ this . epoch
273+ for ( const v of this . values ( ) ) if ( other . has ( v ) ) return false
274+ return true
243275 } ,
244276 }
245277
@@ -253,7 +285,7 @@ export function proxySet<T>(initialValues?: Iterable<T> | null) {
253285 } )
254286 Object . seal ( proxiedObject )
255287
256- return proxiedObject as unknown as InternalProxySet < T > & {
288+ return proxiedObject as InternalProxySet < T > & {
257289 $$valtioSnapshot : Omit < InternalProxySet < T > , 'set' | 'delete' | 'clear' >
258290 }
259291}
0 commit comments