@@ -122,8 +122,20 @@ priv enum WriteFrame {
122122///
123123/// Only applies to object properties, not array elements.
124124pub struct Replacer {
125- priv f : (String , Json ) -> Json?
126- } derive (@debug.Debug )
125+ priv kind : ReplacerKind
126+ }
127+
128+ ///|
129+ priv enum ReplacerKind {
130+ Custom ((String , Json ) -> Json? )
131+ Keep (ArrayView [StringView ])
132+ Exclude (ArrayView [StringView ])
133+ }
134+
135+ ///|
136+ pub impl @debug.Debug for Replacer with fn to_repr(_) {
137+ @debug.Repr ::record(Map ([("f", @debug.Repr ::literal("<function: ...>"))]))
138+ }
127139
128140///|
129141/// Create a new Replacer with a custom function.
@@ -153,7 +165,7 @@ pub struct Replacer {
153165/// ```
154166#alias (new, deprecated="Use `Replacer ()` instead")
155167pub fn Replacer ::Replacer (f : (String , Json ) -> Json? ) -> Replacer {
156- { f, }
168+ { kind: Custom (f) }
157169}
158170
159171///|
@@ -175,7 +187,7 @@ pub fn Replacer::Replacer(f : (String, Json) -> Json?) -> Replacer {
175187/// }
176188/// ```
177189pub fn Replacer ::keep(array : ArrayView [StringView ]) -> Replacer {
178- { f: (idx, value) => if array.contains(idx) { Some (value) } else { None } }
190+ { kind: Keep ( array) }
179191}
180192
181193///|
@@ -197,7 +209,34 @@ pub fn Replacer::keep(array : ArrayView[StringView]) -> Replacer {
197209/// }
198210/// ```
199211pub fn Replacer ::exclude(array : ArrayView [StringView ]) -> Replacer {
200- { f: (idx, value) => if array.contains(idx) { None } else { Some (value) } }
212+ { kind: Exclude (array) }
213+ }
214+
215+ ///|
216+ fn Replacer ::prepare(self : Replacer ) -> (String , Json ) -> Json? {
217+ match self.kind {
218+ Custom (f) => f
219+ Keep (array) =>
220+ if array.length() <= 8 {
221+ (idx, value) => if array.contains(idx) { Some (value) } else { None }
222+ } else {
223+ let keys : Map [String , Unit ] = Map ([] )
224+ for key in array {
225+ keys[key.to_owned()] = ()
226+ }
227+ (idx, value) => if keys.contains(idx) { Some (value) } else { None }
228+ }
229+ Exclude (array) =>
230+ if array.length() <= 8 {
231+ (idx, value) => if array.contains(idx) { None } else { Some (value) }
232+ } else {
233+ let keys : Map [String , Unit ] = Map ([] )
234+ for key in array {
235+ keys[key.to_owned()] = ()
236+ }
237+ (idx, value) => if keys.contains(idx) { None } else { Some (value) }
238+ }
239+ }
201240}
202241
203242///|
@@ -280,6 +319,7 @@ pub fn Json::stringify(
280319 replacer? : Replacer ,
281320) -> String {
282321 let buf = StringBuilder (size_hint=0)
322+ let prepared_replacer = replacer.map(replacer => replacer.prepare())
283323
284324 // Explicit stack to replace recursive calls
285325 let stack : Array [WriteFrame ] = []
@@ -347,8 +387,8 @@ pub fn Json::stringify(
347387 match iterator.next() {
348388 Some ((k, v)) => {
349389 let mut v2 = v
350- if replacer is Some (replacer) {
351- if ( replacer.f) (k, v) is Some (v) {
390+ if prepared_replacer is Some (replacer) {
391+ if replacer(k, v) is Some (v) {
352392 v2 = v
353393 } else {
354394 continue None
@@ -527,21 +567,29 @@ fn escape(str : String, escape_slash~ : Bool) -> String {
527567/// - Non-object values (arrays, strings, numbers, etc.) are returned unchanged
528568/// - The original JSON value is not modified; a new value is returned
529569pub fn Json ::transform(self : Self , replacer : Replacer ) -> Json {
570+ self.transform_with(replacer.prepare())
571+ }
572+
573+ ///|
574+ fn Json ::transform_with(
575+ self : Self ,
576+ replacer : (String , Json ) -> Json? ,
577+ ) -> Json {
530578 match self {
531579 Object (members) =>
532580 members
533581 .iter()
534582 .filter_map(pair => {
535583 let (k, v) = pair
536- if ( replacer.f) (k, v) is Some (v2) {
537- Some ((k, v2.transform (replacer)))
584+ if replacer(k, v) is Some (v2) {
585+ Some ((k, v2.transform_with (replacer)))
538586 } else {
539587 None
540588 }
541589 })
542590 |> Map ::from_iter()
543591 |> Object
544- Array (members) => Array (members.map(m => m.transform (replacer)))
592+ Array (members) => Array (members.map(m => m.transform_with (replacer)))
545593 value => value
546594 }
547595}
0 commit comments