Skip to content

Commit

Permalink
add typetraits.OrdinalEnum, enumutils.symbolName (nim-lang#17281)
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour authored and ardek66 committed Mar 26, 2021
1 parent 1da05d1 commit 6e1766b
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 9 deletions.
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@

- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum.
Added `items` for enums with holes.
Added `symbolName` to return the enum symbol name ignoring the human readable name.

- Added `typetraits.SomeEnumWithHoles` for enums with holes.
- Added `typetraits.HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes.

- Removed deprecated `iup` module from stdlib, it has already moved to
[nimble](https://github.com/nim-lang/iup).
Expand Down
14 changes: 9 additions & 5 deletions lib/pure/typetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@
import std/private/since
export system.`$` # for backward compatibility

type SomeEnumWithHoles* = (not Ordinal) and enum ## Enum with holes.
type HoleyEnum* = (not Ordinal) and enum ## Enum with holes.
type OrdinalEnum* = Ordinal and enum ## Enum without holes.

runnableExamples:
type A = enum a0 = 2, a1 = 4, a2
type B = enum b0 = 2, b1, b2
assert A is SomeEnumWithHoles
assert B isnot SomeEnumWithHoles
assert int isnot SomeEnumWithHoles
assert A is enum
assert A is HoleyEnum
assert A isnot OrdinalEnum
assert B isnot HoleyEnum
assert B is OrdinalEnum
assert int isnot HoleyEnum
type C[T] = enum h0 = 2, h1 = 4
assert C[float] is SomeEnumWithHoles
assert C[float] is HoleyEnum

proc name*(t: typedesc): string {.magic: "TypeTrait".} =
## Returns the name of the given type.
Expand Down
28 changes: 25 additions & 3 deletions lib/std/enumutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#

import std/macros
from std/typetraits import OrdinalEnum, HoleyEnum

# xxx `genEnumCaseStmt` needs tests and runnableExamples

Expand Down Expand Up @@ -65,15 +66,36 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
expectKind(default, nnkSym)
result.add nnkElse.newTree(default)

macro enumWithHolesFullRange(a: typed): untyped =
macro enumFullRange(a: typed): untyped =
newNimNode(nnkCurly).add(a.getType[1][1..^1])

iterator items*[T: enum and not Ordinal](E: typedesc[T]): T =
macro enumNames(a: typed): untyped =
# this could be exported too; in particular this could be useful for enum with holes.
result = newNimNode(nnkBracket)
for ai in a.getType[1][1..^1]:
assert ai.kind == nnkSym
result.add newLit ai.strVal

iterator items*[T: HoleyEnum](E: typedesc[T]): T =
## Iterates over an enum with holes.
runnableExamples:
type A = enum a0 = 2, a1 = 4, a2
type B[T] = enum b0 = 2, b1 = 4
from std/sequtils import toSeq
assert A.toSeq == [a0, a1, a2]
assert B[float].toSeq == [B[float].b0, B[float].b1]
for a in enumWithHolesFullRange(E): yield a
for a in enumFullRange(E): yield a

func symbolName*[T: OrdinalEnum](a: T): string =
## Returns the symbol name of an enum.
runnableExamples:
type B = enum
b0 = (10, "kb0")
b1 = "kb1"
b2
let b = B.low
assert b.symbolName == "b0"
assert $b == "kb0"
static: assert B.high.symbolName == "b2"
const names = enumNames(T)
names[a.ord - T.low.ord]
21 changes: 21 additions & 0 deletions tests/stdlib/tenumutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,26 @@ template main =
doAssert A.toSeq == [a0, a1, a2]
doAssert B[float].toSeq == [B[float].b0, B[float].b1]

block: # symbolName
block:
type A2 = enum a20, a21, a22
doAssert $a21 == "a21"
doAssert a21.symbolName == "a21"
proc `$`(a: A2): string = "foo"
doAssert $a21 == "foo"
doAssert a21.symbolName == "a21"
var a = a22
doAssert $a == "foo"
doAssert a.symbolName == "a22"

type B = enum
b0 = (10, "kb0")
b1 = "kb1"
b2
let b = B.low
doAssert b.symbolName == "b0"
doAssert $b == "kb0"
static: doAssert B.high.symbolName == "b2"

static: main()
main()

0 comments on commit 6e1766b

Please sign in to comment.