@@ -6,6 +6,7 @@ export setproperties
6
6
export constructorof
7
7
using ConstructionBase
8
8
using CompositionsBase
9
+ using Static
9
10
using Base: getproperty
10
11
using Base
11
12
@@ -125,15 +126,15 @@ function _set(obj, optic, val, ::SetBased)
125
126
)
126
127
end
127
128
128
- <<<<<< < HEAD
129
129
if VERSION < v " 1.7"
130
130
struct Returns{V}
131
131
value:: V
132
132
end
133
133
(o:: Returns )(x) = o. value
134
134
else
135
135
using Base: Returns
136
- ====== =
136
+ end
137
+
137
138
138
139
struct Changed end
139
140
struct Unchanged end
@@ -276,19 +277,7 @@ $EXPERIMENTAL
276
277
struct Properties <: ObjectMap end
277
278
278
279
"""
279
- mapobject(f, obj)
280
-
281
- Construct a copy of `obj`, with each property replaced by
282
- the result of applying `f` to it.
283
-
284
- ```jldoctest
285
- julia> using Accessors
286
-
287
- julia> obj = (a=1, b=2);
288
-
289
- julia> Accessors.mapobject(x -> x+1, obj)
290
- (a = 2, b = 3)
291
- ```
280
+ maproperties()
292
281
293
282
# Implementation
294
283
@@ -300,8 +289,8 @@ $EXPERIMENTAL
300
289
"""
301
290
function mapproperties end
302
291
303
- function mapproperties (f, nt:: NamedTuple )
304
- map (f,nt)
292
+ function mapproperties (f, nt:: Union{Tuple, NamedTuple} )
293
+ map (f, nt)
305
294
end
306
295
307
296
function mapproperties (f, obj)
@@ -310,17 +299,6 @@ function mapproperties(f, obj)
310
299
return setproperties (obj, patch)
311
300
end
312
301
313
- # Don't construct when we don't absolutely have to.
314
- # `constructorof` may not be defined for an object.
315
- @generated function _maybeconstruct (obj:: O , props:: P , handler:: H ) where {O,P,H}
316
- ctr = _constructor (H (), O)
317
- if Changed in map (last ∘ fieldtypes, fieldtypes (P))
318
- :($ ctr (map (first, props)... ) => Changed ())
319
- else
320
- :(obj => Unchanged ())
321
- end
322
- end
323
-
324
302
skip (:: Splat ) = true
325
303
skip (x) = false
326
304
@@ -360,6 +338,59 @@ function _modify(f, obj, r::Recursive, ::ModifyBased)
360
338
end
361
339
end
362
340
341
+ """
342
+
343
+ new_obj, new_state = modify_stateful(f, (obj,state), optic)
344
+
345
+ Here `f` has signature `f(::Value, ::State) -> Tuple{NewValue, NewState}`.
346
+ """
347
+ function modify_stateful end
348
+
349
+ @inline function modify_stateful (f, (obj, state), optic:: Properties )
350
+ let f= f, obj= obj, state= state
351
+ modify_stateful_context ((obj, state), optic) do _, fn, pr, st
352
+ f (getfield (pr, known (fn)), st)
353
+ end
354
+ end
355
+ end
356
+
357
+ @generated function modify_stateful_context (f, (obj, state1):: T , optic:: Properties ) where T
358
+ _modify_stateful_inner (T)
359
+ end
360
+
361
+ # Separated for testing object/state combinations without restarts
362
+ function _modify_stateful_inner (:: Type{<:Tuple{O,S}} ) where {O,S}
363
+ modifications = []
364
+ vals = Expr (:tuple )
365
+ fns = fieldnames (O)
366
+ local st1 = :state0
367
+ local st2 = :state1
368
+ for (i, fn) in enumerate (fns)
369
+ v = Symbol (" val$i " )
370
+ st1 = Symbol (" state$i " )
371
+ st2 = Symbol (" state$(i+ 1 ) " )
372
+ ms = if O <: Tuple
373
+ :(($ v, $ st2) = f (obj, StaticInt {$(QuoteNode(fn))} (), props, $ st1))
374
+ else
375
+ :(($ v, $ st2) = f (obj, StaticSymbol {$(QuoteNode(fn))} (), props, $ st1))
376
+ end
377
+ push! (modifications, ms)
378
+ push! (vals. args, v)
379
+ end
380
+ patch = O <: Tuple ? vals : :(NamedTuple {$fns} ($ vals))
381
+ Expr (:block ,
382
+ :(props = getproperties (obj)),
383
+ modifications... ,
384
+ :(patch = $ patch),
385
+ :(new_obj = maybesetproperties ($ st2, obj, patch)),
386
+ :(new_state = maybesetstate ($ st2, obj, patch)),
387
+ :(return (setproperties (obj, patch), $ st2)),
388
+ )
389
+ end
390
+
391
+ maybesetproperties (state, obj, patch) = setproperties (obj, patch)
392
+ maybesetstate (state, obj, patch) = state
393
+
363
394
abstract type AbstractQuery end
364
395
365
396
"""
@@ -395,44 +426,101 @@ Query(; select=Any, descend=x -> true, optic=Properties()) = Query(select, desce
395
426
396
427
OpticStyle (:: Type{<:AbstractQuery} ) = SetBased ()
397
428
398
- @inline function (q:: AbstractQuery )(obj)
399
- let obj= obj, q= q
400
- mapobject (obj, _inner (q. optic), Splat ()) do o
401
- if q. select_condition (o)
402
- (_getouter (o, q. optic),)
403
- elseif q. descent_condition (o)
404
- q (o) # also a tuple
405
- else
406
- ()
407
- end
408
- end
429
+ struct Context{Select,Descend,Optic<: Union{ComposedOptic,Properties} } <: AbstractQuery
430
+ select_condition:: Select
431
+ descent_condition:: Descend
432
+ optic:: Optic
433
+ end
434
+
435
+
436
+ struct ContextState{V}
437
+ vals:: V
438
+ end
439
+ struct GetAllState{V}
440
+ vals:: V
441
+ end
442
+ struct SetAllState{C,V,I}
443
+ change:: C
444
+ vals:: V
445
+ itr:: I
446
+ end
447
+
448
+ pop (x) = first (x), Base. tail (x)
449
+ push (x, val) = (x... , val)
450
+ push (x:: GetAllState , val) = GetAllState (push (x. vals, val))
451
+
452
+ (q:: Query )(obj) = getall (obj, q)
453
+
454
+ function getall (obj, q)
455
+ initial_state = GetAllState (())
456
+ _, final_state = modify_stateful ((obj, initial_state), q) do o, s
457
+ new_state = push (s, outer (q. optic, o, s))
458
+ o, new_state
459
+ end
460
+ return final_state. vals
461
+ end
462
+
463
+ function setall (obj, q, vals)
464
+ initial_state = SetAllState (Unchanged (), vals, 1 )
465
+ final_obj, _ = modify_stateful ((obj, initial_state), q) do o, s
466
+ new_output = outer (q. optic, o, s)
467
+ new_state = SetAllState (Changed (), s. vals, s. itr + 1 )
468
+ new_output, new_state
469
+ end
470
+ return final_obj
471
+ end
472
+
473
+ function context (f, obj, q)
474
+ initial_state = GetAllState (())
475
+ _, final_state = modify_stateful_context ((obj, initial_state), Properties ()) do o, fn, pr, s
476
+ new_state = push (s, f (o, known (fn)))
477
+ o, new_state
409
478
end
479
+ return final_state. vals
410
480
end
411
481
412
- set ( obj, q:: AbstractQuery , vals ) = _set (obj, q, (vals, 1 ))[ 1 ][ 1 ]
482
+ modify (f, obj, q:: Query ) = setall (obj, q, map (f, getall (obj, q)))
413
483
414
- @inline function _set (obj, q :: AbstractQuery , (vals, itr))
415
- let obj= obj, q = q, vals = vals, itr = itr
416
- mapobject (obj, _inner (q . optic), MaybeConstruct (), itr) do o, itr :: Int
417
- if q . select_condition (o )
418
- _setouter (o, q . optic, vals[itr]) => Changed (), itr + 1
419
- elseif q . descent_condition (o )
420
- _set (o, q, (vals, itr)) # Will be marked as Changed()/Unchanged( )
421
- else
422
- o => Unchanged (), itr
423
- end
484
+ @inline function modify_stateful (f :: F , (obj, state), q :: Query ) where F
485
+ modify_stateful (( obj, state), inner (q . optic)) do o, s
486
+ if q . select_condition (o)
487
+ f (o, s )
488
+ elseif q . descent_condition (o)
489
+ ds = descent_state (s )
490
+ o, s = modify_stateful (f :: F , (o, ds), q )
491
+ o, merge_state (s, ds)
492
+ else
493
+ o, s
424
494
end
425
495
end
426
496
end
427
497
428
- modify (f, obj, q:: Query ) = set (obj, q, map (f, q (obj)))
498
+ maybesetproperties (state:: GetAllState , obj, patch) = obj
499
+ maybesetproperties (state:: SetAllState , obj, patch) =
500
+ maybesetproperties (state. change, state, obj, patch)
501
+ maybesetproperties (:: Changed , state:: SetAllState , obj, patch) = setproperties (obj, patch)
502
+ maybesetproperties (:: Unchanged , state:: SetAllState , obj, patch) = obj
503
+
504
+ descent_state (state:: SetAllState ) = SetAllState (Unchanged (), state. vals, state. itr)
505
+ descent_state (state) = state
506
+
507
+ merge_state (s1:: SetAllState , s2) = SetAllState (anychanged (s1, s2), s2. vals, s2. itr)
508
+ merge_state (s1, s2) = s2
509
+
510
+ anychanged (s1, s2) = anychanged (s1. change, s2. change)
511
+ anychanged (:: Unchanged , :: Unchanged ) = Unchanged ()
512
+ anychanged (:: Unchanged , :: Changed ) = Changed ()
513
+ anychanged (:: Changed , :: Unchanged ) = Changed ()
514
+ anychanged (:: Changed , :: Changed ) = Changed ()
515
+
516
+ inner (optic) = optic
517
+ inner (optic:: ComposedOptic ) = optic. inner
518
+
519
+ outer (optic, o, state:: GetAllState ) = o
520
+ outer (optic:: ComposedOptic , o, state:: GetAllState ) = optic. outer (o)
521
+ outer (optic:: ComposedOptic , o, state:: SetAllState ) = set (o, optic. outer, state. vals[state. itr])
522
+ outer (optic, o, state:: SetAllState ) = state. vals[state. itr]
429
523
430
- @inline _inner (optic:: ComposedOptic ) = optic. inner
431
- @inline _inner (optic) = optic
432
- @inline _getouter (o, optic:: ComposedOptic ) = optic. outer (o)
433
- @inline _getouter (o, optic) = o
434
- @inline _setouter (o, optic:: ComposedOptic , v) = set (o, optic. outer, v)
435
- @inline _setouter (o, optic, v) = v
436
524
437
525
# ###############################################################################
438
526
# #### Lenses
0 commit comments