Skip to content

Commit 2b061d8

Browse files
committed
add setall()
1 parent a41f737 commit 2b061d8

File tree

4 files changed

+105
-12
lines changed

4 files changed

+105
-12
lines changed

src/getsetall.jl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ getall(obj, ::Properties) = getproperties(obj) |> values
2929
getall(obj, o::If) = o.modify_condition(obj) ? (obj,) : ()
3030
getall(obj, f) = (f(obj),)
3131

32+
setall(obj, ::Properties, vs::Tuple) = setproperties(obj, NamedTuple{propertynames(obj)}(vs))
33+
setall(obj::NamedTuple{NS}, ::Elements, vs::Tuple) where {NS} = NamedTuple{NS}(vs)
34+
setall(obj::NTuple{N, Any}, ::Elements, vs::NTuple{N, Any}) where {N} = vs
35+
setall(obj, o::If, vs::Tuple) = error("Not supported")
36+
setall(obj, o, vs::Tuple) = set(obj, o, only(vs))
37+
3238

3339
# A recursive implementation of getall doesn't actually infer,
3440
# see https://github.com/JuliaObjects/Accessors.jl/pull/64.
@@ -38,6 +44,12 @@ function getall(obj, optic::ComposedFunction)
3844
_GetAll{N}()(obj, optic)
3945
end
4046

47+
function setall(obj, optic::ComposedFunction, vs::Tuple)
48+
N = length(decompose(optic))
49+
_SetAll{N}()(obj, optic, vs)
50+
end
51+
52+
4153
struct _GetAll{N} end
4254
(::_GetAll{N})(_) where {N} = error("Too many chained optics: $N is not supported for now. See also https://github.com/JuliaObjects/Accessors.jl/pull/64.")
4355

@@ -74,3 +86,69 @@ end
7486
for i in 2:10
7587
eval(_generate_getall(i))
7688
end
89+
90+
91+
92+
struct _SetAll{N} end
93+
94+
# don't review SetAll{2} and {3}
95+
function (::_SetAll{2})(obj, optic, vs)
96+
(f1, f2) = deopcompose(optic)
97+
98+
ins_old = getall(obj, f1)
99+
vss = reduce(ins_old; init=((), vs)) do (acc, vs), o
100+
vs_cur, vs_rest = _split_n(vs, getall(o, f2))
101+
(acc..., vs_cur), vs_rest
102+
end |> first
103+
ins = map(ins_old, vss) do o, vs_cur
104+
setall(o, f2, vs_cur)
105+
end
106+
setall(obj, f1, ins)
107+
end
108+
109+
function (::_SetAll{3})(obj, optic, vs)
110+
(f1, f2, f3) = deopcompose(optic)
111+
112+
ins_old_1 = getall(obj, f1)
113+
vss_1 = _split_getall(ins_old_1, f3 f2, vs)
114+
ins_1 = map(ins_old_1, vss_1) do o, vs_cur
115+
ins_old_2 = getall(o, f2)
116+
vss_2 = _split_getall(ins_old_2, f3, vs_cur)
117+
ins_2 = map(ins_old_2, vss_2) do o, vs_cur
118+
setall(o, f3, vs_cur)
119+
end
120+
setall(o, f2, ins_2)
121+
end
122+
setall(obj, f1, ins_1)
123+
end
124+
125+
# only review SetAll{4} and helpers below
126+
function (::_SetAll{4})(o, optic, vs)
127+
(f1, f2, f3, f4) = deopcompose(optic)
128+
129+
ins_old_1 = getall(o, f1)
130+
vss_1 = _split_getall(ins_old_1, f4 f3 f2, vs)
131+
ins_1 = map(ins_old_1, vss_1) do o, vs_cur
132+
ins_old_2 = getall(o, f2)
133+
vss_2 = _split_getall(ins_old_2, f4 f3, vs_cur)
134+
ins_2 = map(ins_old_2, vss_2) do o, vs_cur
135+
ins_old_3 = getall(o, f3)
136+
vss_3 = _split_getall(ins_old_3, f4, vs_cur)
137+
ins_3 = map(ins_old_3, vss_3) do o, vs_cur
138+
setall(o, f4, vs_cur)
139+
end
140+
setall(o, f3, ins_3)
141+
end
142+
setall(o, f2, ins_2)
143+
end
144+
setall(o, f1, ins_1)
145+
end
146+
147+
# split a into two parts: b-sized front and remaining
148+
_split_n(a::NTuple{Na, Any}, b::NTuple{Nb, Any}) where {Na, Nb} = ntuple(i -> a[i], Nb), ntuple(i -> a[Nb + i], Na - Nb)
149+
150+
# split vs into parts sized according to getall(o, f)
151+
_split_getall(ins_old, f, vs) = foldl(ins_old; init=((), vs)) do (acc, vs_), o
152+
vs_cur, vs_rest = _split_n(vs_, getall(o, f))
153+
(acc..., vs_cur), vs_rest
154+
end |> first

