---
hide:
  - toc
search:
  exclude: true
---
```````pony linenums="1"
use "collections"
use persistent = "collections/persistent"
use "itertools"

trait box GenObj[T]
  """
  Pure function of a `Randomness` source that produces a random value. The
  framework records every random decision during generation, then replays
  generators against mutated decision sequences to produce shrunk values.
  """
  fun generate(rnd: Randomness): T^ ?
    """
    Produce a random value from the given source of randomness.
    """

class box Generator[T] is GenObj[T]
  """
  Wraps a `GenObj` with composition methods (`map`, `filter`, `flat_map`,
  `union`). Shrinking is automatic through choice-sequence replay.
  """
  let _gen: GenObj[T]

  new create(gen: GenObj[T]) =>
    _gen = gen

  fun generate(rnd: Randomness): T^ ? =>
    """
    Produce a random value from the given source of randomness.
    """
    _gen.generate(rnd)?

  fun filter(predicate: {(T): (T^, Bool)} box): Generator[T] =>
    """
    Only yield values for which `predicate` returns `true`.

    Rejected values are retried up to 100 times. Each attempt is
    recorded in its own discardable span so the shrinker can remove
    the failed draws cleanly. Errors after exhausting retries.
    """
    Generator[T](
      object is GenObj[T]
        fun generate(rnd: Randomness): T^ ? =>
          var tries: USize = 0
          while tries < 100 do
            rnd.start_span(SpanFilter)
            let t: T = _gen.generate(rnd)?
            (let t1, let matches) = predicate(consume t)
            if matches then
              rnd.end_span()?
              return consume t1
            end
            rnd.end_span(true)?
            tries = tries + 1
          end
          error
      end)

  fun map[U](fn: {(T): U^} box): Generator[U] =>
    """
    Apply `fn` to each generated value.
    """
    Generator[U](
      object is GenObj[U]
        fun generate(rnd: Randomness): U^ ? =>
          fn(_gen.generate(rnd)?)
      end)

  fun flat_map[U](fn: {(T): Generator[U]} box): Generator[U] =>
    """
    For each value of this generator, create a generator that is then combined.
    Both outer and inner choices are in the same sequence, so shrinking the
    outer value works automatically.
    """
    Generator[U](
      object is GenObj[U]
        fun generate(rnd: Randomness): U^ ? =>
          let outer: T = _gen.generate(rnd)?
          fn(consume outer).generate(rnd)?
      end)

  fun union[U](other: Generator[U]): Generator[(T | U)] =>
    """
    Produce the value of this generator or the other with equal probability.
    """
    Generator[(T | U)](
      object is GenObj[(T | U)]
        fun generate(rnd: Randomness): (T^ | U^) ? =>
          if rnd.bool()? then
            _gen.generate(rnd)?
          else
            other.generate(rnd)?
          end
      end)

type WeightedGenerator[T] is (USize, Generator[T] box)
  """
  A generator with an associated weight, used in `Generators.frequency`.
  """

primitive Generators
  """
  Convenience combinators and factories for common types of Generators.
  """

  fun unit[T](t: T): Generator[box->T] =>
    """
    Generate a reference to the same value over and over again.
    """
    Generator[box->T](
      object is GenObj[box->T]
        let _t: T = consume t
        fun generate(rnd: Randomness): box->T => _t
      end)

  fun none[T: None](): Generator[(T | None)] =>
    """
    Always generate `None`.
    """
    Generators.unit[(T | None)](None)

  fun repeatedly[T](f: {(): T^ ?} box): Generator[T] =>
    """
    Generate values by calling the lambda `f` repeatedly.

    Values generated this way produce zero recorded choices and cannot
    be shrunk. Use a generator that draws from `Randomness` when shrinking
    matters.
    """
    Generator[T](
      object is GenObj[T]
        fun generate(rnd: Randomness): T^ ? => f()?
      end)

  fun array_of[T](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[Array[T]]
  =>
    """
    Generate an `Array[T]` with size in the range `from` to `to`.
    Uses boolean-per-element encoding for shrinking: each element is preceded
    by a boolean deciding whether to include it. Shrinking deletes elements
    while preserving all others exactly.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[Array[T]](
      object is GenObj[Array[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): Array[T]^ ? =>
          let result = Array[T](hi)
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let elem = _gen.generate(rnd)?
              result.push(consume elem)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun iso_seq_of[T: Any #send, S: Seq[T] iso](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[S]
  =>
    """
    Generate a `Seq[T]` where `T` must be sendable.
    Uses boolean-per-element encoding.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[S](
      object is GenObj[S]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): S^ ? =>
          let result: S = recover iso S.create(hi) end
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let elem = _gen.generate(rnd)?
              result.push(consume elem)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          consume result
      end)

  fun seq_of[T, S: Seq[T] ref](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[S]
  =>
    """
    Create a `Seq` from generated values with size in `from` to `to`.
    Uses boolean-per-element encoding.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[S](
      object is GenObj[S]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): S^ ? =>
          let result: S = S.create(hi)
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let elem = _gen.generate(rnd)?
              result.push(consume elem)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun shuffled_array_gen[T](
    gen: Generator[Array[T]])
    : Generator[Array[T]]
  =>
    """
    Generate an array and shuffle it.
    """
    Generator[Array[T]](
      object is GenObj[Array[T]]
        let _gen: GenObj[Array[T]] = gen
        fun generate(rnd: Randomness): Array[T]^ ? =>
          let arr = _gen.generate(rnd)?
          rnd.shuffle[T](arr)?
          arr
      end)

  fun shuffled_iter[T](array: Array[T]): Generator[Iterator[this->T!]] =>
    """
    Shuffle the elements of the array and return an iterator.
    """
    Generator[Iterator[this->T!]](
      object is GenObj[Iterator[this->T!]]
        fun generate(rnd: Randomness): Iterator[this->T!]^ ? =>
          let cloned = array.clone()
          rnd.shuffle[this->T!](cloned)?
          cloned.values()
      end)

  fun list_of[T](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[List[T]]
  =>
    """
    Generate a `List[T]` with size in `from` to `to`.
    """
    Generators.seq_of[T, List[T]](gen, from, to)

  fun set_of[T: (Hashable #read & Equatable[T] #read)](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[Set[T]]
  =>
    """
    Generate a `Set[T]` with elements in `from` to `to`.
    Uses boolean-per-element encoding with a stall guard for duplicate
    rejection.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[Set[T]](
      object is GenObj[Set[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): Set[T]^ ? =>
          let result = Set[T].create(hi)
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              result.set(_gen.generate(rnd)?)
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun set_is_of[T](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[SetIs[T]]
  =>
    """
    Generate a `SetIs[T]` with elements in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[SetIs[T]](
      object is GenObj[SetIs[T]]
        fun generate(rnd: Randomness): SetIs[T]^ ? =>
          let result = SetIs[T].create(hi)
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              result.set(gen.generate(rnd)?)
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun map_of[K: (Hashable #read & Equatable[K] #read), V](
    gen: Generator[(K, V)],
    from: USize = 0,
    to: USize = 100)
    : Generator[Map[K, V]]
  =>
    """
    Generate a `Map[K, V]` with entries in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[Map[K, V]](
      object is GenObj[Map[K, V]]
        fun generate(rnd: Randomness): Map[K, V]^ ? =>
          let result = Map[K, V].create(hi)
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              (let k, let v) = gen.generate(rnd)?
              result(consume k) = consume v
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun map_is_of[K, V](
    gen: Generator[(K, V)],
    from: USize = 0,
    to: USize = 100)
    : Generator[MapIs[K, V]]
  =>
    """
    Generate a `MapIs[K, V]` with entries in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[MapIs[K, V]](
      object is GenObj[MapIs[K, V]]
        fun generate(rnd: Randomness): MapIs[K, V]^ ? =>
          let result = MapIs[K, V].create(hi)
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              (let k, let v) = gen.generate(rnd)?
              result(consume k) = consume v
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun vec_of[T: Any #share](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.Vec[T]]
  =>
    """
    Generate a persistent `Vec[T]` with size in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.Vec[T]](
      object is GenObj[persistent.Vec[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): persistent.Vec[T]^ ? =>
          var result = persistent.Vec[T]
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              result = result.push(_gen.generate(rnd)?)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun persistent_list_of[T: Any #share](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.List[T]]
  =>
    """
    Generate a persistent `List[T]` with size in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.List[T]](
      object is GenObj[persistent.List[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): persistent.List[T]^ ? =>
          var result: persistent.List[T] = persistent.Lists[T].empty()
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              result = result.prepend(_gen.generate(rnd)?)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result.reverse()
      end)

  fun persistent_set_of[T: (Hashable val & Equatable[T] val)](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.Set[T]]
  =>
    """
    Generate a persistent `Set[T]` with elements in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.Set[T]](
      object is GenObj[persistent.Set[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): persistent.Set[T]^ ? =>
          var result = persistent.Set[T].create()
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              result = result + _gen.generate(rnd)?
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun persistent_set_is_of[T: Any #share](
    gen: Generator[T],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.SetIs[T]]
  =>
    """
    Generate a persistent `SetIs[T]` with elements in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.SetIs[T]](
      object is GenObj[persistent.SetIs[T]]
        let _gen: GenObj[T] = gen
        fun generate(rnd: Randomness): persistent.SetIs[T]^ ? =>
          var result = persistent.SetIs[T].create()
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              result = result + _gen.generate(rnd)?
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun persistent_map_of[
    K: (Hashable val & Equatable[K] val),
    V: Any #share](
    gen: Generator[(K, V)],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.Map[K, V]]
  =>
    """
    Generate a persistent `Map[K, V]` with entries in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.Map[K, V]](
      object is GenObj[persistent.Map[K, V]]
        fun generate(rnd: Randomness): persistent.Map[K, V]^ ? =>
          var result = persistent.Map[K, V].create()
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              (let k, let v) = gen.generate(rnd)?
              result = result.update(consume k, consume v)
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun persistent_map_is_of[K: Any #share, V: Any #share](
    gen: Generator[(K, V)],
    from: USize = 0,
    to: USize = 100)
    : Generator[persistent.MapIs[K, V]]
  =>
    """
    Generate a persistent `MapIs[K, V]` with entries in `from` to `to`.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[persistent.MapIs[K, V]](
      object is GenObj[persistent.MapIs[K, V]]
        fun generate(rnd: Randomness): persistent.MapIs[K, V]^ ? =>
          var result = persistent.MapIs[K, V].create()
          var stall: USize = 0
          while (result.size() < hi) and (stall < 100) do
            rnd.start_span(SpanElement)
            let cont =
              if result.size() < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              let prev = result.size()
              (let k, let v) = gen.generate(rnd)?
              result = result.update(consume k, consume v)
              if result.size() == prev then
                stall = stall + 1
              else
                stall = 0
              end
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          result
      end)

  fun one_of[T](xs: ReadSeq[T]): Generator[box->T] =>
    """
    Generate a random value from the given ReadSeq.
    Errors if `xs` is empty.
    """
    Generator[box->T](
      object is GenObj[box->T]
        fun generate(rnd: Randomness): box->T ? =>
          xs(rnd.usize(0, xs.size() - 1)?)?
      end)

  fun one_of_safe[T](xs: ReadSeq[T]): Generator[box->T] ? =>
    """
    Version of `one_of` that errors at construction time if `xs` is empty.
    """
    if xs.size() == 0 then error end
    Generators.one_of[T](xs)

  fun frequency[T](
    weighted_generators: ReadSeq[WeightedGenerator[T]])
    : Generator[T]
  =>
    """
    Choose a value from one of the given Generators, weighted by associated
    weights.
    """
    Generator[T](
      object is GenObj[T]
        fun generate(rnd: Randomness): T^ ? =>
          let weight_sum: USize =
            Iter[WeightedGenerator[T]](weighted_generators.values())
              .fold[USize](
                0,
                {(acc: USize, weighted_gen: WeightedGenerator[T]): USize^ =>
                  weighted_gen._1 + acc
                })
          let desired_sum = rnd.usize(0, weight_sum)?
          var running_sum: USize = 0
          for weighted_gen in weighted_generators.values() do
            let new_sum = running_sum + weighted_gen._1
            if
              ((desired_sum == 0) or
                ((running_sum < desired_sum) and
                  (desired_sum <= new_sum)))
            then
              return weighted_gen._2.generate(rnd)?
            else
              running_sum = new_sum
            end
          end
          error
      end)

  fun frequency_safe[T](
    weighted_generators: ReadSeq[WeightedGenerator[T]])
    : Generator[T] ?
  =>
    """
    Version of `frequency` that errors if the given `weighted_generators` is
    empty.
    """
    if weighted_generators.size() == 0 then error end
    Generators.frequency[T](weighted_generators)

  fun zip2[T1, T2](
    gen1: Generator[T1],
    gen2: Generator[T2])
    : Generator[(T1, T2)]
  =>
    """
    Zip two generators into a generator of a 2-tuple.
    """
    Generator[(T1, T2)](
      object is GenObj[(T1, T2)]
        fun generate(rnd: Randomness): (T1^, T2^) ? =>
          (gen1.generate(rnd)?, gen2.generate(rnd)?)
      end)

  fun zip3[T1, T2, T3](
    gen1: Generator[T1],
    gen2: Generator[T2],
    gen3: Generator[T3])
    : Generator[(T1, T2, T3)]
  =>
    """
    Zip three generators into a generator of a 3-tuple.
    """
    Generator[(T1, T2, T3)](
      object is GenObj[(T1, T2, T3)]
        fun generate(rnd: Randomness): (T1^, T2^, T3^) ? =>
          (gen1.generate(rnd)?, gen2.generate(rnd)?, gen3.generate(rnd)?)
      end)

  fun zip4[T1, T2, T3, T4](
    gen1: Generator[T1],
    gen2: Generator[T2],
    gen3: Generator[T3],
    gen4: Generator[T4])
    : Generator[(T1, T2, T3, T4)]
  =>
    """
    Zip four generators into a generator of a 4-tuple.
    """
    Generator[(T1, T2, T3, T4)](
      object is GenObj[(T1, T2, T3, T4)]
        fun generate(rnd: Randomness): (T1^, T2^, T3^, T4^) ? =>
          (gen1.generate(rnd)?, gen2.generate(rnd)?,
            gen3.generate(rnd)?, gen4.generate(rnd)?)
      end)

  fun map2[T1, T2, T3](
    gen1: Generator[T1],
    gen2: Generator[T2],
    fn: {(T1, T2): T3^})
    : Generator[T3]
  =>
    """
    Convenience combinator for mapping 2 generators into 1.
    """
    Generators.zip2[T1, T2](gen1, gen2)
      .map[T3]({(arg) =>
        (let arg1, let arg2) = consume arg
        fn(consume arg1, consume arg2)
      })

  fun map3[T1, T2, T3, T4](
    gen1: Generator[T1],
    gen2: Generator[T2],
    gen3: Generator[T3],
    fn: {(T1, T2, T3): T4^})
    : Generator[T4]
  =>
    """
    Convenience combinator for mapping 3 generators into 1.
    """
    Generators.zip3[T1, T2, T3](gen1, gen2, gen3)
      .map[T4]({(arg) =>
        (let arg1, let arg2, let arg3) = consume arg
        fn(consume arg1, consume arg2, consume arg3)
      })

  fun map4[T1, T2, T3, T4, T5](
    gen1: Generator[T1],
    gen2: Generator[T2],
    gen3: Generator[T3],
    gen4: Generator[T4],
    fn: {(T1, T2, T3, T4): T5^})
    : Generator[T5]
  =>
    """
    Convenience combinator for mapping 4 generators into 1.
    """
    Generators.zip4[T1, T2, T3, T4](gen1, gen2, gen3, gen4)
      .map[T5]({(arg) =>
        (let arg1, let arg2, let arg3, let arg4) = consume arg
        fn(consume arg1, consume arg2, consume arg3, consume arg4)
      })

  fun bool(): Generator[Bool] =>
    """
    Generate random Bool values.
    """
    Generator[Bool](
      object is GenObj[Bool]
        fun generate(rnd: Randomness): Bool ? => rnd.bool()?
      end)

  fun u8(
    from: U8 = U8.min_value(),
    to: U8 = U8.max_value())
    : Generator[U8]
  =>
    """
    Generate U8 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[U8](
      object is GenObj[U8]
        fun generate(rnd: Randomness): U8 ? => rnd.u8(lo, hi)?
      end)

  fun u16(
    from: U16 = U16.min_value(),
    to: U16 = U16.max_value())
    : Generator[U16]
  =>
    """
    Generate U16 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[U16](
      object is GenObj[U16]
        fun generate(rnd: Randomness): U16 ? => rnd.u16(lo, hi)?
      end)

  fun u32(
    from: U32 = U32.min_value(),
    to: U32 = U32.max_value())
    : Generator[U32]
  =>
    """
    Generate U32 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[U32](
      object is GenObj[U32]
        fun generate(rnd: Randomness): U32 ? => rnd.u32(lo, hi)?
      end)

  fun u64(
    from: U64 = U64.min_value(),
    to: U64 = U64.max_value())
    : Generator[U64]
  =>
    """
    Generate U64 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[U64](
      object is GenObj[U64]
        fun generate(rnd: Randomness): U64 ? => rnd.u64(lo, hi)?
      end)

  fun u128(
    from: U128 = U128.min_value(),
    to: U128 = U128.max_value())
    : Generator[U128]
  =>
    """
    Generate U128 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[U128](
      object is GenObj[U128]
        fun generate(rnd: Randomness): U128 ? => rnd.u128(lo, hi)?
      end)

  fun usize(
    from: USize = USize.min_value(),
    to: USize = USize.max_value())
    : Generator[USize]
  =>
    """
    Generate USize values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[USize](
      object is GenObj[USize]
        fun generate(rnd: Randomness): USize ? => rnd.usize(lo, hi)?
      end)

  fun ulong(
    from: ULong = ULong.min_value(),
    to: ULong = ULong.max_value())
    : Generator[ULong]
  =>
    """
    Generate ULong values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[ULong](
      object is GenObj[ULong]
        fun generate(rnd: Randomness): ULong ? => rnd.ulong(lo, hi)?
      end)

  fun i8(
    from: I8 = I8.min_value(),
    to: I8 = I8.max_value())
    : Generator[I8]
  =>
    """
    Generate I8 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[I8](
      object is GenObj[I8]
        fun generate(rnd: Randomness): I8 ? => rnd.i8(lo, hi)?
      end)

  fun i16(
    from: I16 = I16.min_value(),
    to: I16 = I16.max_value())
    : Generator[I16]
  =>
    """
    Generate I16 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[I16](
      object is GenObj[I16]
        fun generate(rnd: Randomness): I16 ? => rnd.i16(lo, hi)?
      end)

  fun i32(
    from: I32 = I32.min_value(),
    to: I32 = I32.max_value())
    : Generator[I32]
  =>
    """
    Generate I32 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[I32](
      object is GenObj[I32]
        fun generate(rnd: Randomness): I32 ? => rnd.i32(lo, hi)?
      end)

  fun i64(
    from: I64 = I64.min_value(),
    to: I64 = I64.max_value())
    : Generator[I64]
  =>
    """
    Generate I64 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[I64](
      object is GenObj[I64]
        fun generate(rnd: Randomness): I64 ? => rnd.i64(lo, hi)?
      end)

  fun i128(
    from: I128 = I128.min_value(),
    to: I128 = I128.max_value())
    : Generator[I128]
  =>
    """
    Generate I128 values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[I128](
      object is GenObj[I128]
        fun generate(rnd: Randomness): I128 ? => rnd.i128(lo, hi)?
      end)

  fun ilong(
    from: ILong = ILong.min_value(),
    to: ILong = ILong.max_value())
    : Generator[ILong]
  =>
    """
    Generate ILong values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[ILong](
      object is GenObj[ILong]
        fun generate(rnd: Randomness): ILong ? => rnd.ilong(lo, hi)?
      end)

  fun isize(
    from: ISize = ISize.min_value(),
    to: ISize = ISize.max_value())
    : Generator[ISize]
  =>
    """
    Generate ISize values in `[from, to]`. Order does not matter.
    """
    let lo = from.min(to)
    let hi = from.max(to)
    Generator[ISize](
      object is GenObj[ISize]
        fun generate(rnd: Randomness): ISize ? => rnd.isize(lo, hi)?
      end)

  fun byte_string(
    gen: Generator[U8],
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate a string from bytes with length in `from` to `to`.
    Uses boolean-per-element encoding.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[String](
      object is GenObj[String]
        fun generate(rnd: Randomness): String^ ? =>
          let arr: Array[U8] iso = recover Array[U8](hi) end
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              arr.push(gen.generate(rnd)?)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          String.from_iso_array(consume arr)
      end)

  fun ascii(
    from: USize = 0,
    to: USize = 100,
    range: ASCIIRange = ASCIIAll)
    : Generator[String]
  =>
    """
    Generate a string within the given `range` with length in `from` to `to`.
    """
    let range_bytes = range.apply()
    let fallback = U8(0)
    let range_bytes_gen = usize(0, range_bytes.size() - 1)
      .map[U8]({(size) =>
        try
          range_bytes(size)?
        else
          fallback
        end
      })
    byte_string(range_bytes_gen, from, to)

  fun ascii_printable(
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate strings of printable ASCII characters.
    """
    ascii(from, to, ASCIIPrintable)

  fun ascii_numeric(
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate strings of numeric ASCII characters.
    """
    ascii(from, to, ASCIIDigits)

  fun ascii_letters(
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate strings of ASCII letter characters.
    """
    ascii(from, to, ASCIILetters)

  fun utf32_codepoint_string(
    gen: Generator[U32],
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate a string from unicode codepoints with length in `from` to `to`
    codepoints.
    """
    let lo = from.min(to)
    let hi = from.max(to)

    Generator[String](
      object is GenObj[String]
        fun generate(rnd: Randomness): String^ ? =>
          let s: String iso = recover String(hi) end
          var count: USize = 0
          while count < hi do
            rnd.start_span(SpanElement)
            let cont =
              if count < lo then
                rnd.forced_bool(true)?
              else
                rnd.bool()?
              end
            if cont then
              var cp = gen.generate(rnd)?
              while (cp > 0xD7FF) and (cp < 0xE000) do
                cp = gen.generate(rnd)?
              end
              s.push_utf32(cp)
              count = count + 1
              rnd.end_span()?
            else
              rnd.end_span()?
              break
            end
          end
          consume s
      end)

  fun unicode(
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate a random String of Unicode code points.
    """
    let range_1 = u32(0x0, 0xD7FF)
    let range_1_size: USize = 0xD7FF
    let range_2 = u32(0xE000, 0x10FFFF)
    let range_2_size = U32(0x10FFFF - 0xE000).usize()

    let code_point_gen =
      frequency[U32](
        [ (range_1_size, range_1)
          (range_2_size, range_2)
        ])
    utf32_codepoint_string(code_point_gen, from, to)

  fun unicode_bmp(
    from: USize = 0,
    to: USize = 100)
    : Generator[String]
  =>
    """
    Generate a random String of Unicode BMP code points.
    """
    let range_1 = u32(0x0, 0xD7FF)
    let range_1_size: USize = 0xD7FF
    let range_2 = u32(0xE000, 0xFFFF)
    let range_2_size = U32(0xFFFF - 0xE000).usize()

    let code_point_gen =
      frequency[U32](
        [ (range_1_size, range_1)
          (range_2_size, range_2)
        ])
    utf32_codepoint_string(code_point_gen, from, to)

```````