Skip to content

Commit aa95687

Browse files
committed
modify
1 parent 28ba71c commit aa95687

File tree

1 file changed

+58
-28
lines changed

1 file changed

+58
-28
lines changed

src/optics.jl

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ struct ConstructIfChanged{C}
133133
constructor::C
134134
end
135135

136+
_constructor(x, t) = _constructor(x.handler, t)
137+
136138
# TODO what do we call these things?
137139
struct Construct end
138140
_constructor(::Construct, ::Type{T}) where T = constructorof(T)
@@ -249,6 +251,19 @@ function modify(f, obj, w::If)
249251
end
250252
end
251253

254+
struct Select{C}
255+
select_condition::C
256+
end
257+
OpticStyle(::Type{<:If}) = ModifyBased()
258+
259+
function modify(f, obj, w::If)
260+
if w.modify_condition(obj)
261+
(obj,)
262+
else
263+
()
264+
end
265+
end
266+
252267
"""
253268
mapproperties(f, obj)
254269
@@ -265,24 +280,31 @@ julia> Accessors.mapproperties(x -> x+1, obj)
265280
```
266281
$EXPERIMENTAL
267282
"""
268-
function mapproperties(f, obj::O, handler=Construct(), itr=nothing) where O
283+
function mapproperties(f, obj::O, optic, itr::Nothing=nothing) where O
269284
# TODO move this helper elsewhere?
285+
pnames = propertynames(obj)
286+
if isempty(pnames)
287+
return obj
288+
else
289+
ctor = constructorof(typeof(obj))
290+
new_props = map(pnames) do p
291+
f(getproperty(obj, p))
292+
end
293+
ctr = _constructor(optic, O)
294+
return ctr(new_props...)
295+
end
296+
end
297+
function mapproperties(f, obj::O, optic, itr::Int) where O
270298
pnames = propertynames(obj)
271299
if isempty(pnames)
272300
return _maybeitr(obj, itr)
273301
else
274302
# TODO: this is too slow
275303
new_props, itr = reduce(pnames; init=((), itr)) do (vals, itr), p
276-
prop = getproperty(obj, p)
277-
if itr isa Nothing
278-
val = f(prop)
279-
(vals..., val), itr
280-
else
281-
val, itr = f(prop, itr)
282-
(vals..., val), itr
283-
end
304+
val, itr = f(getproperty(obj, p), itr)
305+
(vals..., val), itr
284306
end
285-
ctr = _constructor(handler, O)
307+
ctr = _constructor(optic, O)
286308
return _maybeitr(ctr(new_props...), itr)
287309
end
288310
end
@@ -308,7 +330,10 @@ Based on [`mapproperties`](@ref).
308330
309331
$EXPERIMENTAL
310332
"""
311-
struct Properties end
333+
struct Properties{H}
334+
handler::H
335+
end
336+
Properties() = Properties(Construct())
312337
OpticStyle(::Type{<:Properties}) = ModifyBased()
313338
modify(f, o, ::Properties) = mapproperties(f, o)
314339

@@ -328,7 +353,7 @@ julia> Accessors.mapfields(x -> x+1, obj)
328353
```
329354
$EXPERIMENTAL
330355
"""
331-
@generated function mapfields(f, obj::O, handler::H=Construct(), itr::I=nothing) where {O,H,I}
356+
@generated function mapfields(f, obj::O, optic, itr::I=nothing) where {O,H,I}
332357
# TODO: This is how Flatten.jl works, but it's not really
333358
# correct use of ConstructionBase as it assumers properties=fields
334359
fnames = fieldnames(O)
@@ -350,23 +375,23 @@ $EXPERIMENTAL
350375
end
351376
new_prop_exp = Expr(:tuple, val_exps...)
352377
end
353-
# ret = if H == MaybeConstruct
354-
# quote
378+
ret = if H == MaybeConstruct
379+
quote
355380
# TODO: last type instability.
356381
# replace this with val => Changed(), val => Unchanged()
357382
# return values.
358383
#
359384
# Don't construct when we don't absolutely have to.
360385
# `constructorof` may not be defined for an object.
361-
# if props === new_props
362-
# return obj, itr
363-
# else
364-
# return _maybeitr($ctr(new_props...), itr)
365-
# end
366-
# end
367-
# else
386+
if props === new_props
387+
return _maybeitr(obj, itr)
388+
else
389+
return _maybeitr($ctr(new_props...), itr)
390+
end
391+
end
392+
else
368393
ret = :(return _maybeitr($ctr(new_props...), itr))
369-
# end
394+
end
370395
quote
371396
props = $prop_exp
372397
new_props = $new_prop_exp
@@ -399,9 +424,12 @@ Based on [`mapfields`](@ref).
399424
400425
$EXPERIMENTAL
401426
"""
402-
struct Fields end
427+
struct Fields{H}
428+
handler::H
429+
end
430+
Fields() = Fields(Construct())
403431
OpticStyle(::Type{<:Fields}) = ModifyBased()
404-
modify(f, o, ::Fields) = mapfields(f, o)
432+
modify(f, o, optic::Fields) = mapfields(f, o, optic)
405433

406434
"""
407435
Recursive(descent_condition, optic)
@@ -505,7 +533,7 @@ struct Query{Select,Descend,Optic}
505533
descent_condition::Descend
506534
optic::Optic
507535
end
508-
Query(select, ignore = x -> true) = Query(select, ignore, Fields())
536+
Query(select, descend = x -> true) = Query(select, descend, Fields())
509537
Query(; select=Any, descend=x -> true, optic=Fields()) = Query(select, descend, optic)
510538

511539
function (q::Query)(obj)
@@ -534,6 +562,8 @@ function _setquery(obj, q::Query, (val, itr))
534562
end
535563
end
536564

537-
_query(f, o, ::Elements, handler, itr) = map(f, o)
538-
_query(f, o, ::Fields, handler, itr) = mapfields(f, o, handler, itr)
539-
_query(f, o, ::Properties, handler, itr) = mapproperties(f, o, handler, itr)
565+
modify(f, obj, q::Query) = set(obj, q, map(f, q(obj)))
566+
567+
_query(f, o, ::Elements, itr) = map(f, o)
568+
_query(f, o, ::Fields, itr) = mapfields(f, o, itr)
569+
_query(f, o, ::Properties, itr) = mapproperties(f, o, itr)

0 commit comments

Comments
 (0)