///|
pub struct Relay {
  decoder : Decoder
}

///|
pub fn Relay::new(
  generation : Generation,
  max_packets~ : Int32 = 4096,
) -> Relay raise CodeError {
  { decoder: Decoder::new(generation, max_packets~), }
}

///|
pub fn Relay::generation(self : Relay) -> Generation {
  self.decoder.generation()
}

///|
pub fn Relay::rank(self : Relay) -> Int32 {
  self.decoder.rank()
}

///|
pub fn Relay::admit(self : Relay, packet : Packet) -> Admission raise CodeError {
  self.decoder.admit(packet)
}

///|
pub fn Relay::report(self : Relay) -> DecodeReport {
  self.decoder.report()
}

///|
// Weights index the CURRENT pivot-ordered basis. No source recovery is required.
// Recoding can redistribute information but can never increase the relay's rank.
pub fn Relay::mix(
  self : Relay,
  weights : Symbols,
  sequence : Int32,
) -> Packet raise CodeError {
  if sequence < 0 {
    raise Invalid("negative recoded sequence")
  }
  let basis = self.decoder.basis_equations()
  if basis.length() == 0 {
    raise Incomplete(self.generation().count())
  }
  if weights.length() != basis.length() {
    raise Shape("one weight is required per current basis row")
  }
  let coefficients = Array::make(self.generation().count(), 0)
  let payload = Array::make(self.generation().width(), 0)
  for i in 0.. Packet raise CodeError {
  if sequence < 0 {
    raise Invalid("negative recoded sequence")
  }
  if self.rank() == 0 {
    raise Incomplete(self.generation().count())
  }
  self.mix(stream.draw(self.rank()), sequence)
}

///|
// Export independent relay rows rather than promising random packet independence.
pub fn Relay::basis_packets(
  self : Relay,
  first_sequence : Int32,
) -> Array[Packet] raise CodeError {
  if first_sequence < 0 {
    raise Invalid("negative first sequence")
  }
  let basis = self.decoder.basis_equations()
  if basis.length() > 0 && first_sequence > 2147483647 - (basis.length() - 1) {
    raise Limit("basis packet sequence overflow")
  }
  let out : Array[Packet] = []
  for i in 0..