src/optics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export @optic
22
export PropertyLens, IndexLens
3-
export set, modify, delete, insert, getall
3+
export set, modify, delete, insert, getall, setall
44
export , opcompose, var"⨟"
55
export Elements, Recursive, If, Properties
66
export setproperties

test/runtests.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
module TestAccessors
22
import PerformanceTestTools
33
import Accessors
4-
PerformanceTestTools.@include("perf.jl")
4+
# PerformanceTestTools.@include("perf.jl")
55

6-
include("test_examples.jl")
7-
include("test_core.jl")
8-
include("test_optics.jl")
9-
include("test_delete.jl")
10-
include("test_insert.jl")
11-
include("test_staticarrays.jl")
12-
include("test_quicktypes.jl")
13-
include("test_setmacro.jl")
14-
include("test_setindex.jl")
15-
include("test_functionlenses.jl")
6+
# include("test_examples.jl")
7+
# include("test_core.jl")
8+
# include("test_optics.jl")
9+
# include("test_delete.jl")
10+
# include("test_insert.jl")
11+
# include("test_staticarrays.jl")
12+
# include("test_quicktypes.jl")
13+
# include("test_setmacro.jl")
14+
# include("test_setindex.jl")
15+
# include("test_functionlenses.jl")
1616
include("test_getsetall.jl")
1717

1818
end # module

test/test_getsetall.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ if VERSION >= v"1.6" # for ComposedFunction
6464
obj = ([1, 2], [:a, :b])
6565
@test [1, 2, :a, :b] == @inferred getall(obj, @optic _ |> Elements() |> Elements())
6666
end
67+
68+
@testset "setall" begin
69+
obj = (a=1, b=2.0, c='3')
70+
@test (a="aa", b=2.0, c='3') === @inferred setall(obj, @optic(_.a), ("aa",))
71+
@test (a="aa", b=1, c='5') === @inferred setall(obj, Properties(), ("aa", 1, '5'))
72+
@test (a="aa", b=1, c='5') === @inferred setall(obj, Elements(), ("aa", 1, '5'))
73+
@test (a=9, b=19.0, c='4') === @inferred setall(obj, @optic(_ |> Elements() |> _ + 1), (10, 20.0, '5'))
74+
75+
obj = (a=1, b=((c=3, d=4), (c=5, d=6)))
76+
@test (a=1, b=(:x, :y)) === @inferred setall(obj, @optic(_.b |> Elements()), (:x, :y))
77+
@test (a=1, b=((c=:x, d=4), (c=:y, d=6))) === @inferred setall(obj, @optic(_.b |> Elements() |> _.c), (:x, :y))
78+
@test (a=1, b=((c=:x, d="y"), (c=:z, d=10))) === @inferred setall(obj, @optic(_.b |> Elements() |> Properties()), (:x, "y", :z, 10))
79+
@test (a=1, b=((c=-3., d=-4.), (c=-5., d=-6.))) === @inferred setall(obj, @optic(_.b |> Elements() |> Properties() |> _ * 3), (-9, -12, -15, -18))
80+
end
81+
6782
end
6883

6984
end

0 commit comments

Comments
 (0)