[
  {
    "path": ".codecov.yml",
    "content": "comment: false\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\non:\n  - push\n  - pull_request\njobs:\n  test:\n    name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        version:\n          - '1.6'\n          - '1'\n          - 'nightly'\n        os:\n          - ubuntu-latest\n        arch:\n          - x64\n        include:\n          - os: macOS-latest\n            version: '1'\n            arch: x64\n          - os: windows-latest\n            version: '1'\n            arch: x64\n    steps:\n      - uses: actions/checkout@v2\n      - uses: julia-actions/setup-julia@v1\n        with:\n          version: ${{ matrix.version }}\n          arch: ${{ matrix.arch }}\n          show-versioninfo: true\n      - uses: actions/cache@v1\n        env:\n          cache-name: cache-artifacts\n        with:\n          path: ~/.julia/artifacts\n          key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}\n          restore-keys: |\n            ${{ runner.os }}-test-${{ env.cache-name }}-\n            ${{ runner.os }}-test-\n            ${{ runner.os }}-\n      - uses: julia-actions/julia-buildpkg@latest\n      - uses: julia-actions/julia-runtest@latest\n  docs:\n    name: Documentation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: julia-actions/setup-julia@v1\n        with:\n          version: 1\n      - run: |\n          julia --project=docs -e '\n            using Pkg\n            Pkg.develop(PackageSpec(path=pwd()))\n            Pkg.instantiate()'\n      - run: |\n          julia --project=docs -e '\n            using Documenter: doctest\n            using Setfield\n            doctest(Setfield)'\n      - run: julia --project=docs docs/make.jl\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".github/workflows/CompatHelper.yml",
    "content": "name: CompatHelper\n\non:\n  schedule:\n    - cron: '00 * * * *'\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        julia-version: [1]\n        julia-arch: [x86]\n        os: [ubuntu-latest]\n    steps:\n      - uses: julia-actions/setup-julia@latest\n        with:\n          version: ${{ matrix.julia-version }}\n      - name: Pkg.add(\"CompatHelper\")\n        run: julia -e 'using Pkg; Pkg.add(\"CompatHelper\")'\n      - name: CompatHelper.main()\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: julia -e 'using CompatHelper; CompatHelper.main()'\n"
  },
  {
    "path": ".github/workflows/Invalidations.yml",
    "content": "name: Invalidations\n\non:\n  pull_request:\n\nconcurrency:\n  # Skip intermediate builds: always.\n  # Cancel intermediate builds: always.\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  evaluate:\n    # Only run on PRs to the default branch.\n    # In the PR trigger above branches can be specified only explicitly whereas this check should work for master, main, or any other default branch\n    if: github.base_ref == github.event.repository.default_branch\n    runs-on: ubuntu-latest\n    steps:\n    - uses: julia-actions/setup-julia@v1\n      with:\n        version: '1'\n    - uses: actions/checkout@v3\n    - uses: julia-actions/julia-buildpkg@v1\n    - uses: julia-actions/julia-invalidations@v1\n      id: invs_pr\n\n    - uses: actions/checkout@v3\n      with:\n        ref: ${{ github.event.repository.default_branch }}\n    - uses: julia-actions/julia-buildpkg@v1\n    - uses: julia-actions/julia-invalidations@v1\n      id: invs_default\n    \n    - name: Report invalidation counts\n      run: |\n        echo \"Invalidations on default branch: ${{ steps.invs_default.outputs.total }} (${{ steps.invs_default.outputs.deps }} via deps)\" >> $GITHUB_STEP_SUMMARY\n        echo \"This branch: ${{ steps.invs_pr.outputs.total }} (${{ steps.invs_pr.outputs.deps }} via deps)\" >> $GITHUB_STEP_SUMMARY\n    - name: Check if the PR does increase number of invalidations\n      if: steps.invs_pr.outputs.total > steps.invs_default.outputs.total\n      run: exit 1\n"
  },
  {
    "path": ".github/workflows/TagBot.yml",
    "content": "name: TagBot\non:\n  issue_comment:\n    types:\n      - created\n  workflow_dispatch:\njobs:\n  TagBot:\n    if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: JuliaRegistries/TagBot@v1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          ssh: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.jl.cov\n*.jl.*.cov\n*.jl.mem\nManifest.toml\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The Setfield.jl package is licensed under the MIT \"Expat\" License:\n\n> Copyright (c) 2017: Jan Weidner.\n>\n> Permission is hereby granted, free of charge, to any person obtaining a copy\n> of this software and associated documentation files (the \"Software\"), to deal\n> in the Software without restriction, including without limitation the rights\n> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n> copies of the Software, and to permit persons to whom the Software is\n> furnished to do so, subject to the following conditions:\n>\n> The above copyright notice and this permission notice shall be included in all\n> copies or substantial portions of the Software.\n>\n> THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n> SOFTWARE.\n>\n"
  },
  {
    "path": "Project.toml",
    "content": "name = \"Setfield\"\nuuid = \"efcf1570-3423-57d1-acb7-fd33fddbac46\"\nversion = \"1.1.2\"\n\n[deps]\nConstructionBase = \"187b0558-2788-49d3-abe0-74a17ed4e7c9\"\nFuture = \"9fa8497b-333b-5362-9e8d-4d0656e87820\"\nMacroTools = \"1914dd2f-81c6-5fcd-8719-6d5c9610ff09\"\nStaticArraysCore = \"1e83bf80-4336-4d27-bf5d-d5a4f845583c\"\n\n[compat]\nConstructionBase = \"0.1, 1.0\"\nStaticArraysCore = \"1\"\nMacroTools = \"0.4.4, 0.5\"\njulia = \"1.6\"\n\n[extras]\nBenchmarkTools = \"6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf\"\nDocumenter = \"e30172f5-a6a5-5a46-863b-614d45cd2de4\"\nInteractiveUtils = \"b77e0a4c-d291-57a0-90e8-8db25a27a240\"\nPerformanceTestTools = \"dc46b164-d16f-48ec-a853-60448fc869fe\"\nQuickTypes = \"ae2dfa86-617c-530c-b392-ef20fdad97bb\"\nStaticArrays = \"90137ffa-7385-5640-81b9-e52037218182\"\nStaticNumbers = \"c5e4b96a-f99f-5557-8ed2-dc63ef9b5131\"\nTest = \"8dfed614-e22c-5e08-85e1-65c5234f0b40\"\n\n[targets]\ntest = [\"Test\", \"Documenter\", \"PerformanceTestTools\", \"QuickTypes\", \"StaticArrays\", \"BenchmarkTools\", \"InteractiveUtils\", \"StaticNumbers\"]\n"
  },
  {
    "path": "README.md",
    "content": "# Setfield\n\n[![DocStable](https://img.shields.io/badge/docs-stable-blue.svg)](https://jw3126.github.io/Setfield.jl/stable/intro)\n[![DocDev](https://img.shields.io/badge/docs-dev-blue.svg)](https://jw3126.github.io/Setfield.jl/dev/intro)\n![CI](https://github.com/jw3126/Setfield.jl/workflows/CI/badge.svg)\n\nUpdate deeply nested immutable structs.\n\n# Lifecycle\n\nWe plan to maintain `Setfield.jl` for a long time (written 2020-09-21, reinforced 2021-08-01, 2022-09-08, 2024-02-15). We will however not add new features. For a successor, see [Accessors.jl](https://github.com/JuliaObjects/Accessors.jl).\n\n# Usage\nUpdating deeply nested immutable structs was never easier:\n```julia\nusing Setfield\n@set obj.a.b.c = d\n```\nFor more information, see [the documentation](https://jw3126.github.io/Setfield.jl/latest/intro/) and/or watch this video:\n\n[![JuliaCon2020 Changing the immutable](https://img.youtube.com/vi/vkAOYeTpLg0/0.jpg)](https://youtu.be/vkAOYeTpLg0 \"Changing the immutable\")\n\n# Some creative usages of Setfield\n\n* [VegaLite.jl](https://github.com/queryverse/VegaLite.jl) overloads\n  `getproperty` and lens API to manipulate JSON-based nested objects.\n\n* [Kaleido.jl](https://github.com/tkf/Kaleido.jl) is a library of\n  additional lenses.\n\n* [PhaseSpaceIO.jl](https://github.com/jw3126/PhaseSpaceIO.jl) overloads\n  `getproperty` and `setproperties` to get/set values from/in packed bits.\n"
  },
  {
    "path": "appveyor.yml",
    "content": "environment:\n  matrix:\n  - JULIA_URL: \"https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe\"\n  - JULIA_URL: \"https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe\"\n  - JULIA_URL: \"https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe\"\n  - JULIA_URL: \"https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe\"\n\n## uncomment the following lines to allow failures on nightly julia\n## (tests will run but not make your overall status red)\n#matrix:\n#  allow_failures:\n#  - JULIA_URL: \"https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe\"\n#  - JULIA_URL: \"https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe\"\n\nbranches:\n  only:\n    - master\n    - /release-.*/\n\nnotifications:\n  - provider: Email\n    on_build_success: false\n    on_build_failure: false\n    on_build_status_changed: false\n\ninstall:\n  - ps: \"[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12\"\n# If there's a newer build queued for the same PR, cancel this one\n  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `\n        https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `\n        Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `\n        throw \"There are newer queued builds for this pull request, failing early.\" }\n# Download most recent Julia Windows binary\n  - ps: (new-object net.webclient).DownloadFile(\n        $env:JULIA_URL,\n        \"C:\\projects\\julia-binary.exe\")\n# Run installer silently, output to C:\\projects\\julia\n  - C:\\projects\\julia-binary.exe /S /D=C:\\projects\\julia\n\nbuild_script:\n# Need to convert from shallow to complete for Pkg.clone to work\n  - IF EXIST .git\\shallow (git fetch --unshallow)\n  - C:\\projects\\julia\\bin\\julia -e \"versioninfo();\n      Pkg.clone(pwd(), \\\"Setfield\\\"); Pkg.build(\\\"Setfield\\\")\"\n\ntest_script:\n  - C:\\projects\\julia\\bin\\julia -e \"Pkg.test(\\\"Setfield\\\")\"\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "build\nsite\n"
  },
  {
    "path": "docs/Project.toml",
    "content": "[deps]\nDocumenter = \"e30172f5-a6a5-5a46-863b-614d45cd2de4\"\nLiterate = \"98b081ad-f1c9-55d3-8b20-4c87d4299306\"\nStaticArrays = \"90137ffa-7385-5640-81b9-e52037218182\"\n"
  },
  {
    "path": "docs/make.jl",
    "content": "using Setfield, Documenter, Literate\n\ninputdir = joinpath(@__DIR__, \"..\", \"examples\")\noutputdir = joinpath(@__DIR__, \"src\", \"examples\")\nmkpath(outputdir)\nfor filename in readdir(inputdir)\n    inpath = joinpath(inputdir, filename)\n    Literate.markdown(inpath, outputdir; documenter=true)\nend\n\nmakedocs(\n         modules = [Setfield],\n         sitename = \"Setfield.jl\",\n         pages = [\n            \"Introduction\" => \"intro.md\",\n            \"Docstrings\" => \"index.md\",\n            \"Custom Macros\" => \"examples/custom_macros.md\",\n             hide(\"internals.md\"),\n            ],\n        strict = true,  # to exit with non-zero code on error\n        )\n\ndeploydocs(\n    repo = \"github.com/jw3126/Setfield.jl.git\",\n)\n"
  },
  {
    "path": "docs/src/examples/.gitignore",
    "content": "*.md\n"
  },
  {
    "path": "docs/src/index.md",
    "content": "## Docstrings\n\n```@autodocs\nModules = [Setfield]\nPrivate = false\n```\n"
  },
  {
    "path": "docs/src/internals.md",
    "content": "# Internals\n\n```@autodocs\nModules = [Setfield]\nPublic = false\n```\n"
  },
  {
    "path": "docs/src/intro.md",
    "content": "## Usage\n\nSay we have a deeply nested struct:\n\n```jldoctest spaceship\njulia> using StaticArrays;\n\njulia> struct Person\n           name::Symbol\n           age::Int\n       end;\n\njulia> struct SpaceShip\n           captain::Person\n           velocity::SVector{3, Float64}\n           position::SVector{3, Float64}\n       end;\n\njulia> s = SpaceShip(Person(:julia, 2009), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])\nSpaceShip(Person(:julia, 2009), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])\n```\nLets update the captains name:\n```jldoctest spaceship; filter = r\" .*$\"\njulia> s.captain.name = :JULIA\nERROR: type Person is immutable\n```\nIt's a bit cryptic but what it means that Julia tried very hard to set the field but gave it up since the struct is immutable.  So we have to do:\n```jldoctest spaceship\njulia> SpaceShip(Person(:JULIA, s.captain.age), s.velocity, s.position)\nSpaceShip(Person(:JULIA, 2009), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])\n```\nThis is messy and things get worse, if the structs are bigger. `Setfields` to the rescue!\n\n```jldoctest spaceship\njulia> using Setfield\n\njulia> s = @set s.captain.name = :JULIA\nSpaceShip(Person(:JULIA, 2009), [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])\n\njulia> s = @set s.velocity[1] += 999999\nSpaceShip(Person(:JULIA, 2009), [999999.0, 0.0, 0.0], [0.0, 0.0, 0.0])\n\njulia> s = @set s.velocity[1] += 1000001\nSpaceShip(Person(:JULIA, 2009), [2.0e6, 0.0, 0.0], [0.0, 0.0, 0.0])\n\njulia> @set s.position[2] = 20\nSpaceShip(Person(:JULIA, 2009), [2.0e6, 0.0, 0.0], [0.0, 20.0, 0.0])\n```\n\n## Under the hood\n\nUnder the hood this package implements a simple [lens](https://hackage.haskell.org/package/lens) api.\nThis api may be useful in its own right and works as follows:\n\n```jldoctest\njulia> using Setfield\n\njulia> l = @lens _.a.b\n(@lens _.a.b)\n\njulia> struct AB;a;b;end\n\njulia> obj = AB(AB(1,2),3)\nAB(AB(1, 2), 3)\n\njulia> set(obj, l, 42)\nAB(AB(1, 42), 3)\n\njulia> obj\nAB(AB(1, 2), 3)\n\njulia> get(obj, l)\n2\n\njulia> modify(x->10x, obj, l)\nAB(AB(1, 20), 3)\n```\n\nNow the `@set` macro simply provides sugar for creating a `lens` and applying it.\nFor instance\n```julia\n@set obj.a.b = 42\n```\nexpands roughly to\n```julia\nl = @lens _.a.b\nset(obj, l, 42)\n```\n"
  },
  {
    "path": "examples/custom_macros.jl",
    "content": "# # Extending `@set` and `@lens`\n# This code demonstrates how to extend the `@set` and `@lens` mechanism with custom\n# lenses.\n# As a demo, we want to implement `@mylens!` and `@myset!`, which work much like \n# `@lens` and `@set`, but mutate objects instead of returning modified copies.\n\nusing Setfield\nusing Setfield: IndexLens, PropertyLens, ComposedLens\n\nstruct Lens!{L <:Lens} <: Lens\n    pure::L\nend\n\nSetfield.get(o, l::Lens!) = Setfield.get(o, l.pure)\nfunction Setfield.set(o, l::Lens!{<: ComposedLens}, val)\n    o_inner = get(o, l.pure.outer)\n    set(o_inner, Lens!(l.pure.inner), val)\nend\nfunction Setfield.set(o, l::Lens!{PropertyLens{prop}}, val) where {prop}\n    setproperty!(o, prop, val)\n    o\nend\nfunction Setfield.set(o, l::Lens!{<:IndexLens}, val) where {prop}\n    o[l.pure.indices...] = val\n    o\nend\n\n# Now this implements the kind of `lens` the new macros should use.\n# Of course there are more variants like `Lens!(<:DynamicIndexLens)`, for which we might\n# want to overload `set`, but lets ignore that. Instead we want to check, that everything works so far:\n\nusing Test\nmutable struct M\n    a\n    b\nend\n\no = M(1,2)\nl = Lens!(@lens _.b)\nset(o, l, 20)\n@test o.b == 20\n\nl = Lens!(@lens _.foo[1])\no = (foo=[1,2,3], bar=:bar)\nset(o, l, 100)\n@test o == (foo=[100,2,3], bar=:bar)\n\n# Now we can implement the syntax macros\n\nusing Setfield: setmacro, lensmacro\n\nmacro myset!(ex)\n    setmacro(Lens!, ex)\nend\n\nmacro mylens!(ex)\n    lensmacro(Lens!, ex)\nend\n\no = M(1,2)\n@myset! o.a = :hi\n@myset! o.b += 98\n@test o.a == :hi\n@test o.b == 100\n\ndeep = [[[[1]]]]\n@myset! deep[1][1][1][1] = 2\n@test deep[1][1][1][1] === 2\n\nl = @mylens! _.foo[1]\no = (foo=[1,2,3], bar=:bar)\nset(o, l, 100)\n@test o == (foo=[100,2,3], bar=:bar)\n\n# Everything works, we can do arbitrary nesting and also use `+=` syntax etc.\n"
  },
  {
    "path": "src/Setfield.jl",
    "content": "__precompile__(true)\nmodule Setfield\nusing MacroTools\nusing MacroTools: isstructdef, splitstructdef, postwalk\nusing StaticArraysCore\n\nif VERSION < v\"1.1-\"\n    using Future: copy!\nend\n\ninclude(\"setindex.jl\")\ninclude(\"lens.jl\")\ninclude(\"sugar.jl\")\ninclude(\"functionlenses.jl\")\n\n# To correctly dispatch to `show(::IO, ::CustomLens)` when it is defined by a\n# user, we avoid defining the generic `show(::IO, ::Lens)`.  This way, we can\n# safely call `show` inside `ComposedLens` without worrying about the\n# `StackOverflowError` that can be easily triggered in the previous approach.\n# See also:\n# * https://github.com/jw3126/Setfield.jl/pull/86\n# * https://github.com/jw3126/Setfield.jl/pull/88\nfor n in names(Setfield, all=true)\n    T = getproperty(Setfield, n)\n    if T isa Type && T <: Lens && (T === ComposedLens || has_atlens_support(T))\n        @eval Base.show(io::IO, l::$T) = _show(io, nothing, l)\n    end\nend\nend\n"
  },
  {
    "path": "src/functionlenses.jl",
    "content": "set(obj, ::typeof(@lens last(_)), val) = @set obj[lastindex(obj)] = val\nset(obj, ::typeof(@lens first(_)), val) = @set obj[firstindex(obj)] = val\n\n################################################################################\n##### eltype\n################################################################################\nfunction set(obj, ::typeof(@lens eltype(_)), ::Type{T}) where {T}\n    return set_eltype(obj, T)\nend\n\nset_eltype(obj::Array,  T::Type) = collect(T, obj)\nset_eltype(obj::Number, T::Type) = T(obj)\nset_eltype(::Type{<:Number}, ::Type{T}) where {T} = T\nset_eltype(::Type{<:Array{<:Any, N}}, ::Type{T}) where {N, T} = Array{T, N}\nset_eltype(::Type{<:Dict}, ::Type{Pair{K, V}}) where {K, V} = Dict{K, V}\nset_eltype(obj::Dict, ::Type{T}) where {T} = set_eltype(typeof(obj), T)(obj)\n\nset(obj::Dict, l::Union{typeof(@lens keytype(_)), typeof(@lens valtype(_))},\n    T::Type) = set(typeof(obj), l, T)(obj)\nset(::Type{<:Dict{<:Any,V}}, ::typeof(@lens keytype(_)), ::Type{K}) where {K, V} =\n    Dict{K, V}\nset(::Type{<:Dict{K}}, ::typeof(@lens valtype(_)), ::Type{V}) where {K, V} =\n    Dict{K, V}\n"
  },
  {
    "path": "src/lens.jl",
    "content": "export Lens, set, get, modify\nexport @lens\nexport set, get, modify\nusing ConstructionBase\nexport setproperties\nexport constructorof\n\n\nimport Base: get, hash, ==\nusing Base: getproperty\n\n\n# used for hashing\nfunction make_salt(s64::UInt64)::UInt\n    if UInt === UInt64\n        return s64\n    else\n        return UInt32(s64 >> 32) ^ UInt32(s64 & 0x00000000ffffffff)\n    end\nend\n\n\n\"\"\"\n    Lens\n\nA `Lens` allows to access or replace deeply nested parts of complicated objects.\n\n# Example\n```jldoctest\njulia> using Setfield\n\njulia> struct T;a;b; end\n\njulia> obj = T(\"AA\", \"BB\")\nT(\"AA\", \"BB\")\n\njulia> lens = @lens _.a\n(@lens _.a)\n\njulia> get(obj, lens)\n\"AA\"\n\njulia> set(obj, lens, 2)\nT(2, \"BB\")\n\njulia> obj\nT(\"AA\", \"BB\")\n\njulia> modify(lowercase, obj, lens)\nT(\"aa\", \"BB\")\n```\n\n# Interface\nConcrete subtypes of `Lens` have to implement\n* `set(obj, lens, val)`\n* `get(obj, lens)`\n\nThese must be pure functions, that satisfy the three lens laws:\n\n```jldoctest; output = false, setup = :(using Setfield; (≅ = (==)); obj = (a=\"A\", b=\"B\"); lens = @lens _.a; val = 2; val1 = 10; val2 = 20)\n@assert get(set(obj, lens, val), lens) ≅ val\n        # You get what you set.\n@assert set(obj, lens, get(obj, lens)) ≅ obj\n        # Setting what was already there changes nothing.\n@assert set(set(obj, lens, val1), lens, val2) ≅ set(obj, lens, val2)\n        # The last set wins.\n\n# output\n\n```\nHere `≅` is an appropriate notion of equality or an approximation of it. In most contexts\nthis is simply `==`. But in some contexts it might be `===`, `≈`, `isequal` or something\nelse instead. For instance `==` does not work in `Float64` context, because\n`get(set(obj, lens, NaN), lens) == NaN` can never hold. Instead `isequal` or\n`≅(x::Float64, y::Float64) = isequal(x,y) | x ≈ y` are possible alternatives.\n\nSee also [`@lens`](@ref), [`set`](@ref), [`get`](@ref), [`modify`](@ref).\n\"\"\"\nabstract type Lens end\n\n\"\"\"\n    modify(f, obj, l::Lens)\n\nReplace a deeply nested part `x` of `obj` by `f(x)`. See also [`Lens`](@ref).\n\"\"\"\nfunction modify end\n\n\n\"\"\"\n    get(obj, l::Lens)\n\nAccess a deeply nested part of `obj`. See also [`Lens`](@ref).\n\"\"\"\nfunction get end\n\n\"\"\"\n    set(obj, l::Lens, val)\n\nReplace a deeply nested part of `obj` by `val`. See also [`Lens`](@ref).\n\"\"\"\nfunction set end\n\n@inline function modify(f, obj, l::Lens)\n    old_val = get(obj, l)\n    new_val = f(old_val)\n    set(obj, l, new_val)\nend\n\nstruct IdentityLens <: Lens end\nget(obj, ::IdentityLens) = obj\nset(obj, ::IdentityLens, val) = val\n\n\nstruct PropertyLens{fieldname} <: Lens end\n\nfunction get(obj, l::PropertyLens{field}) where {field}\n    getproperty(obj, field)\nend\n\n@inline function set(obj, l::PropertyLens{field}, val) where {field}\n    patch = (;field => val)\n    setproperties(obj, patch)\nend\n\nstruct ComposedLens{LO, LI} <: Lens\n    outer::LO\n    inner::LI\nend\n\nfunction ==(l1::ComposedLens, l2::ComposedLens)\n    return l1.outer == l2.outer && l1.inner == l2.inner\nend\n\nconst SALT_COMPOSEDLENS = make_salt(0xcf7322dcc2129a31)\nhash(l::ComposedLens, h::UInt) = hash(l.outer, hash(l.inner, SALT_INDEXLENS + h))\n\n\"\"\"\n    compose([lens₁, [lens₂, [lens₃, ...]]])\n\nCompose `lens₁`, `lens₂` etc. There is one subtle point here:\nWhile the two composition orders `(lens₁ ∘ lens₂) ∘ lens₃` and `lens₁ ∘ (lens₂ ∘ lens₃)` have equivalent semantics,\ntheir performance may not be the same. The compiler tends to optimize right associative composition\n(second case) better then left associative composition.\n\nThe compose function tries to use a composition order, that the compiler likes. The composition order is therefore not part of the stable API.\n\"\"\"\nfunction compose end\ncompose() = IdentityLens()\ncompose(l::Lens) = l\ncompose(::IdentityLens, ::IdentityLens) = IdentityLens()\ncompose(::IdentityLens, l::Lens) = l\ncompose(l::Lens, ::IdentityLens) = l\ncompose(outer::Lens, inner::Lens) = ComposedLens(outer, inner)\nfunction compose(l1::Lens, ls::Lens...)\n    compose(l1, compose(ls...))\nend\n\n\"\"\"\n    lens₁ ∘ lens₂\n\nCompose lenses `lens₁`, `lens₂`, ..., `lensₙ` to access nested objects.\n\n# Example\n```jldoctest\njulia> using Setfield\n\njulia> obj = (a = (b = (c = 1,),),);\n\njulia> la = @lens _.a\n       lb = @lens _.b\n       lc = @lens _.c\n       lens = la ∘ lb ∘ lc\n(@lens _.a.b.c)\n\njulia> get(obj, lens)\n1\n```\n\"\"\"\nBase.:∘(l1::Lens, l2::Lens) = compose(l1, l2)\n\nfunction get(obj, l::ComposedLens)\n    inner_obj = get(obj, l.outer)\n    get(inner_obj, l.inner)\nend\n\nfunction set(obj,l::ComposedLens, val)\n    inner_obj = get(obj, l.outer)\n    inner_val = set(inner_obj, l.inner, val)\n    set(obj, l.outer, inner_val)\nend\n\nstruct IndexLens{I <: Tuple} <: Lens\n    indices::I\nend\n\n==(l1::IndexLens, l2::IndexLens) = l1.indices == l2.indices\n\nconst SALT_INDEXLENS = make_salt(0x8b4fd6f97c6aeed6)\nhash(l::IndexLens, h::UInt) = hash(l.indices, SALT_INDEXLENS + h)\n\nBase.@propagate_inbounds function get(obj, l::IndexLens)\n    getindex(obj, l.indices...)\nend\nBase.@propagate_inbounds function set(obj, l::IndexLens, val)\n    setindex(obj, val, l.indices...)\nend\n\nstruct DynamicIndexLens{F} <: Lens\n    f::F\nend\n\nBase.@propagate_inbounds get(obj, I::DynamicIndexLens) = obj[I.f(obj)...]\n\nBase.@propagate_inbounds set(obj, I::DynamicIndexLens, val) =\n    setindex(obj, val, I.f(obj)...)\n\n\"\"\"\n    FunctionLens(f)\n    @lens f(_)\n\nLens with [`get`](@ref) method definition that simply calls `f`.\n[`set`](@ref) method for each function `f` must be implemented manually.\nUse `methods(set, (Any, Setfield.FunctionLens, Any))` to get a list of\nsupported functions.\n\nNote that `FunctionLens` flips the order of composition; i.e.,\n`(@lens f(_)) ∘ (@lens g(_)) == @lens g(f(_))`.\n\n# Example\n```jldoctest\njulia> using Setfield\n\njulia> obj = ((1, 2), (3, 4));\n\njulia> lens = (@lens first(_)) ∘ (@lens last(_))\n(@lens last(first(_)))\n\njulia> get(obj, lens)\n2\n\njulia> set(obj, lens, '2')\n((1, '2'), (3, 4))\n```\n\n# Implementation\n\nTo use `myfunction` as a lens, define a `set` method with the following\nsignature:\n\n```julia\nSetfield.set(obj, ::typeof(@lens myfunction(_)), val) = ...\n```\n\n`typeof` is used above instead of `FunctionLens` because how actual\ntype of `@lens myfunction(_)` is implemented is not the part of stable\nAPI.\n\"\"\"\nstruct FunctionLens{f} <: Lens end\nFunctionLens(f) = FunctionLens{f}()\n\nget(obj, ::FunctionLens{f}) where f = f(obj)\n"
  },
  {
    "path": "src/setindex.jl",
    "content": "Base.@propagate_inbounds function setindex(args...)\n    Base.setindex(args...)\nend\n\nBase.@propagate_inbounds function setindex(xs::AbstractArray, v, I...)\n    # we need to distinguish between scalar and sliced assignment\n    I_normalized = Base.to_indices(xs, I)\n    T = promote_type(eltype(xs), I_normalized isa Tuple{Vararg{Integer}} ? typeof(v) : eltype(v))\n    ys = similar(xs, T)\n    if eltype(xs) !== Union{}\n        copy!(ys, xs)\n    end\n    ys[I_normalized...] = v\n    return ys\nend\n\nBase.@propagate_inbounds function setindex(d0::AbstractDict, v, k)\n    K = promote_type(keytype(d0), typeof(k))\n    V = promote_type(valtype(d0), typeof(v))\n    d = empty(d0, K, V)\n    copy!(d, d0)\n    d[k] = v\n    return d\nend\n\nsetindex(a::StaticArraysCore.StaticArray, args...) =\n    Base.setindex(a, args...)\n"
  },
  {
    "path": "src/sugar.jl",
    "content": "export @set, @lens, @set!\nusing MacroTools\n\n\"\"\"\n    @set assignment\n\nReturn a modified copy of deeply nested objects.\n\n# Example\n```jldoctest\njulia> using Setfield\n\njulia> struct T;a;b end\n\njulia> t = T(1,2)\nT(1, 2)\n\njulia> @set t.a = 5\nT(5, 2)\n\njulia> t\nT(1, 2)\n\njulia> t = @set t.a = T(2,2)\nT(T(2, 2), 2)\n\njulia> @set t.a.b = 3\nT(T(2, 3), 2)\n```\n\"\"\"\nmacro set(ex)\n    setmacro(identity, ex, overwrite=false)\nend\n\n\"\"\"\n    @set! assignment\n\nShortcut for `obj = @set obj...`.\n\n# Example\n```jldoctest\njulia> using Setfield\n\njulia> t = (a=1,)\n(a = 1,)\n\njulia> @set! t.a=2\n(a = 2,)\n\njulia> t\n(a = 2,)\n```\n\"\"\"\nmacro set!(ex)\n    setmacro(identity, ex, overwrite=true)\nend\n\nis_interpolation(x) = x isa Expr && x.head == :$\n\nfoldtree(op, init, x) = op(init, x)\nfoldtree(op, init, ex::Expr) =\n    op(foldl((acc, x) -> foldtree(op, acc, x), ex.args; init=init), ex)\n\nconst HAS_BEGIN_INDEXING = VERSION ≥ v\"1.5.0-DEV.666\"\n\nfunction need_dynamic_lens(ex)\n    return foldtree(false, ex) do yes, x\n        (yes || x === :end || (HAS_BEGIN_INDEXING && x === :begin) ||\n            x == Expr(:end) || (HAS_BEGIN_INDEXING && x == Expr(:begin)) || x === :_)\n    end\nend\n\nfunction lower_index(collection::Symbol, index, dim)\n    if isexpr(index, :call)\n        return Expr(:call, lower_index.(collection, index.args, dim)...)\n    elseif (index === :end || index == Expr(:end))\n        if dim === nothing\n            return :($(Base.lastindex)($collection))\n        else\n            return :($(Base.lastindex)($collection, $dim))\n        end\n    elseif HAS_BEGIN_INDEXING && (index === :begin || index == Expr(:begin))\n        if dim === nothing\n            return :($(Base.firstindex)($collection))\n        else\n            return :($(Base.firstindex)($collection, $dim))\n        end\n    end\n    return index\nend\n\nreplace_underscore(ex, to) = postwalk(x -> x === :_ ? to : x, ex)\n\nfunction parse_obj_lenses_composite(lensexprs::Vector)\n    if isempty(lensexprs)\n        return esc(:_), ()\n    else\n        obj, outermostlens = parse_obj_lens(lensexprs[1])\n        innerlenses = map(lensexprs[2:end]) do innerex\n            o, lens = parse_obj_lens(innerex)\n            @assert o == esc(:_)\n            lens\n        end\n        return obj, (outermostlens, innerlenses...)\n    end\nend\n\nfunction parse_obj_lenses(ex)\n    if @capture(ex, ∘(lensexprs__))\n        return parse_obj_lenses_composite(lensexprs)\n    elseif is_interpolation(ex)\n        @assert length(ex.args) == 1\n        return esc(:_), (esc(ex.args[1]),)\n    elseif @capture(ex, front_[indices__])\n        obj, frontlens = parse_obj_lenses(front)\n        if any(need_dynamic_lens, indices)\n            @gensym collection\n            indices = replace_underscore.(indices, collection)\n            dims = length(indices) == 1 ? nothing : 1:length(indices)\n            lindices = esc.(lower_index.(collection, indices, dims))\n            lens = :($DynamicIndexLens($(esc(collection)) -> ($(lindices...),)))\n        else\n            index = esc(Expr(:tuple, indices...))\n            lens = :($IndexLens($index))\n        end\n    elseif @capture(ex, front_.property_)\n        obj, frontlens = parse_obj_lenses(front)\n        if property isa Union{Symbol,String}\n            lens = :($PropertyLens{$(QuoteNode(property))}())\n        elseif is_interpolation(property)\n            lens = :($PropertyLens{$(esc(property.args[1]))}())\n        else\n            throw(ArgumentError(\n                string(\"Error while parsing :($ex). Second argument to `getproperty` can only be\",\n                       \"a `Symbol` or `String` literal, received `$property` instead.\")\n            ))\n        end\n    elseif @capture(ex, f_(front_))\n        obj, frontlens = parse_obj_lenses(front)\n        lens = :($FunctionLens($(esc(f))))\n    else\n        obj = esc(ex)\n        return obj, ()\n    end\n    obj, tuple(frontlens..., lens)\nend\n\nfunction parse_obj_lens(ex)\n    obj, lenses = parse_obj_lenses(ex)\n    lens = Expr(:call, compose, lenses...)\n    obj, lens\nend\n\nfunction get_update_op(sym::Symbol)\n    s = String(sym)\n    if !endswith(s, '=') || isdefined(Base, sym)\n        # 'x +=' etc. is actually 'x = x +', and so '+=' isn't defined in Base.\n        # '>=' however is a function, and not an assignment operator.\n        msg = \"Operation $sym doesn't look like an assignment\"\n        throw(ArgumentError(msg))\n    end\n    Symbol(s[1:end-1])\nend\n\nstruct _UpdateOp{OP,V}\n    op::OP\n    val::V\nend\n(u::_UpdateOp)(x) = u.op(x, u.val)\n\n\"\"\"\n    setmacro(lenstransform, ex::Expr; overwrite::Bool=false)\n\nThis function can be used to create a customized variant of [`@set`](@ref).\nIt works by applying `lenstransform` to the lens that is used in the customized `@set` macro\nat runtime.\n```julia\nfunction mytransform(lens::Lens)::Lens\n    ...\nend\nmacro myset(ex)\n    setmacro(mytransform, ex)\nend\n```\nSee also [`lensmacro`](@ref).\n\"\"\"\nfunction setmacro(lenstransform, ex::Expr; overwrite::Bool=false)\n    @assert ex.head isa Symbol\n    @assert length(ex.args) == 2\n    ref, val = ex.args\n    obj, lens = parse_obj_lens(ref)\n    lenssym = gensym(:lens)\n    dst = overwrite ? obj : gensym(\"_\")\n    val = esc(val)\n    ret = if ex.head == :(=)\n        quote\n            $lenssym = ($lenstransform)($lens)\n            $dst = $set($obj, $lenssym, $val)\n        end\n    else\n        op = get_update_op(ex.head)\n        f = :($_UpdateOp($op,$val))\n        quote\n            $lenssym = ($lenstransform)($lens)\n            $dst = $modify($f, $obj, $lenssym)\n        end\n    end\n    ret\nend\n\n\"\"\"\n    @lens\n\nConstruct a lens from a field access.\n\n# Example\n\n```jldoctest\njulia> using Setfield\n\njulia> struct T;a;b;end\n\njulia> t = T(\"A1\", T(T(\"A3\", \"B3\"), \"B2\"))\nT(\"A1\", T(T(\"A3\", \"B3\"), \"B2\"))\n\njulia> l = @lens _.b.a.b\n(@lens _.b.a.b)\n\njulia> get(t, l)\n\"B3\"\n\njulia> set(t, l, 100)\nT(\"A1\", T(T(\"A3\", 100), \"B2\"))\n\njulia> t = (\"one\", \"two\")\n(\"one\", \"two\")\n\njulia> set(t, (@lens _[1]), \"1\")\n(\"1\", \"two\")\n\njulia> # Indices are always evaluated in external scope; for properties, you can use interpolation:\n       n, i = :a, 10\n       @lens(_.\\$n[i, i+1])\n(@lens _.a[10, 11])\n```\n\n\"\"\"\nmacro lens(ex)\n    lensmacro(identity, ex)\nend\n\n\n\"\"\"\n    lensmacro(lenstransform, ex::Expr)\n\nThis function can be used to create a customized variant of [`@lens`](@ref).\nIt works by applying `lenstransform` to the created lens at runtime.\n```julia\nfunction mytransform(lens::Lens)::Lens\n    ...\nend\nmacro mylens(ex)\n    lensmacro(mytransform, ex)\nend\n```\nSee also [`setmacro`](@ref).\n\"\"\"\nfunction lensmacro(lenstransform, ex)\n    obj, lens = parse_obj_lens(ex)\n    if obj != esc(:_)\n        msg = \"\"\"Cannot parse lens $ex. Lens expressions must start with _, got $obj instead.\"\"\"\n        throw(ArgumentError(msg))\n    end\n    :($(lenstransform)($lens))\nend\n\nhas_atlens_support(l::Lens) = has_atlens_support(typeof(l))\nhas_atlens_support(::Type{<:Lens}) = false\nhas_atlens_support(::Type{<:Union{PropertyLens, IndexLens, FunctionLens, IdentityLens}}) =\n    true\nhas_atlens_support(::Type{ComposedLens{LO, LI}}) where {LO, LI} =\n    has_atlens_support(LO) && has_atlens_support(LI)\n\nprint_application(io::IO, l::PropertyLens{field}) where {field} = print(io, \".\", field)\nprint_application(io::IO, l::IndexLens) = print(io, \"[\", join(repr.(l.indices), \", \"), \"]\")\nprint_application(io::IO, l::IdentityLens) = print(io, \"\")\n\nfunction print_application(io::IO, l::ComposedLens)\n    print_application(io, l.outer)\n    print_application(io, l.inner)\nend\n\nfunction print_application(printer, io, ::FunctionLens{f}) where f\n    print(io, f, '(')\n    printer(io)\n    print(io, ')')\nend\n\nfunction print_application(printer, io, l)\n    @assert has_atlens_support(l)\n    printer(io)\n    print_application(io, l)\nend\n\nfunction print_application(printer, io, l::ComposedLens)\n    print_application(io, l.inner) do io\n        print_application(printer, io, l.outer)\n    end\nend\n\n# Since `show` of `ComposedLens` needs to call `show` of other lenses,\n# we explicitly define text/plain `show` for `ComposedLens` to propagate\n# the \"context\" (2-arg or 3-arg `show`) with which `show` has to be called.\n# See: https://github.com/jw3126/Setfield.jl/pull/86\nBase.show(io::IO, ::MIME\"text/plain\", l::ComposedLens) =\n    _show(io, MIME(\"text/plain\"), l)\n\nfunction _show(io::IO, mime, l::Lens)\n    if has_atlens_support(l)\n        print_in_atlens(io, l)\n    elseif mime === nothing\n        show(io, l)\n    else\n        show(io, mime, l)\n    end\nend\n\nfunction _show(io::IO, mime, l::ComposedLens)\n    if has_atlens_support(l)\n        print_in_atlens(io, l)\n    else\n        _show(io, mime, l.outer)\n        print(io, \" ∘ \")\n        _show(io, mime, l.inner)\n    end\nend\n\nfunction print_in_atlens(io, l)\n    print(io, \"(@lens \")\n    print_application(io, l) do io\n        print(io, '_')\n    end\n    print(io, ')')\nend\n"
  },
  {
    "path": "test/dynamiclens_begin.jl",
    "content": "l = @lens _[begin]\n@test l isa Setfield.DynamicIndexLens\nobj = (1,2,3)\n@test get(obj, l) == 1\n@test set(obj, l, true) == (true,2,3)\n\nl = @lens _[2*begin]\n@test l isa Setfield.DynamicIndexLens\nobj = (1,2,3)\n@test get(obj, l) == 2\n@test set(obj, l, true) == (1,true,3)\n\none = 1\nplustwo(x) = x + 2\nl = @lens _.a[plustwo(begin) - one].b\nobj = (a=(1, (a=10, b=20), 3), b=4)\n@test get(obj, l) == 20\n@test set(obj, l, true) == (a=(1, (a=10, b=true), 3), b=4)\n"
  },
  {
    "path": "test/perf.jl",
    "content": "module Perf\nusing BenchmarkTools\nusing BenchmarkTools: Benchmark, TrialEstimate\nusing Setfield\nusing Test\nusing InteractiveUtils\nusing StaticArrays\n\nstruct AB{A,B}\n    a::A\n    b::B\nend\n\nfunction lens_set_a((obj, val))\n    @set obj.a = val\nend\n\nfunction hand_set_a((obj, val))\n    AB(val, obj.b)\nend\n\nfunction lens_set_ab((obj, val))\n    @set obj.a.b = val\nend\n\nfunction hand_set_ab((obj, val))\n    a = AB(obj.a.a, val)\n    AB(a, obj.b)\nend\n\nfunction lens_set_a_and_b((obj, val))\n    o1 = @set obj.a = val\n    o2 = @set o1.b = val\nend\n\nfunction hand_set_a_and_b((obj, val))\n    AB(val, val)\nend\n\nfunction lens_set_i((obj, val, i))\n    @inbounds (@set obj[i] = val)\nend\n\nfunction hand_set_i((obj, val, i))\n    @inbounds Base.setindex(obj, val, i)\nend\n\nfunction benchmark_lens_vs_hand(b_lens::Benchmark, b_hand::Benchmark)\n\n    te_hand = minimum(run(b_lens))\n    te_lens = minimum(run(b_hand))\n    @show te_lens\n    @show te_hand\n    @test te_lens.memory == te_hand.memory\n    @test te_lens.allocs == te_hand.allocs\n    @test te_lens.time <= 2*te_hand.time\nend\n\nfunction uniquecounts(iter)\n    ret = Dict{eltype(iter), Int}()\n    for x in iter\n        ret[x] = get!(ret, x, 0) + 1\n    end\n    ret\nend\n\nfunction test_ir_lens_vs_hand(info_lens::Core.CodeInfo,\n                              info_hand::Core.CodeInfo)\n\n    heads(info) = [ex.head for ex in info.code if ex isa Expr]\n\n    # test no needless kinds of operations\n    heads_lens = heads(info_lens)\n    heads_hand = heads(info_hand)\n    @test Set(heads_lens) == Set(heads_hand)\n\n    # test no intermediate objects or lenses\n    @test count(==(:new), heads_lens) == count(==(:new), heads_hand)\n\n    # this test might be too strict\n    @test uniquecounts(heads_lens) == uniquecounts(heads_hand)\nend\n\nlet\n    obj = AB(AB(1,2), :b)\n    val = (1,2)\n    @testset \"$(setup.lens)\" for setup in [\n            (lens=lens_set_a,           hand=hand_set_a,       args=(obj, val)),\n            (lens=lens_set_a,           hand=hand_set_a,       args=(obj, val)),\n            (lens=lens_set_ab,          hand=hand_set_ab,      args=(obj, val)),\n            (lens=lens_set_a_and_b,     hand=hand_set_a_and_b, args=(obj, val)),\n            (lens=lens_set_i,           hand=hand_set_i,\n             args=(@SVector[1,2], 10, 1))\n            ]\n        f_lens = setup.lens\n        f_hand = setup.hand\n        args = setup.args\n\n        @assert f_hand(args) == f_lens(args)\n\n        @testset \"IR\" begin\n            info_lens, _ = @code_typed f_lens(args)\n            info_hand, _ = @code_typed f_hand(args)\n            test_ir_lens_vs_hand(info_lens, info_hand)\n        end\n\n        @testset \"benchmark\" begin\n            b_lens = @benchmarkable $f_lens($args)\n            b_hand = @benchmarkable $f_hand($args)\n            benchmark_lens_vs_hand(b_lens, b_hand)\n        end\n    end\nend\n\nfunction compose_left_assoc(obj, val)\n    l = @lens ((_.a∘_.b)∘_.c)∘_.d\n    set(obj, l, val)\nend\n\nfunction compose_right_assoc(obj, val)\n    l = @lens _.a∘(_.b∘(_.c∘_.d))\n    set(obj, l, val)\nend\nfunction compose_default_assoc(obj, val)\n    l = @lens _.a.b.c.d\n    set(obj, l, val)\nend\n@testset \"Lens composition compiler prefered associativity\" begin\n\n    obj = (a=(b=(c=(d=1,d2=2),c2=2),b2=3), a2=2)\n    val = 2.2\n    @test compose_left_assoc(obj, val) == compose_default_assoc(obj, val)\n    @test compose_right_assoc(obj, val) == compose_default_assoc(obj, val)\n\n    b_default = minimum(@benchmark compose_default_assoc($obj, $val))\n    println(\"Default associative composition: $b_default\")\n    b_left    = minimum(@benchmark compose_left_assoc($obj, $val)   )\n    println(\"Left associative composition: $b_left\")\n    b_right   = minimum(@benchmark compose_right_assoc($obj, $val)  )\n    println(\"Right associative composition: $b_right\")\n\n    @test b_default.allocs == 0\n    @test b_right.allocs == 0\n    @test_broken b_left.allocs == 0\n\n    @test b_left.time > 2b_default.time\n    @test b_right.time ≈ b_default.time rtol=0.8\nend\n\nend\n"
  },
  {
    "path": "test/runtests.jl",
    "content": "module TestSetfield\n\nimport PerformanceTestTools\nimport Setfield\nusing Documenter: doctest\n\ninclude(\"test_setindex.jl\")\ninclude(\"test_examples.jl\")\ninclude(\"test_setmacro.jl\")\ninclude(\"test_core.jl\")\ninclude(\"test_functionlenses.jl\")\ninclude(\"test_staticarrays.jl\")\ninclude(\"test_quicktypes.jl\")\nPerformanceTestTools.@include(\"perf.jl\")\n\ndoctest(Setfield)\n\nend  # module\n"
  },
  {
    "path": "test/test_core.jl",
    "content": "module TestCore\nusing Test\nusing Setfield\nusing Setfield: compose, get_update_op\nusing ConstructionBase: ConstructionBase\nusing StaticNumbers: static\n\nstruct T\n    a\n    b\nend\n\nstruct TT{A,B}\n    a::A\n    b::B\nend\n\n@testset \"get_update_op\" begin\n    @test get_update_op(:(&=)) === :(&)\n    @test get_update_op(:(^=)) === :(^)\n    @test get_update_op(:(-=)) === :(-)\n    @test get_update_op(:(%=)) === :(%)\n    @test_throws ArgumentError get_update_op(:(++))\n    @test_throws ArgumentError get_update_op(:(<=))\nend\n\n@testset \"@set!\" begin\n    a = 1\n    @set a = 2\n    @test a === 1\n    @set! a = 2\n    @test a === 2\n\n    t = T(1, T(2,3))\n    @set t.b.a = 20\n    @test t === T(1, T(2,3))\n\n    @set! t.b.a = 20\n    @test t === T(1,T(20,3))\n\n    a = 1\n    @set! a += 10\n    @test a === 11\n    nt = (a=1,)\n    @set! nt.a = 5\n    @test nt === (a=5,)\nend\n\n@testset \"@set\" begin\n\n    t = T(1, T(2, T(T(4,4),3)))\n    s = @set t.b.b.a.a = 5\n    @test t === T(1, T(2, T(T(4,4),3)))\n    @test s === T(1, T(2, T(T(5, 4), 3)))\n    @test_throws ArgumentError @set t.b.b.a.a.a = 3\n\n    t = T(1,2)\n    @test T(1, T(1,2)) === @set t.b = T(1,2)\n    @test_throws ArgumentError @set t.c = 3\n\n    t = T(T(2,2), 1)\n    s = @set t.a.a = 3\n    @test s === T(T(3, 2), 1)\n\n    t = T(1, T(2, T(T(4,4),3)))\n    s = @set t.b.b = 4\n    @test s === T(1, T(2, 4))\n\n    t = T(1,2)\n    s = @set t.a += 1\n    @test s === T(2,2)\n\n    t = T(1,2)\n    s = @set t.b -= 2\n    @test s === T(1,0)\n\n    t = T(10, 20)\n    s = @set t.a *= 10\n    @test s === T(100, 20)\n\n    t = T(2,1)\n    s = @set t.a /= 2\n    @test s === T(1.0,1)\n\n    t = T(1, 2)\n    s = @set t.a <<= 2\n    @test s === T(4, 2)\n\n    t = T(8, 2)\n    s = @set t.a >>= 2\n    @test s === T(2, 2)\n\n    t = T(1, 2)\n    s = @set t.a &= 0\n    @test s === T(0, 2)\n\n    t = T(1, 2)\n    s = @set t.a |= 2\n    @test s === T(3, 2)\n\n    t = T((1,2),(3,4))\n    @set t.a[1] = 10\n    s1 = @set t.a[1] = 10\n    @test s1 === T((10,2),(3,4))\n    i = 1\n    si = @set t.a[i] = 10\n    @test s1 === si\n    se = @set t.a[end] = 20\n    @test se === T((1,20),(3,4))\n    se1 = @set t.a[end-1] = 10\n    @test s1 === se1\n\n    s1 = @set t.a[static(1)] = 10\n    @test s1 === T((10,2),(3,4))\n    i = 1\n    si = @set t.a[static(i)] = 10\n    @test s1 === si\n\n    t = @set T(1,2).a = 2\n    @test t === T(2,2)\n\n    t = (1, 2, 3, 4)\n    @test (@set t[length(t)] = 40) === (1, 2, 3, 40)\n    @test (@set t[length(t) ÷ 2] = 20) === (1, 20, 3, 4)\nend\n\n\nstruct UserDefinedLens <: Lens end\n\nstruct LensWithTextPlain <: Lens end\nBase.show(io::IO, ::MIME\"text/plain\", ::LensWithTextPlain) =\n    print(io, \"I define text/plain.\")\n\n\n@testset \"show it like you build it \" begin\n    i = 3\n    @testset for item in [\n            @lens _.a\n            @lens _[1]\n            @lens _[:a]\n            @lens _[\"a\"]\n            @lens _[static(1)]\n            @lens _[static(1), static(1 + 1)]\n            @lens _.a.b[:c][\"d\"][2][static(3)]\n            @lens _\n            @lens first(_)\n            @lens last(first(_))\n            @lens last(first(_.a))[1]\n            UserDefinedLens()\n            (@lens _.a) ∘ UserDefinedLens()\n            UserDefinedLens() ∘ (@lens _.b)\n            (@lens _.a) ∘ UserDefinedLens() ∘ (@lens _.b)\n            (@lens _.a) ∘ LensWithTextPlain() ∘ (@lens _.b)\n        ]\n        buf = IOBuffer()\n        show(buf, item)\n        item2 = eval(Meta.parse(String(take!(buf))))\n        @test item === item2\n    end\nend\n\nfunction test_getset_laws(lens, obj, val1, val2)\n\n    # set ∘ get\n    val = get(obj, lens)\n    @test set(obj, lens, val) == obj\n\n    # get ∘ set\n    obj1 = set(obj, lens, val1)\n    @test get(obj1, lens) == val1\n\n    # set idempotent\n    obj12 = set(obj1, lens, val2)\n    obj2 = set(obj, lens, val2)\n    @test obj12 == obj2\nend\n\nfunction test_modify_law(f, lens, obj)\n    obj_modify = modify(f, obj, lens)\n    old_val = get(obj, lens)\n    val = f(old_val)\n    obj_setfget = set(obj, lens, val)\n    @test obj_modify == obj_setfget\nend\n\n@testset \"lens laws\" begin\n    obj = T(2, T(T(3,(4,4)), 2))\n    i = 2\n    for lens ∈ [\n            @lens _.a\n            @lens _.b\n            @lens _.b.a\n            @lens _.b.a.b[2]\n            @lens _.b.a.b[i]\n            @lens _.b.a.b[static(2)]\n            @lens _.b.a.b[static(i)]\n            @lens _.b.a.b[end]\n            @lens _.b.a.b[identity(end) - 1]\n            @lens _\n        ]\n        val1, val2 = randn(2)\n        f(x) = (x,x)\n        test_getset_laws(lens, obj, val1, val2)\n        test_modify_law(f, lens, obj)\n    end\nend\n\n@testset \"equality & hashing\" begin\n    # singletons (identity and property lens) are egal\n    for (l1, l2) ∈ [\n        @lens(_) => @lens(_),\n        @lens(_.a) => @lens(_.a),\n    ]\n        @test l1 === l2\n        @test l1 == l2\n        @test hash(l1) == hash(l2)\n    end\n\n    # composite and index lenses are structurally equal\n    for (l1, l2) ∈ [\n        @lens(_[1]) => @lens(_[1]),\n        @lens(_.a[2]) => @lens(_.a[2]),\n        @lens(_.a.b[3]) => @lens(_.a.b[3]),\n        @lens(_[1:10]) => @lens(_[1:10]),\n        @lens(_.a[2:20]) => @lens(_.a[2:20]),\n        @lens(_.a.b[3:30]) => @lens(_.a.b[3:30]),\n    ]\n        @test l1 == l2\n        @test hash(l1) == hash(l2)\n    end\n\n    # inequality\n    for (l1, l2) ∈ [\n        @lens(_[1]) => @lens(_[2]),\n        @lens(_.a[1]) => @lens(_.a[2]),\n        @lens(_.a[1]) => @lens(_.b[1]),\n        @lens(_[1:10]) => @lens(_[2:20]),\n        @lens(_.a[1:10]) => @lens(_.a[2:20]),\n        @lens(_.a[1:10]) => @lens(_.b[1:10]),\n    ]\n        @test l1 != l2\n    end\n\n    # equality with non-equal range types (#165)\n    for (l1, l2) ∈ [\n        @lens(_[1:10]) => @lens(_[Base.OneTo(10)]),\n        @lens(_.a[1:10]) => @lens(_.a[Base.OneTo(10)]),\n        @lens(_.a.b[1:10]) => @lens(_.a.b[Base.OneTo(10)]),\n        @lens(_.a[Base.StepRange(1, 1, 5)].b[1:10]) => @lens(_.a[1:5].b[Base.OneTo(10)]),\n        @lens(_.a.b[1:3]) => @lens(_.a.b[[1, 2, 3]]),\n    ]\n        @test l1 == l2\n        @test hash(l1) == hash(l2)\n    end\n\n    # Hash property: equality implies equal hashes, or in other terms:\n    # lenses either have equal hashes or are unequal\n    # Because collisions can occur theoretically (though unlikely), this is a property test,\n    # not a unit test.\n    random_lenses = (@lens(_.a[rand(Int)]) for _ in 1:1000)\n    @test all((hash(l2) == hash(l1)) || (l1 != l2)\n              for (l1, l2) in zip(random_lenses, random_lenses))\n\n    # Lenses should hash differently from the underlying tuples, to avoid confusion.\n    # To account for potential collisions, we check that the property holds with high\n    # probability.  \n    @test count(hash(@lens(_[i])) != hash((i,)) for i = 1:1000) > 900\n\n    # Same for tuples of tuples (√(1000) ≈ 32).\n    @test count(hash(@lens(_[i][j])) != hash(((i,), (j,))) for i = 1:32, j = 1:32) > 900\nend\n\n\n@testset \"type stability\" begin\n    o1 = 2\n    o22 = 2\n    o212 = (4,4)\n    o211 = 3\n    o21 = TT(o211, o212)\n    o2 = TT(o21, o22)\n    obj = TT(o1, o2)\n    @assert obj === TT(2, TT(TT(3,(4,4)), 2))\n    i = 1\n    for (lens, val) ∈ [\n          ((@lens _.a           ),   o1 ),\n          ((@lens _.b           ),   o2 ),\n          ((@lens _.b.a         ),   o21),\n          ((@lens _.b.a.b[2]    ),   4  ),\n          ((@lens _.b.a.b[i+1]  ),   4  ),\n          ((@lens _.b.a.b[static(2)]   ),   4  ),\n          ((@lens _.b.a.b[static((i+1))]),  4  ),\n          ((@lens _.b.a.b[static(2)]   ),   4.0),\n          ((@lens _.b.a.b[static((i+1))]),  4.0),\n          ((@lens _.b.a.b[end]),     4.0),\n          ((@lens _.b.a.b[end÷2+1]), 4.0),\n          ((@lens _             ),   obj),\n          ((@lens _             ),   :xy),\n        ]\n        @inferred get(obj, lens)\n        @inferred set(obj, lens, val)\n        @inferred modify(identity, obj, lens)\n    end\nend\n\n@testset \"IndexLens\" begin\n    l = @lens _[]\n    @test l isa Setfield.IndexLens\n    x = randn()\n    obj = Ref(x)\n    @test get(obj, l) == x\n\n    l = @lens _[][]\n    @test l.outer isa Setfield.IndexLens\n    @test l.inner isa Setfield.IndexLens\n    inner = Ref(x)\n    obj = Base.RefValue{typeof(inner)}(inner)\n    @test get(obj, l) == x\n\n    obj = (1,2,3)\n    l = @lens _[1]\n    @test l isa Setfield.IndexLens\n    @test get(obj, l) == 1\n    @test set(obj, l, 6) == (6,2,3)\n\n\n    l = @lens _[1:3]\n    @test l isa Setfield.IndexLens\n    @test get([4,5,6,7], l) == [4,5,6]\nend\n\n@testset \"DynamicIndexLens\" begin\n    l = @lens _[end]\n    @test l isa Setfield.DynamicIndexLens\n    obj = (1,2,3)\n    @test get(obj, l) == 3\n    @test set(obj, l, true) == (1,2,true)\n\n    l = @lens _[end÷2]\n    @test l isa Setfield.DynamicIndexLens\n    obj = (1,2,3)\n    @test get(obj, l) == 1\n    @test set(obj, l, true) == (true,2,3)\n\n    two = 2\n    plusone(x) = x + 1\n    l = @lens _.a[plusone(end) - two].b\n    obj = (a=(1, (a=10, b=20), 3), b=4)\n    @test get(obj, l) == 20\n    @test set(obj, l, true) == (a=(1, (a=10, b=true), 3), b=4)\n\n    if Setfield.HAS_BEGIN_INDEXING\n        # Need to keep this in a separate file since `begin` won't parse\n        # on older Julia versions.\n        include(\"dynamiclens_begin.jl\")\n    end\nend\n\n@testset \"StaticNumbers\" begin\n    obj = (1, 2.0, '3')\n    l = @lens _[static(1)]\n    @test (@inferred get(obj, l)) === 1\n    @test (@inferred set(obj, l, 6.0)) === (6.0, 2.0, '3')\n    l = @lens _[static(1 + 1)]\n    @test (@inferred get(obj, l)) === 2.0\n    @test (@inferred set(obj, l, 6)) === (1, 6, '3')\n    n = 1\n    l = @lens _[static(3n)]\n    @test (@inferred get(obj, l)) === '3'\n    @test (@inferred set(obj, l, 6)) === (1, 2.0, 6)\n\n    l = @lens _[static(1):static(3)]\n    @test get([4,5,6,7], l) == [4,5,6]\n\n    @testset \"complex example (sweeper)\" begin\n        sweeper_with_const = (\n            model = (1, 2.0, 3im),\n            axis = (@lens _[static(2)]),\n        )\n\n        sweeper_with_noconst = @set sweeper_with_const.axis = @lens _[2]\n\n        function f(s)\n            a = sum(set(s.model, s.axis, 0))\n            for i in 1:10\n                a += sum(set(s.model, s.axis, i))\n            end\n            return a\n        end\n\n        @test (@inferred f(sweeper_with_const)) == 66 + 33im\n        @test_broken (@inferred f(sweeper_with_noconst)) == 66 + 33im\n    end\nend\n\nmutable struct M\n    a\n    b\nend\n\n@testset \"IdentityLens\" begin\n    id = @lens _\n    @test compose(id, id) === id\n    obj1 = M(1,1)\n    obj2 = M(2,2)\n    @test obj2 === set(obj1, id, obj2)\n    la = @lens _.a\n    @test compose(id, la) === la\n    @test compose(la, id) === la\nend\n\nstruct ABC{A,B,C}\n    a::A\n    b::B\n    c::C\nend\n\n@testset \"type change during @set (default constructorof)\" begin\n    obj = TT(2,3)\n    obj2 = @set obj.b = :three\n    @test obj2 === TT(2, :three)\nend\n\n# https://github.com/tkf/Reconstructables.jl#how-to-use-type-parameters\nstruct B{T, X, Y}\n    x::X\n    y::Y\n    B{T}(x::X, y::Y = 2) where {T, X, Y} = new{T, X, Y}(x, y)\nend\nConstructionBase.constructorof(::Type{<: B{T}}) where T = B{T}\n\n@testset \"type change during @set (custom constructorof)\" begin\n    obj = B{1}(2,3)\n    obj2 = @set obj.y = :three\n    @test obj2 === B{1}(2, :three)\nend\n\n@testset \"text/plain show\" begin\n    @testset for lens in [\n        LensWithTextPlain()\n        (@lens _.a) ∘ LensWithTextPlain()\n        LensWithTextPlain() ∘ (@lens _.b)\n        (@lens _.a) ∘ LensWithTextPlain() ∘ (@lens _.b)\n    ]\n        @test occursin(\"I define text/plain.\", sprint(show, \"text/plain\", lens))\n    end\n\n    @testset for lens in [\n        UserDefinedLens()\n        (@lens _.a) ∘ UserDefinedLens()\n        UserDefinedLens() ∘ (@lens _.b)\n        (@lens _.a) ∘ UserDefinedLens() ∘ (@lens _.b)\n    ]\n        @test sprint(show, lens) == sprint(show, \"text/plain\", lens)\n    end\nend\n\n@testset \"Named Tuples\" begin\n    t = (x=1, y=2)\n    @test (@set t.x =2) === (x=2, y=2)\n    @test (@set t.x += 2) === (x=3, y=2)\n    @test (@set t.x =:hello) === (x=:hello, y=2)\n    l = @lens _.x\n    @test get(t, l) === 1\n\n    # do we want this to throw an error?\n    @test_throws ArgumentError (@set t.z = 3)\nend\n\nstruct CustomProperties\n    _a\n    _b\nend\n\nfunction ConstructionBase.setproperties(o::CustomProperties, patch::NamedTuple)\n    CustomProperties(get(patch, :a, getfield(o, :_a)),\n                     get(patch, :b, getfield(o, :_b)))\n\nend\n\nConstructionBase.constructorof(::Type{CustomProperties}) = error()\n\n@testset \"setproperties overloading\" begin\n    o = CustomProperties(\"A\", \"B\")\n    o2 = @set o.a = :A\n    @test o2 == CustomProperties(:A, \"B\")\n    o3 = @set o.b = :B\n    @test o3 == CustomProperties(\"A\", :B)\nend\n\n@testset \"issue #83\" begin\n    @test_throws ArgumentError Setfield.lensmacro(identity, :(_.[:a]))\nend\n\n@testset \"@lens and ∘\" begin\n    @test @lens(∘()) === @lens(_)\n    @test @lens(∘(_.a)) === @lens(_.a)\n    @test @lens(∘(_.a, _.b)) === @lens(_.a) ∘ @lens(_.b)\n    @test @lens(∘(_.a, _.b, _.c)) === Setfield.compose(@lens(_.a), @lens(_.b), @lens(_.c))\n\n    @test @lens(∘(_[1])) === @lens(_[1])\n    @test @lens(∘(_[1], _[2])) === @lens(_[1]) ∘ @lens(_[2])\n    @test @lens(∘(_[1], _[2], _[3])) === Setfield.compose(@lens(_[1]), @lens(_[2]), @lens(_[3]))\n\n    @test @lens(_ ∘ (_[1] ∘ _.a) ∘ first(_)) == @lens(_) ∘ (@lens(_[1]) ∘ @lens(_.a)) ∘ @lens(first(_))\nend\n\n@testset \"@lens ∘ and \\$\" begin\n    lbc = @lens _.b.c\n    @test @lens($lbc)== lbc\n    @test @lens(_.a ∘ $lbc) == @lens(_.a) ∘ lbc\n    @test @lens(_.a ∘ $lbc ∘ _[1] ∘ $lbc) == @lens(_.a) ∘ lbc ∘ @lens(_[1]) ∘ lbc\n\n    # property interpolation\n    name = :a\n    fancy(name, suffix) = Symbol(\"fancy_\", name, suffix)\n    @test @lens(_.$name) == @lens(_.a)\n    @test @lens(_.x[1, :].$name) == @lens(_.x[1, :].a)\n    @test @lens(_.x[1, :].$(fancy(name, \"✨\"))) == @lens(_.x[1, :].fancy_a✨)\nend\n\nend\n"
  },
  {
    "path": "test/test_examples.jl",
    "content": "module TestExamples\nusing Test\ndir = joinpath(\"..\", \"examples\")\n@testset \"example $filename\" for filename in readdir(dir)\n    path = joinpath(dir, filename)\n    include(path)\nend\nend#module\n"
  },
  {
    "path": "test/test_functionlenses.jl",
    "content": "module TestFunctionLenses\nusing Test\nusing Setfield\n\n@testset \"first\" begin\n    obj = (1, 2.0, '3')\n    l = @lens first(_)\n    @test get(obj, l) === 1\n    @test set(obj, l, \"1\") === (\"1\", 2.0, '3')\n    @test (@set first(obj) = \"1\") === (\"1\", 2.0, '3')\n\n    obj2 = (a=((b=1,), 2), c=3)\n    @test (@set first(obj2.a).b = '1') === (a=((b='1',), 2), c=3)\nend\n\n@testset \"last\" begin\n    obj = (1, 2.0, '3')\n    l = @lens last(_)\n    @test get(obj, l) === '3'\n    @test set(obj, l, '4') === (1, 2.0, '4')\n    @test (@set last(obj) = '4') === (1, 2.0, '4')\n\n    obj2 = (a=(1, (b=2,)), c=3)\n    @test (@set last(obj2.a).b = '2') === (a=(1, (b='2',)), c=3)\nend\n\n@testset \"eltype on Number\" begin\n    @test @set(eltype(Int) = Float32) === Float32\n    @test @set(eltype(1.0) = UInt8)   === UInt8(1)\n\n    @inferred set(Int, @lens(eltype(_)), Float32)\n    @inferred set(1.2, @lens(eltype(_)), Float32)\n\nend\n\n@testset \"eltype(::Type{<:Array})\" begin\n    obj = Vector{Int}\n    @inferred set(obj, @lens(eltype(_)), Float32)\n    obj2 = @set eltype(obj) = Float64\n    @test obj2 === Vector{Float64}\nend\n\n@testset \"eltype(::Array)\" begin\n    obj = [1, 2, 3]\n    @inferred set(obj, @lens(eltype(_)), Float32)\n    obj2 = @set eltype(obj) = Float64\n    @test eltype(obj2) == Float64\n    @test obj == obj2\nend\n\n@testset \"(key|val|el)type(::Type{<:Dict})\" begin\n    obj = Dict{Symbol, Int}\n    @test (@set keytype(obj) = String) === Dict{String, Int}\n    @test (@set valtype(obj) = String) === Dict{Symbol, String}\n    @test (@set eltype(obj) = Pair{String, Any}) === Dict{String, Any}\n\n    obj2 = Dict{Symbol, Dict{Int, Float64}}\n    @test (@set keytype(valtype(obj2)) = String) === Dict{Symbol, Dict{String, Float64}}\n    @test (@set valtype(valtype(obj2)) = String) === Dict{Symbol, Dict{Int, String}}\nend\n\n@testset \"(key|val|el)type(::Dict)\" begin\n    obj = Dict(1 => 2)\n    @test typeof(@set keytype(obj) = Float64) === Dict{Float64, Int}\n    @test typeof(@set valtype(obj) = Float64) === Dict{Int, Float64}\n    @test typeof(@set eltype(obj) = Pair{UInt, Float64}) === Dict{UInt, Float64}\nend\n\nend  # module\n"
  },
  {
    "path": "test/test_quicktypes.jl",
    "content": "module TestQuicktypes\nusing Test\n\nimport Base: ==\nimport MacroTools\n\nusing QuickTypes\nusing Setfield\nimport ConstructionBase\n\n# this is a limitation in `MacroTools.splitarg`. If it is fixed\n# this test can be removed and our custom splitarg removed.\ntry\n    MacroTools.splitarg(:(x=$nothing))\n    println(\"MacroTools.splitarg can now handle literal nothing in AST.\n            Revisit splitarg_no_default workaround\")\ncatch e\n    @assert e isa AssertionError\nend\n\n# Examples are taken from https://github.com/cstjean/QuickTypes.jl\n# Strings are replaced with symbols so that `===` and `==` works\n# nicely.\n\n@qstruct Wall(width, height)\n\n@testset \"Wall\" begin\n    x0 = Wall(400, 600)\n    x1 = @set x0.width = 300\n    @test x1 === Wall(300, 600)\nend\n\nabstract type Vehicle end\n\n@qstruct Car{T<:Number, U}(size::T, nwheels::Int=4; manufacturer::U=nothing,\n                           brand::String=\"off-brand\") <: Vehicle\n\n@testset \"Car\" begin\n    c = Car(10; manufacturer=(\"Danone\", \"Hershey\"))\n    @test c isa Car\n    @test Car <: Vehicle\n    c2 = @set c.size = 10\n    @test c2.size === 10\n    c3 = @set c.manufacturer = 100\n    @test c3 === Car(10;manufacturer =100)\nend\n\n@qstruct Empty()\n@qstruct Cat(name, age::Int, nlegs=4; species=:Siamese)\n\n@testset \"Cat\" begin\n    x0 = Cat(:Tama, 1)\n\n\n    x1 = @set x0.nlegs = 8\n    @test x1 === Cat(:Tama, 1, 8)\n\n    x2 = @set x0.species = :Singapura\n    @test x2 === Cat(:Tama, 1, species=:Singapura)\nend\n\n\n@qstruct Pack{T, N}(animals::NTuple{N, T})\n\n@testset \"Pack\" begin\n    x = Pack((Cat(:Tama, 1), Cat(:Pochi, 2)))\n\n    x = @set x.animals[2].nlegs = 5\n    @test x.animals == (Cat(:Tama, 1), Cat(:Pochi, 2, 5))\nend\n\n\nabstract type Tree end\n@qstruct Maple(qty_syrup::Float64) <: Tree\n\n@testset \"Maple\" begin\n    x0 = Maple(1)\n    x1 = @set x0.qty_syrup = 2\n    @test x1 === Maple(2)\nend\n\n\n@qmutable Window(height::Float64, width::Float64)\n==(x::Window, y::Window) = x.height == y.height && x.width == y.width\n\n@testset \"Window\" begin\n    x0 = Window(1, 2)\n\n    x1 = @set x0.width = 3.0\n    @test isequal(x1, Window(1, 3))\n    @test x1 == Window(1, 3)\n    x2 = @set x0.width = 3\n    @test x1 == x2\n    @test !(x1 === x2)\nend\n\n\n@qstruct Human(; name=:Alice, height::Float64=170) do\n    @assert height > 0    # arbitrary code, executed in the constructor\nend\n\n@testset \"Human\" begin\n    x0 = Human()\n\n    x1 = @set x0.name = :Bob\n    @test x1 === Human(name=:Bob)\n\n    @test_throws AssertionError @set x0.height = -10\nend\n\n\n@qstruct Group{x}(members::x; _concise_show=true)\n\n@testset \"Group\" begin\n    x = Group((0, 1))\n    x = @set x.members[2] = 111\n    @test x.members == (0, 111)\nend\n\n@qstruct_fp Plane1(nwheels, weight::Number; brand=:zoomba)\n\n@testset \"Plane1\" begin\n    x0 = Plane1(3, 100)\n    x1 = @set x0.nwheels = 5\n    @test x1 == Plane1(5, 100)\n    @test (@set x0.brand = 31).brand === 31\nend\n\n# Another way to \"support\" QuickTypes with type parameters is to use\n# QuickTypes.construct.\n@qstruct_fp Plane2(nwheels, weight::Number; brand=:zoomba)\nConstructionBase.constructorof(::Type{<: Plane2}) =\n    (args...) -> QuickTypes.construct(Plane2, args...)\n\n@testset \"Plane2\" begin\n    x0 = Plane2(3, 100)\n\n    x1 = @set x0.brand = 31\n    @test typeof(x1) != typeof(x0)\n    @test x1 == Plane2(3, 100, brand=31)\nend\n\nend  # module\n"
  },
  {
    "path": "test/test_setindex.jl",
    "content": "module TestSetindex\nusing Setfield\nusing Test\n\n\"\"\"\n    ==ₜ(x, y)\n\nCheck that _type_ and value of `x` and `y` are equal.\n\"\"\"\n==ₜ(_, _) = false\n==ₜ(x::T, y::T) where T = x == y\n\n@testset \"==ₜ\" begin\n    @test 1 ==ₜ 1\n    @test !(1.0 ==ₜ 1)\nend\n\n@testset \"setindex\" begin\n    arr = [1,2,3]\n    @test_throws MethodError Base.setindex(arr, 10, 1)\n    @test Setfield.setindex(arr, 10, 1) == [10, 2, 3]\n    @test arr == [1,2,3]\n    @test @set(arr[1] = 10) == [10, 2, 3]\n    @test arr == [1,2,3]\n    @test Setfield.setindex(arr, 10.0, 1) ==ₜ Float64[10.0, 2.0, 3.0]\n    @test Setfield.setindex(ones(2, 2), zeros(2), 1, :) ==ₜ Float64[0.0 0.0; 1.0 1.0]\n    @test Setfield.setindex(ones(BigInt, 2, 2), zeros(Float32, 2), 1, :) ==ₜ BigFloat[0.0 0.0; 1.0 1.0]\n    @test Setfield.setindex(fill(ones(1), 2, 2), [im, im], :, 1) ==ₜ hcat([im, im], [[1.0], [1.0]])\n\n    d = Dict(:a => 1, :b => 2)\n    @test_throws MethodError Base.setindex(d, 10, :a)\n    @test Setfield.setindex(d, 10, :a) == Dict(:a=>10, :b=>2)\n    @test d == Dict(:a => 1, :b => 2)\n    @test @set(d[:a] = 10) == Dict(:a=>10, :b=>2)\n    @test d == Dict(:a => 1, :b => 2)\n    @test Setfield.setindex(d, 30, \"c\") ==ₜ Dict(:a=>1, :b=>2, \"c\"=>30)\n    @test Setfield.setindex(d, 10.0, :a) ==ₜ Dict(:a=>10.0, :b=>2.0)\nend\n\nend\n"
  },
  {
    "path": "test/test_setmacro.jl",
    "content": "module TestSetMacro\n\nmodule Clone\nusing Setfield: setmacro, lensmacro\n\nmacro lens(ex)\n    lensmacro(identity, ex)\nend\n\nmacro set(ex)\n    setmacro(identity, ex)\nend\n\nend#module Clone\n\nusing Setfield: Setfield\nusing Test\nusing .Clone: Clone\n\nusing StaticArrays: @SMatrix\nusing StaticNumbers\n\n@testset \"setmacro, lensmacro isolation\" begin\n\n    # test that no symbols like `IndexLens` are needed:\n    @test Clone.@lens(_                                   ) isa Setfield.Lens\n    @test Clone.@lens(_.a                                 ) isa Setfield.Lens\n    @test Clone.@lens(_[1]                                ) isa Setfield.Lens\n    @test Clone.@lens(first(_)                            ) isa Setfield.Lens\n    @test Clone.@lens(_[end]                              ) isa Setfield.Lens\n    @test Clone.@lens(_[static(1)]                           ) isa Setfield.Lens\n    @test Clone.@lens(_.a[1][end, end-2].b[static(1), static(1)]) isa Setfield.Lens\n\n    @test Setfield.@lens(_.a) === Clone.@lens(_.a)\n    @test Setfield.@lens(_.a.b) === Clone.@lens(_.a.b)\n    @test Setfield.@lens(_.a.b[1,2]) === Clone.@lens(_.a.b[1,2])\n\n    o = (a=1, b=2)\n    @test Clone.@set(o.a = 2) === Setfield.@set(o.a = 2)\n    @test Clone.@set(o.a += 2) === Setfield.@set(o.a += 2)\n\n    m = @SMatrix [0 0; 0 0]\n    m2 = Clone.@set m[end-1, end] = 1\n    @test m2 === @SMatrix [0 1; 0 0]\n    m3 = Clone.@set(first(m) = 1)\n    @test m3 === @SMatrix[1 0; 0 0]\nend\n\nfunction test_all_inferrable(f, argtypes)\n    typed = first(code_typed(f, argtypes))\n    code = typed.first\n    @test all(T -> !(T isa UnionAll || T === Any), code.slottypes)\nend\n\n# Example of macro that caused inference issues before.\nmacro test_macro(expr)\n    quote\n        function f($(esc(:x)))\n            $(Setfield.setmacro(identity, expr, overwrite=true))\n            $(Setfield.setmacro(identity, expr, overwrite=true))\n            $(Setfield.setmacro(identity, expr, overwrite=true))\n            $(Setfield.setmacro(identity, expr, overwrite=true))\n            $(Setfield.setmacro(identity, expr, overwrite=true))\n            return $(esc(:x))\n        end\n    end\nend\n\nif VERSION >= v\"1.3\"\n    @testset \"setmacro multiple usage\" begin\n        let f = @test_macro(x[end] = 1)\n            test_all_inferrable(f, (Vector{Float64}, ))\n        end\n    end\nend\n\nend#module\n\n"
  },
  {
    "path": "test/test_staticarrays.jl",
    "content": "module TestStaticArrays\nusing Test\nusing Setfield\nusing StaticArrays\nusing StaticNumbers\n\n@testset \"StaticArrays\" begin\n    obj = StaticArrays.@SMatrix [1 2; 3 4]\n    @testset for l in [\n            (@lens _[2,1]),\n        ]\n        @test get(obj, l) == 3\n        @test set(obj, l, 5) == StaticArrays.@SMatrix [1 2; 5 4]\n        @test setindex(obj, 5, 2, 1) == StaticArrays.@SMatrix [1 2; 5 4]\n    end\n\n    v = @SVector [1,2,3]\n    @test (@set v[1] = 10) === @SVector [10,2,3]\n    @test_broken (@set v[1] = π) === @SVector [π,2,3]\n\n    @testset \"Multi-dynamic indexing\" begin\n        two = 2\n        plusone(x) = x + 1\n        l1 = @lens _.a[2, 1].b\n        l2 = @lens _.a[plusone(end) - two, end÷2].b\n        m_orig = @SMatrix [\n            (a=1, b=10) (a=2, b=20)\n            (a=3, b=30) (a=4, b=40)\n            (a=5, b=50) (a=6, b=60)\n        ]\n        m_mod = @SMatrix [\n            (a=1, b=10) (a=2, b=20)\n            (a=3, b=3000) (a=4, b=40)\n            (a=5, b=50) (a=6, b=60)\n        ]\n        obj = (a=m_orig, b=4)\n        @test get(obj, l1) === get(obj, l2) === 30\n        @test set(obj, l1, 3000) === set(obj, l2, 3000) === (a=m_mod, b=4)\n    end\nend\nend\n"
  }
]