Skip to content

Commit ee4f41f

Browse files
mcabbottmartinholters
authored andcommitted
1 parent 33b906f commit ee4f41f

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ Currently, the `@compat` macro supports the following syntaxes:
114114

115115
## New functions, macros, and methods
116116

117+
* `only(x)` returns the one-and-only element of a collection `x`. ([#33129])
118+
117119
* `mod` now accepts a unit range as the second argument ([#32628]).
118120

119121
* `eachrow`, `eachcol`, and `eachslice` to iterate over first, second, or given dimension
@@ -576,3 +578,5 @@ includes this fix. Find the minimum version from there.
576578
[#29259]: https://github.com/JuliaLang/julia/issues/29259
577579
[#29674]: https://github.com/JuliaLang/julia/issues/29674
578580
[#29749]: https://github.com/JuliaLang/julia/issues/29749
581+
[#33129]: https://github.com/JuliaLang/julia/issues/33129
582+
[#32628]: https://github.com/JuliaLang/julia/issues/32628

src/Compat.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,37 @@ if v"0.7.0" <= VERSION < v"1.1.0-DEV.594"
18661866
Base.merge(a::NamedTuple) = a
18671867
end
18681868

1869+
# https://github.com/JuliaLang/julia/pull/33129
1870+
if v"0.7.0" <= VERSION < v"1.4.0-DEV.142"
1871+
export only
1872+
1873+
Base.@propagate_inbounds function only(x)
1874+
i = iterate(x)
1875+
@boundscheck if i === nothing
1876+
throw(ArgumentError("Collection is empty, must contain exactly 1 element"))
1877+
end
1878+
(ret, state) = i
1879+
@boundscheck if iterate(x, state) !== nothing
1880+
throw(ArgumentError("Collection has multiple elements, must contain exactly 1 element"))
1881+
end
1882+
return ret
1883+
end
1884+
1885+
# Collections of known size
1886+
only(x::Ref) = x[]
1887+
only(x::Number) = x
1888+
only(x::Char) = x
1889+
only(x::Tuple{Any}) = x[1]
1890+
only(x::Tuple) = throw(
1891+
ArgumentError("Tuple contains $(length(x)) elements, must contain exactly 1 element")
1892+
)
1893+
only(a::AbstractArray{<:Any, 0}) = @inbounds return a[]
1894+
only(x::NamedTuple{<:Any, <:Tuple{Any}}) = first(x)
1895+
only(x::NamedTuple) = throw(
1896+
ArgumentError("NamedTuple contains $(length(x)) elements, must contain exactly 1 element")
1897+
)
1898+
end
1899+
18691900
# https://github.com/JuliaLang/julia/pull/32628
18701901
if v"0.7.0" <= VERSION < v"1.3.0-alpha.8"
18711902
Base.mod(i::Integer, r::Base.OneTo) = mod1(i, last(r))

test/runtests.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,43 @@ end
14991499
@test merge((a=1,), (b=2,), (c=3,)) == (a=1,b=2,c=3)
15001500
end
15011501

1502+
@static if VERSION >= v"0.7.0"
1503+
@testset "only" begin
1504+
@test only([3]) === 3
1505+
@test_throws ArgumentError only([])
1506+
@test_throws ArgumentError only([3, 2])
1507+
1508+
@test @inferred(only((3,))) === 3
1509+
@test_throws ArgumentError only(())
1510+
@test_throws ArgumentError only((3, 2))
1511+
1512+
@test only(Dict(1=>3)) === (1=>3)
1513+
@test_throws ArgumentError only(Dict{Int,Int}())
1514+
@test_throws ArgumentError only(Dict(1=>3, 2=>2))
1515+
1516+
@test only(Set([3])) === 3
1517+
@test_throws ArgumentError only(Set(Int[]))
1518+
@test_throws ArgumentError only(Set([3,2]))
1519+
1520+
@test @inferred(only((;a=1))) === 1
1521+
@test_throws ArgumentError only(NamedTuple())
1522+
@test_throws ArgumentError only((a=3, b=2.0))
1523+
1524+
@test @inferred(only(1)) === 1
1525+
@test @inferred(only('a')) === 'a'
1526+
if VERSION >= v"1.0"
1527+
@test @inferred(only(Ref([1, 2]))) == [1, 2] # Fails on v0.7, depwarn "`Ref(x::AbstractArray)` is deprecated, use `Ref(x, 1)` instead."
1528+
end
1529+
@test_throws ArgumentError only(Pair(10, 20))
1530+
1531+
@test only(1 for ii in 1:1) === 1
1532+
@test only(1 for ii in 1:10 if ii < 2) === 1
1533+
@test_throws ArgumentError only(1 for ii in 1:10)
1534+
@test_throws ArgumentError only(1 for ii in 1:10 if ii > 2)
1535+
@test_throws ArgumentError only(1 for ii in 1:10 if ii > 200)
1536+
end
1537+
end
1538+
15021539
# https://github.com/JuliaLang/julia/pull/32628
15031540
if VERSION >= v"0.7"
15041541
@testset "mod with ranges" begin

0 commit comments

Comments
 (0)