diff --git a/Project.toml b/Project.toml index 24e046a..13543cd 100644 --- a/Project.toml +++ b/Project.toml @@ -1,16 +1,28 @@ name = "ConstructionBase" uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" authors = ["Takafumi Arakaki", "Rafael Schouten", "Jan Weidner"] -version = "1.4.1" +version = "1.5.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +[weakdeps] +IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[extensions] +IntervalSetsExt = "IntervalSets" +StaticArraysExt = "StaticArrays" + [compat] +IntervalSets = "0.5, 0.6, 0.7" +StaticArrays = "1" julia = "1" [extras] +IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["IntervalSets","StaticArrays","Test"] diff --git a/ext/IntervalSetsExt.jl b/ext/IntervalSetsExt.jl new file mode 100644 index 0000000..1208d8e --- /dev/null +++ b/ext/IntervalSetsExt.jl @@ -0,0 +1,8 @@ +module IntervalSetsExt + +using ConstructionBase +using IntervalSets + +ConstructionBase.constructorof(::Type{<:Interval{L, R}}) where {L, R} = Interval{L, R} + +end diff --git a/ext/StaticArraysExt.jl b/ext/StaticArraysExt.jl new file mode 100644 index 0000000..6bcc490 --- /dev/null +++ b/ext/StaticArraysExt.jl @@ -0,0 +1,31 @@ +module StaticArraysExt + +using ConstructionBase +using StaticArrays + +# general static arrays need to keep the size parameter +ConstructionBase.constructorof(sa::Type{<:SArray{S}}) where {S} = SArray{S} +ConstructionBase.constructorof(sa::Type{<:MArray{S}}) where {S} = MArray{S} +ConstructionBase.constructorof(sa::Type{<:SizedArray{S}}) where {S} = SizedArray{S} + +# static vectors don't even need the explicit size specification +ConstructionBase.constructorof(::Type{<:SVector}) = SVector +ConstructionBase.constructorof(::Type{<:MVector}) = MVector + +# set properties by name: x, y, z, w +@generated function ConstructionBase.setproperties(obj::Union{SVector{N}, MVector{N}}, patch::NamedTuple{KS}) where {N, KS} + if KS == (:data,) + :( constructorof(typeof(obj))(only(patch)) ) + else + N <= 4 || error("type $obj does not have properties $(join(KS, ", "))") + propnames = (:x, :y, :z, :w)[1:N] + KS ⊆ propnames || error("type $obj does not have properties $(join(KS, ", "))") + field_exprs = map(enumerate(propnames)) do (i, p) + from = p ∈ KS ? :patch : :obj + :( $from.$p ) + end + :( constructorof(typeof(obj))($(field_exprs...)) ) + end +end + +end diff --git a/test/runtests.jl b/test/runtests.jl index 0cfb291..294fd82 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -467,3 +467,49 @@ end @inferred getproperties(funny_numbers(S,20)) @inferred getproperties(funny_numbers(S,40)) end + + +using StaticArrays, IntervalSets + +if isdefined(Base, :get_extension) # some 1.9 version + @testset "staticarrays" begin + sa = @SVector [2, 4, 6, 8] + sa2 = ConstructionBase.constructorof(typeof(sa))((3.0, 5.0, 7.0, 9.0)) + @test sa2 === @SVector [3.0, 5.0, 7.0, 9.0] + + ma = @MMatrix [2.0 4.0; 6.0 8.0] + ma2 = @inferred ConstructionBase.constructorof(typeof(ma))((1, 2, 3, 4)) + @test ma2 isa MArray{Tuple{2,2},Int,2,4} + @test all(ma2 .=== @MMatrix [1 3; 2 4]) + + sz = SizedArray{Tuple{2,2}}([1 2;3 4]) + sz2 = @inferred ConstructionBase.constructorof(typeof(sz))([:a :b; :c :d]) + @test sz2 == SizedArray{Tuple{2,2}}([:a :b; :c :d]) + @test typeof(sz2) <: SizedArray{Tuple{2,2},Symbol,2,2} + + for T in (SVector, MVector) + @test @inferred(ConstructionBase.constructorof(T)((1, 2, 3)))::T == T((1, 2, 3)) + @test @inferred(ConstructionBase.constructorof(T{3})((1, 2, 3)))::T == T((1, 2, 3)) + @test @inferred(ConstructionBase.constructorof(T{3})((1, 2)))::T == T((1, 2)) + @test @inferred(ConstructionBase.constructorof(T{3, Symbol})((1, 2, 3)))::T == T((1, 2, 3)) + @test @inferred(ConstructionBase.constructorof(T{3, Symbol})((1, 2)))::T == T((1, 2)) + @test @inferred(ConstructionBase.constructorof(T{3, X} where {X})((1, 2, 3)))::T == T((1, 2, 3)) + @test @inferred(ConstructionBase.constructorof(T{3, X} where {X})((1, 2)))::T == T((1, 2)) + @test @inferred(ConstructionBase.constructorof(T{X, Symbol} where {X})((1, 2, 3)))::T == T((1, 2, 3)) + end + + sv = SVector(1, 2) + @test SVector(3.0, 2.0) === @inferred setproperties(sv, x = 3.0) + @test SVector(3.0, 5.0) === @inferred setproperties(sv, x = 3.0, y = 5.0) + @test SVector(-1.0, -2.0) === @inferred setproperties(sv, data = (-1.0, -2)) + @test_throws "does not have properties z" setproperties(sv, z = 3.0) + @test_throws "does not have properties z" setproperties(SVector(1, 2, 3, 4, 5), z = 3.0) + end + + @testset "intervalsets" begin + @test constructorof(typeof(1..2))(0.5, 1.5) === 0.5..1.5 + @test constructorof(typeof(OpenInterval(1, 2)))(0.5, 1.5) === OpenInterval(0.5, 1.5) + @test setproperties(1..2, left=0.0) === 0.0..2.0 + @test setproperties(OpenInterval(1.0, 2.0), left=1, right=5) === OpenInterval(1, 5) + end +end