Browse Source

Add package content.

pull/8/head
Fredrik Ekre 4 years ago
parent
commit
a5a2636c2f
  1. 9
      Project.toml
  2. 2
      README.md
  3. 58
      src/EnumX.jl
  4. 64
      test/runtests.jl

9
Project.toml

@ -1,3 +1,12 @@ @@ -1,3 +1,12 @@
name = "EnumX"
uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
version = "1.0.0"
[compat]
julia = "1.6"
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[targets]
test = ["Test"]

2
README.md

@ -1 +1,3 @@ @@ -1 +1,3 @@
# EnumX
`Base.@enum`s protected by a module scope.

58
src/EnumX.jl

@ -2,4 +2,62 @@ @@ -2,4 +2,62 @@
module EnumX
export @enumx
abstract type Enum{T} <: Base.Enum{T} end
macro enumx(args...)
return enumx(args...)
end
function enumx(name, args...)
namemap = Dict{Int32,Symbol}()
next = 0
for arg in args
@assert arg isa Symbol # TODO
namemap[next] = arg
next += 1
end
module_block = quote
primitive type Type <: Enum{Int32} 32 end
let namemap = $(namemap)
check_valid(x) = x in keys(namemap) ||
throw(ArgumentError("invalid value $(x) for Enum $($(QuoteNode(name)))"))
global function $(esc(:Type))(x::Integer)
check_valid(x)
return Base.bitcast($(esc(:Type)), convert(Int32, x))
end
Base.Enums.namemap(::Base.Type{$(esc(:Type))}) = namemap
Base.Enums.instances(::Base.Type{$(esc(:Type))}) =
($([esc(k) for k in values(namemap)]...),)
end
end
for (k, v) in namemap
push!(module_block.args,
Expr(:const, Expr(:(=), esc(v), Expr(:call, esc(:Type), k)))
)
end
return Expr(:toplevel, Expr(:module, false, esc(name), module_block), nothing)
end
function Base.show(io::IO, ::MIME"text/plain", x::E) where E <: Enum
print(io, "$(nameof(parentmodule(E))).$(Symbol(x)::Symbol) = $(Integer(x))")
return nothing
end
function Base.show(io::IO, ::MIME"text/plain", ::Base.Type{E}) where E <: Enum
iob = IOBuffer()
insts = Base.Enums.instances(E)
n = length(insts)
stringmap = Dict{String, Int32}(
string("$(nameof(parentmodule(E))).", v) => k for (k, v) in Base.Enums.namemap(E)
)
mx = maximum(textwidth, keys(stringmap); init = 0)
print(iob, "Enum type $(nameof(parentmodule(E))).Type <: Enum{$(Base.Enums.basetype(E))} with $(n) instance$(n == 1 ? "" : "s"):")
for (k, v) in stringmap
print(iob, "\n", rpad(k, mx), " = $(v)")
end
write(io, seekstart(iob))
return nothing
end
end # module EnumX

64
test/runtests.jl

@ -4,4 +4,68 @@ using EnumX, Test @@ -4,4 +4,68 @@ using EnumX, Test
@testset "EnumX" begin
# Basic
@enumx Fruit Apple Banana
@test Fruit isa Module
@test Set(names(Fruit)) == Set([:Fruit])
@test_broken Set(names(Fruit; all=true)) == Set([:Fruit, :Apple, :Banana, :Type])
@test issubset(Set([:Fruit, :Apple, :Banana, :Type]), Set(names(Fruit; all=true)))
@test Fruit.Type <: EnumX.Enum{Int32} <: Base.Enum{Int32}
@test !@isdefined(Apple)
@test !@isdefined(Banana)
@test Fruit.Apple isa EnumX.Enum
@test Fruit.Apple isa Base.Enum
@test Fruit.Banana isa EnumX.Enum
@test Fruit.Banana isa Base.Enum
@test instances(Fruit.Type) === (Fruit.Apple, Fruit.Banana)
@test Base.Enums.namemap(Fruit.Type) == Dict{Int32,Symbol}(0 => :Apple, 1 => :Banana)
@test Base.Enums.basetype(Fruit.Type) == Int32
@test Symbol(Fruit.Apple) === :Apple
@test Symbol(Fruit.Banana) === :Banana
@test Integer(Fruit.Apple) === Int32(0)
@test Int(Fruit.Apple) === Int(0)
@test Integer(Fruit.Banana) === Int32(1)
@test Int(Fruit.Banana) === Int(1)
@test Fruit.Apple === Fruit.Apple
@test Fruit.Banana === Fruit.Banana
@test Fruit.Type(Int32(0)) === Fruit.Type(0) === Fruit.Apple
@test Fruit.Type(Int32(1)) === Fruit.Type(1) === Fruit.Banana
@test_throws ArgumentError("invalid value 123 for Enum Fruit") Fruit.Type(Int32(123))
@test_throws ArgumentError("invalid value 123 for Enum Fruit") Fruit.Type(123)
@test Fruit.Apple < Fruit.Banana
let io = IOBuffer()
write(io, Fruit.Apple)
seekstart(io)
@test read(io, Fruit.Type) === Fruit.Apple
seekstart(io)
write(io, Fruit.Banana)
seekstart(io)
@test read(io, Fruit.Type) === Fruit.Banana
seekstart(io)
write(io, Int32(123))
seekstart(io)
@test_throws ArgumentError("invalid value 123 for Enum Fruit") read(io, Fruit.Type)
end
let io = IOBuffer()
show(io, "text/plain", Fruit.Type)
str = String(take!(io))
@test str == "Enum type Fruit.Type <: Enum{Int32} with 2 instances:\nFruit.Apple = 0\nFruit.Banana = 1"
show(io, "text/plain", Fruit.Apple)
str = String(take!(io))
@test str == "Fruit.Apple = 0"
show(io, "text/plain", Fruit.Banana)
str = String(take!(io))
@test str == "Fruit.Banana = 1"
end
end # testset

Loading…
Cancel
Save