summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md6
-rw-r--r--doc/lib.rst3
-rw-r--r--lib/pure/typetraits.nim11
-rw-r--r--lib/std/enumutils.nim19
-rw-r--r--lib/system/iterators.nim9
-rw-r--r--tests/stdlib/tenumutils.nim16
6 files changed, 58 insertions, 6 deletions
diff --git a/changelog.md b/changelog.md
index 8caee8aff..17844e09a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -41,8 +41,10 @@
 - Added `randState` template that exposes the default random number generator.
   Useful for library authors.
 
-- Added std/enumutils module containing `genEnumCaseStmt` macro that generates
-  case statement to parse string to enum.
+- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum.
+  Added `items` for enums with holes.
+
+- Added `typetraits.SomeEnumWithHoles` for enums with holes.
 
 - Removed deprecated `iup` module from stdlib, it has already moved to
   [nimble](https://github.com/nim-lang/iup).
diff --git a/doc/lib.rst b/doc/lib.rst
index 11b479902..47ede70ee 100644
--- a/doc/lib.rst
+++ b/doc/lib.rst
@@ -85,6 +85,9 @@ Algorithms
 * `algorithm <algorithm.html>`_
   This module implements some common generic algorithms like sort or binary search.
 
+* `std/enumutils <enumutils.html>`_
+  This module adds functionality for the built-in ``enum`` type.
+
 * `sequtils <sequtils.html>`_
   This module implements operations for the built-in ``seq`` type
   which were inspired by functional programming languages.
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index 7af78bf31..69c0329ef 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -15,6 +15,17 @@
 import std/private/since
 export system.`$` # for backward compatibility
 
+type SomeEnumWithHoles* = (not Ordinal) and enum ## Enum with 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
+  type C[T] = enum h0 = 2, h1 = 4
+  assert C[float] is SomeEnumWithHoles
+
 proc name*(t: typedesc): string {.magic: "TypeTrait".} =
   ## Returns the name of the given type.
   ##
diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim
index 704e42de5..56a6d82a7 100644
--- a/lib/std/enumutils.nim
+++ b/lib/std/enumutils.nim
@@ -7,7 +7,9 @@
 #    distribution, for details about the copyright.
 #
 
-import macros
+import std/macros
+
+# xxx `genEnumCaseStmt` needs tests and runnableExamples
 
 macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, 
             userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped =
@@ -61,4 +63,17 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
     result.add nnkElse.newTree(raiseStmt)
   else:
     expectKind(default, nnkSym)
-    result.add nnkElse.newTree(default)
\ No newline at end of file
+    result.add nnkElse.newTree(default)
+
+macro enumWithHolesFullRange(a: typed): untyped = 
+  newNimNode(nnkCurly).add(a.getType[1][1..^1])
+
+iterator items*[T: enum and not Ordinal](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
diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim
index 504695bf6..7f0076a44 100644
--- a/lib/system/iterators.nim
+++ b/lib/system/iterators.nim
@@ -82,8 +82,13 @@ iterator mitems*(a: var cstring): var char {.inline.} =
       yield a[i]
       inc(i)
 
-iterator items*[T: enum](E: typedesc[T]): T =
-  ## Iterates over the values of the enum ``E``.
+iterator items*[T: enum and Ordinal](E: typedesc[T]): T =
+  ## Iterates over the values of `E`.
+  ## See also `enumutils.items` for enums with holes.
+  runnableExamples:
+    type Goo = enum g0 = 2, g1, g2
+    from std/sequtils import toSeq
+    assert Goo.toSeq == [g0, g1, g2]
   for v in low(E) .. high(E):
     yield v
 
diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim
new file mode 100644
index 000000000..dd5da1974
--- /dev/null
+++ b/tests/stdlib/tenumutils.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "c js"
+"""
+
+import std/enumutils
+from std/sequtils import toSeq
+
+template main =
+  block: # items
+    type A = enum a0 = 2, a1 = 4, a2
+    type B[T] = enum b0 = 2, b1 = 4
+    doAssert A.toSeq == [a0, a1, a2]
+    doAssert B[float].toSeq == [B[float].b0, B[float].b1]
+
+static: main()
+main()