diff --git a/Project.toml b/Project.toml index a55f877..a31802b 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,9 @@ version = "0.5.2" [deps] ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" [compat] ConstructionBase = "0.1, 1.0" diff --git a/src/Setfield.jl b/src/Setfield.jl index 576f9cf..35f1068 100644 --- a/src/Setfield.jl +++ b/src/Setfield.jl @@ -2,7 +2,13 @@ __precompile__(true) module Setfield using MacroTools using MacroTools: isstructdef, splitstructdef, postwalk +using Requires: @require +if VERSION < v"1.1-" + using Future: copy! +end + +include("setindex.jl") include("lens.jl") include("sugar.jl") include("functionlenses.jl") @@ -23,4 +29,11 @@ for n in names(Setfield, all=true) end end +function __init__() + @require StaticArrays="90137ffa-7385-5640-81b9-e52037218182" begin + setindex(a::StaticArrays.StaticArray, args...) = + Base.setindex(a, args...) + end +end + end diff --git a/src/lens.jl b/src/lens.jl index 147415f..087b7a8 100644 --- a/src/lens.jl +++ b/src/lens.jl @@ -7,7 +7,7 @@ export constructorof import Base: get -using Base: setindex, getproperty +using Base: getproperty """ Lens diff --git a/src/setindex.jl b/src/setindex.jl new file mode 100644 index 0000000..03639d7 --- /dev/null +++ b/src/setindex.jl @@ -0,0 +1,22 @@ +Base.@propagate_inbounds function setindex(args...) + Base.setindex(args...) +end + +Base.@propagate_inbounds function setindex(xs::AbstractArray, v, I...) + T = promote_type(eltype(xs), typeof(v)) + ys = similar(xs, T) + if eltype(xs) !== Union{} + copy!(ys, xs) + end + ys[I...] = v + return ys +end + +Base.@propagate_inbounds function setindex(d0::AbstractDict, v, k) + K = promote_type(keytype(d0), typeof(k)) + V = promote_type(valtype(d0), typeof(v)) + d = empty(d0, K, V) + copy!(d, d0) + d[k] = v + return d +end diff --git a/test/perf.jl b/test/perf.jl index def0b6b..fe8361c 100644 --- a/test/perf.jl +++ b/test/perf.jl @@ -42,7 +42,7 @@ function lens_set_i((obj, val, i)) end function hand_set_i((obj, val, i)) - @inbounds setindex(obj, val, i) + @inbounds Base.setindex(obj, val, i) end function benchmark_lens_vs_hand(b_lens::Benchmark, b_hand::Benchmark) diff --git a/test/runtests.jl b/test/runtests.jl index 789a3cd..cbadbe9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,6 @@ module TestSetfield +include("test_setindex.jl") include("test_examples.jl") include("test_setmacro.jl") include("test_core.jl") diff --git a/test/test_setindex.jl b/test/test_setindex.jl new file mode 100644 index 0000000..54d3a2d --- /dev/null +++ b/test/test_setindex.jl @@ -0,0 +1,37 @@ +module TestSetindex +using Setfield +using Test + +""" + ==ₜ(x, y) + +Check that _type_ and value of `x` and `y` are equal. +""" +==ₜ(_, _) = false +==ₜ(x::T, y::T) where T = x == y + +@testset "==ₜ" begin + @test 1 ==ₜ 1 + @test !(1.0 ==ₜ 1) +end + +@testset "setindex" begin + arr = [1,2,3] + @test_throws MethodError Base.setindex(arr, 10, 1) + @test Setfield.setindex(arr, 10, 1) == [10, 2, 3] + @test arr == [1,2,3] + @test @set(arr[1] = 10) == [10, 2, 3] + @test arr == [1,2,3] + @test Setfield.setindex(arr, 10.0, 1) ==ₜ Float64[10.0, 2.0, 3.0] + + d = Dict(:a => 1, :b => 2) + @test_throws MethodError Base.setindex(d, 10, :a) + @test Setfield.setindex(d, 10, :a) == Dict(:a=>10, :b=>2) + @test d == Dict(:a => 1, :b => 2) + @test @set(d[:a] = 10) == Dict(:a=>10, :b=>2) + @test d == Dict(:a => 1, :b => 2) + @test Setfield.setindex(d, 30, "c") ==ₜ Dict(:a=>1, :b=>2, "c"=>30) + @test Setfield.setindex(d, 10.0, :a) ==ₜ Dict(:a=>10.0, :b=>2.0) +end + +end