Skip to content

Commit

Permalink
only (#662)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcabbott authored and martinholters committed Sep 30, 2019
1 parent 33b906f commit ee4f41f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ Currently, the `@compat` macro supports the following syntaxes:

## New functions, macros, and methods

* `only(x)` returns the one-and-only element of a collection `x`. ([#33129])

* `mod` now accepts a unit range as the second argument ([#32628]).

* `eachrow`, `eachcol`, and `eachslice` to iterate over first, second, or given dimension
Expand Down Expand Up @@ -576,3 +578,5 @@ includes this fix. Find the minimum version from there.
[#29259]: https://github.com/JuliaLang/julia/issues/29259
[#29674]: https://github.com/JuliaLang/julia/issues/29674
[#29749]: https://github.com/JuliaLang/julia/issues/29749
[#33129]: https://github.com/JuliaLang/julia/issues/33129
[#32628]: https://github.com/JuliaLang/julia/issues/32628
31 changes: 31 additions & 0 deletions src/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1866,6 +1866,37 @@ if v"0.7.0" <= VERSION < v"1.1.0-DEV.594"
Base.merge(a::NamedTuple) = a
end

# https://github.com/JuliaLang/julia/pull/33129
if v"0.7.0" <= VERSION < v"1.4.0-DEV.142"
export only

Base.@propagate_inbounds function only(x)
i = iterate(x)
@boundscheck if i === nothing
throw(ArgumentError("Collection is empty, must contain exactly 1 element"))
end
(ret, state) = i
@boundscheck if iterate(x, state) !== nothing
throw(ArgumentError("Collection has multiple elements, must contain exactly 1 element"))
end
return ret
end

# Collections of known size
only(x::Ref) = x[]
only(x::Number) = x
only(x::Char) = x
only(x::Tuple{Any}) = x[1]
only(x::Tuple) = throw(
ArgumentError("Tuple contains $(length(x)) elements, must contain exactly 1 element")
)
only(a::AbstractArray{<:Any, 0}) = @inbounds return a[]
only(x::NamedTuple{<:Any, <:Tuple{Any}}) = first(x)
only(x::NamedTuple) = throw(
ArgumentError("NamedTuple contains $(length(x)) elements, must contain exactly 1 element")
)
end

# https://github.com/JuliaLang/julia/pull/32628
if v"0.7.0" <= VERSION < v"1.3.0-alpha.8"
Base.mod(i::Integer, r::Base.OneTo) = mod1(i, last(r))
Expand Down
37 changes: 37 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,43 @@ end
@test merge((a=1,), (b=2,), (c=3,)) == (a=1,b=2,c=3)
end

@static if VERSION >= v"0.7.0"
@testset "only" begin
@test only([3]) === 3
@test_throws ArgumentError only([])
@test_throws ArgumentError only([3, 2])

@test @inferred(only((3,))) === 3
@test_throws ArgumentError only(())
@test_throws ArgumentError only((3, 2))

@test only(Dict(1=>3)) === (1=>3)
@test_throws ArgumentError only(Dict{Int,Int}())
@test_throws ArgumentError only(Dict(1=>3, 2=>2))

@test only(Set([3])) === 3
@test_throws ArgumentError only(Set(Int[]))
@test_throws ArgumentError only(Set([3,2]))

@test @inferred(only((;a=1))) === 1
@test_throws ArgumentError only(NamedTuple())
@test_throws ArgumentError only((a=3, b=2.0))

@test @inferred(only(1)) === 1
@test @inferred(only('a')) === 'a'
if VERSION >= v"1.0"
@test @inferred(only(Ref([1, 2]))) == [1, 2] # Fails on v0.7, depwarn "`Ref(x::AbstractArray)` is deprecated, use `Ref(x, 1)` instead."
end
@test_throws ArgumentError only(Pair(10, 20))

@test only(1 for ii in 1:1) === 1
@test only(1 for ii in 1:10 if ii < 2) === 1
@test_throws ArgumentError only(1 for ii in 1:10)
@test_throws ArgumentError only(1 for ii in 1:10 if ii > 2)
@test_throws ArgumentError only(1 for ii in 1:10 if ii > 200)
end
end

# https://github.com/JuliaLang/julia/pull/32628
if VERSION >= v"0.7"
@testset "mod with ranges" begin
Expand Down

0 comments on commit ee4f41f

Please sign in to comment.