///|
/// The error every codec raises, its kinds, and the limits a stream can
/// exceed, from `gaato/codec`, so that a caller of a codec can name them with
/// this package as its only import. A constructor is matched unqualified, as
/// in `CodecError(Corrupt, _)`, where the type is known (a `catch` on a
/// codec's step), or qualified by its type, as in
/// `@codec_bytes.CodecError::CodecError(kind, _)`.
pub using @codec {type CodecError, type ErrorKind, type Limit, type Resource}

///|
/// Why a step stopped without an error.
pub(all) enum Status {
  /// The stream is complete. With `Until::EndOfInput` this needs `end` and
  /// every input byte consumed; with `Until::EndOfMember`, nothing after the
  /// first member was consumed.
  Done
  /// Every input byte was consumed, and everything it determines was written.
  NeedMoreInput
  /// The output slice is full.
  NeedMoreOutput
} derive(Eq, @debug.Debug)

///|
pub extend Status with Eq::{equal, not_equal}

///|
pub extend Status with @debug.Debug::{to_repr}

///|
/// Where a decoder stops, for formats whose streams can follow one another.
pub(all) enum Until {
  /// Decode every member up to the end of the input; bytes after the last
  /// member are an error.
  EndOfInput
  /// Stop right after the first member and leave the rest unread.
  EndOfMember
} derive(Eq, @debug.Debug)

///|
pub extend Until with Eq::{equal, not_equal}

///|
pub extend Until with @debug.Debug::{to_repr}

///|
/// What an encoder's step should do with the input it has.
pub(all) enum EncodeAction {
  /// Compress as convenient; output may lag behind input.
  Continue
  /// Make everything so far decodable without ending the stream.
  Flush
  /// End the stream.
  Finish
} derive(Eq, @debug.Debug)

///|
pub extend EncodeAction with Eq::{equal, not_equal}

///|
pub extend EncodeAction with @debug.Debug::{to_repr}

///|
/// A decoder of a byte stream, driven step by step.
///
/// A step consumes a prefix of `input` and writes a prefix of `output`
/// (`last_consumed` and `last_produced` say how much), and returns why it
/// stopped. `end` says whether `input` reaches the end of the data. The rules
/// every decoder keeps are in the repository's CONTRACT.md: among them, a
/// step that raises first writes all the output the input determines before
/// the error (answering `NeedMoreOutput` if the slice fills first) and
/// reports what it consumed and wrote, errors stick until `reset`, and the
/// output and the error do not depend on how input and output are split.
pub(open) trait Decode {
  fn step(Self, BytesView, MutArrayView[Byte], end~ : Bool) -> Status raise @codec.CodecError
  /// Input bytes consumed by the last step, one that raised included: what it
  /// consumed before the error. For `TrailingData`, exactly up to the end of
  /// the stream (zero if it ended before this step's input). Zero for the
  /// steps after an error.
  fn last_consumed(Self) -> Int32
  /// Output bytes written by the last step, one that raised included: what it
  /// wrote before the error. Zero for the steps after an error.
  fn last_produced(Self) -> Int32
  /// Returns the decoder to the state of a new one with the same options.
  fn reset(Self) -> Unit
  /// Bytes the decoder has allocated for the current stream.
  fn memory_usage(Self) -> Int32
}

///|
/// An encoder of a byte stream, driven step by step, with the same rules as
/// `Decode`; `action` takes the place of `end`.
pub(open) trait Encode {
  fn step(Self, BytesView, MutArrayView[Byte], action~ : EncodeAction) -> Status raise @codec.CodecError
  /// Input bytes consumed by the last step, one that raised included: what it
  /// consumed before the error. Zero for the steps after an error.
  fn last_consumed(Self) -> Int32
  /// Output bytes written by the last step, one that raised included: what it
  /// wrote before the error. Zero for the steps after an error.
  fn last_produced(Self) -> Int32
  /// Returns the encoder to the state of a new one with the same options.
  fn reset(Self) -> Unit
  /// Bytes the encoder has allocated for the current stream.
  fn memory_usage(Self) -> Int32
}