Skip to content

Commit

Permalink
https://github.com/JuliaLang/julia/pull/33129
Browse files Browse the repository at this point in the history
  • Loading branch information
mcabbott committed Sep 29, 2019
1 parent 29e95d7 commit bbb92d0
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
2 changes: 2 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])

* `eachrow`, `eachcol`, and `eachslice` to iterate over first, second, or given dimension
of an array ([#29749]).

Expand Down
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

include("deprecated.jl")

end # module Compat
37 changes: 36 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ if VERSION >= v"0.7"
@test collect(eachrow(M)) == collect(eachslice(M, dims = 1)) == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
@test collect(eachcol(M)) == collect(eachslice(M, dims = 2)) == [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
@test_throws DimensionMismatch eachslice(M, dims = 4)

# Higher-dimensional case
M = reshape([(1:16)...], 2, 2, 2, 2)
@test_throws MethodError collect(eachrow(M))
Expand Down Expand Up @@ -1499,4 +1499,39 @@ 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'
@test @inferred(only(Ref([1, 2]))) == [1, 2]
@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

nothing

0 comments on commit bbb92d0

Please sign in to comment.