///|
pub struct CoefficientStream {
  mut state : UInt32
  mut draw_count : Int32
  draw_limit : Int32
}

///|
pub fn CoefficientStream::new(
  seed : UInt32,
  max_draws~ : Int32 = 1048576,
) -> CoefficientStream raise CodeError {
  if seed == 0U {
    raise Invalid("xorshift seed must be nonzero")
  }
  if max_draws < 1 || max_draws > 1048576 {
    raise Limit("coefficient draw limit must be 1..1048576")
  }
  { state: seed, draw_count: 0, draw_limit: max_draws, }
}

///|
fn rng_step(state : UInt32) -> UInt32 {
  let x = state ^ (state << 13)
  let y = x ^ (x >> 17)
  y ^ (y << 5)
}

///|
pub fn CoefficientStream::draws(self : CoefficientStream) -> Int32 {
  self.draw_count
}

///|
pub fn CoefficientStream::remaining(self : CoefficientStream) -> Int32 {
  self.draw_limit - self.draw_count
}

///|
// Reproducible coefficient selection, NOT a cryptographic RNG or MDS code.
// The all-zero vector is replaced by e_0; this is deliberately not uniform.
pub fn CoefficientStream::draw(
  self : CoefficientStream,
  count : Int32,
) -> Symbols raise CodeError {
  if count < 1 || count > 64 {
    raise Limit("coefficient count must be 1..64")
  }
  if count > self.remaining() {
    raise Limit("coefficient stream exhausted")
  }
  let mut state = self.state
  let values : Array[Int32] = []
  let mut any = false
  for _ in 0.. Packet raise CodeError {
  if sequence < 0 {
    raise Invalid("negative packet sequence")
  }
  let coefficients = stream.draw(self.generation().count())
  self.encode(coefficients, sequence)
}