You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This package provides the `@unpack` and `@unpack_fields` macros for destructuring properties and fields, respectively.
8
-
The behaviour of `@unpack` is equivalent to the destructuring that was introduced in [Julia#39285](https://github.com/JuliaLang/julia/pull/39285) and is available in Julia >= 1.7.0-DEV.364.
7
+
This package provides four macros, namely
8
+
9
+
-`@unpack` for destructuring properties,
10
+
-`@pack!` for setting properties,
11
+
-`@unpack_fields` for destructuring fields,
12
+
-`@pack_fields!` for setting fields.
13
+
14
+
`@unpack`/`@pack!` are based on `getproperty`/`setproperty` whereas `@unpack_fields`/`@pack_fields!` are based on `getfield`/`setfield!`.
15
+
16
+
In Julia >= 1.7.0-DEV.364, `@unpack` is expanded to the destructuring syntax that was introduced in [Julia#39285](https://github.com/JuliaLang/julia/pull/39285).
9
17
10
18
## Examples
11
19
@@ -40,7 +48,7 @@ An example with a custom struct in a function:
40
48
```julia
41
49
julia>using SimpleUnPack
42
50
43
-
julia>struct MyStruct{X,Y}
51
+
julia>mutable struct MyStruct{X,Y}
44
52
x::X
45
53
y::Y
46
54
end
@@ -55,6 +63,14 @@ julia> function Base.getproperty(m::MyStruct, p::Symbol)
@@ -63,22 +79,37 @@ julia> function g(m::MyStruct)
63
79
julia> g(MyStruct(1.0, -5))
64
80
(x =1.0, y =42)
65
81
82
+
julia>function g!(m::MyStruct, x, y)
83
+
@pack! m = x, y
84
+
return m
85
+
end;
86
+
87
+
julia> g!(MyStruct(2.1, 5), 1.2, 2)
88
+
MyStruct{Float64, Int64}(1.2, 4)
89
+
66
90
julia>function h(m::MyStruct)
67
91
@unpack_fields x, y = m
68
92
return (; x, y)
69
93
end
70
94
71
95
julia> h(MyStruct(1.0, -5))
72
96
(x =1.0, y =-5)
97
+
98
+
julia>function h!(m::MyStruct, x, y)
99
+
@pack_fields! m = x, y
100
+
return m
101
+
end;
102
+
103
+
julia> h!(MyStruct(2.1, 5), 1.2, 2)
104
+
MyStruct{Float64, Int64}(1.2, 2)
73
105
```
74
106
75
107
## Comparison with UnPack.jl
76
108
77
-
The syntax of `@unpack` is based on [`UnPack.@unpack`](https://github.com/mauro3/UnPack.jl).
78
-
However, `UnPack.@unpack` is more flexible and based on `UnPack.unpack` instad of `getproperty`.
79
-
While `UnPack.unpack` falls back to `getproperty`, it also supports `AbstractDict`s with keys of type `Symbol` and `AbstractString`, and can be specialized for other types.
80
-
Since `UnPack.unpack` dispatches on `Val(property)` instances, this increased flexibility comes at the cost of increased compilation times.
109
+
The syntax of `@unpack` and `@pack!` is based on `UnPack.@unpack` and `UnPack.@pack!` in [UnPack.jl](https://github.com/mauro3/UnPack.jl).
81
110
82
-
In contrast to SimpleUnPack, UnPack provides an `UnPack.@pack!` macro for setting properties.
111
+
`UnPack.@unpack`/`UnPack.@pack!` are more flexible since they are based on `UnPack.unpack`/`UnPack.pack!` instad of `getproperty`/`setproperty!`.
112
+
While `UnPack.unpack`/`UnPack.pack!` fall back to `getproperty`/`setproperty!`, they also support `AbstractDict`s with keys of type `Symbol` and `AbstractString` and can be specialized for other types.
113
+
Since `UnPack.unpack` and `UnPack.pack!` dispatch on `Val(property)` instances, this increased flexibility comes at the cost of increased number of specializations and increased compilation times.
83
114
84
-
However, currently UnPack does not support destructuring based on `getfield` only ([UnPack#23](https://github.com/mauro3/UnPack.jl/issues/23)).
115
+
In contrast to SimpleUnPack, currently UnPack does not support destructuring/updating based on `getfield`/`setfield!` only ([UnPack#23](https://github.com/mauro3/UnPack.jl/issues/23)).
@@ -9,93 +9,173 @@ Destructure properties `a`, `b`, ... of `x` into variables of the same name.
9
9
10
10
The behaviour of the macro is equivalent to `(; a, b, ...) = x` which was introduced in [Julia#39285](https://github.com/JuliaLang/julia/pull/39285) and is available in Julia >= 1.7.0-DEV.364.
11
11
12
-
See also [`@unpack_fields`](@ref)
12
+
See also [`@pack!`](@ref), [`@unpack_fields`](@ref), [`@pack_fields!`](@ref)
Split an expression `expr` of the form `a, b, ... = x` into a tuple consisting of a vector of symbols `a`, `b`, ..., and the right-hand side `x`.
84
+
Split an expression `expr` of the form `a, b, ... = x` (if `object_on_rhs = true`) or `x = a, b, ...` (if `object_on_rhs = false`) into a tuple consisting of a vector of symbols `a`, `b`, ..., and the expression or symbol for `x`.
51
85
52
86
The symbol `macro_name` specifies the macro from which this function is called.
53
87
54
-
This function is used internally with `macrosym = :unpack`and `macrosym = :unpack_fields`.
88
+
This function is used internally with `macrosym = :unpack`, `macrosym = :unpack_fields`, `macrosym = :pack!`, and `macrosym = :pack_fields!`.
55
89
"""
56
-
function split_names_rhs(macrosym::Symbol, expr)
90
+
function split_names_object(macrosym::Symbol, expr, object_on_rhs::Bool)
91
+
# Split expression in LHS and RHS
57
92
if!Meta.isexpr(expr, :(=), 2)
58
93
throw(
59
94
ArgumentError(
60
-
"`@$macrosym` can only be applied to expressions of the form `a, b, ... = x`",
95
+
"`@$macrosym` can only be applied to expressions of the form "*
96
+
(object_on_rhs ?"`a, b, ... = x`":"`x = a, b, ...`"),
61
97
),
62
98
)
63
99
end
64
100
lhs, rhs = expr.args
65
-
names =if lhs isa Symbol
66
-
[lhs]
67
-
elseif Meta.isexpr(lhs, :tuple) &&
68
-
!isempty(lhs.args) &&
69
-
all(x -> x isa Symbol, lhs.args)
70
-
lhs.args
101
+
102
+
# Clean expression with keys a bit:
103
+
# Remove line numbers and unwrap it from `:block` expression
104
+
names_expr = object_on_rhs ? lhs : rhs
105
+
Base.remove_linenums!(names_expr)
106
+
if Meta.isexpr(names_expr, :block, 1)
107
+
names_expr = names_expr.args[1]
108
+
end
109
+
110
+
# Ensure that names are given as symbol or tuple of symbols,
111
+
# and convert them to a vector of symbols
112
+
names =if names_expr isa Symbol
113
+
[names_expr]
114
+
elseif Meta.isexpr(names_expr, :tuple) &&
115
+
!isempty(names_expr.args) &&
116
+
all(x -> x isa Symbol, names_expr.args)
117
+
names_expr.args
71
118
else
72
119
throw(
73
120
ArgumentError(
74
-
"`@$macrosym` can only be applied to expressions of the form `a, b, ... = x`",
121
+
"`@$macrosym` can only be applied to expressions of the form "*
122
+
(object_on_rhs ?"`a, b, ... = x`":"`x = a, b, ...`"),
75
123
),
76
124
)
77
125
end
78
-
return names, rhs
126
+
127
+
# Extract the object
128
+
object = object_on_rhs ? rhs : lhs
129
+
130
+
return names, object
79
131
end
80
132
81
133
"""
82
-
destructuring_expr(fsym::Symbol, names, rhs)
134
+
destructuring_expr(fsym::Symbol, names, object)
83
135
84
-
Return an expression that destructures `rhs` based on a function of name `fsym` and keys `names` into variables of the same `names`.
136
+
Return an expression that destructures `object` based on a function of name `fsym` and keys `names` into variables of the same `names`.
85
137
86
138
This function is used internally with `fsym = :getproperty` and `fsym = :getfield`.
87
139
"""
88
-
function destructuring_expr(fsym::Symbol, names, rhs)
89
-
@gensym object
140
+
function destructuring_expr(fsym::Symbol, names, object)
0 commit comments