///|
/// Explicit ceilings for untrusted help/argv. Values must all be positive.
pub(all) struct Limits {
  document_units : Int32
  usage_tokens : Int32
  options : Int32
  argv_count : Int32
  argv_units : Int32
  match_steps : Int32
}

///|
pub fn Limits::default() -> Limits {
  {
    document_units: 65536,
    usage_tokens: 8192,
    options: 2048,
    argv_count: 4096,
    argv_units: 1048576,
    match_steps: 1000000,
  }
}

///|
fn Limits::validate(self : Limits) -> Unit raise DocoptError {
  guard self.document_units > 0 &&
    self.usage_tokens > 0 &&
    self.options > 0 &&
    self.argv_count > 0 &&
    self.argv_units > 0 &&
    self.match_steps > 0 else {
    raise Language("resource limits must be positive")
  }
  guard self.document_units <= 1048576 &&
    self.usage_tokens <= 32768 &&
    self.options <= 8192 &&
    self.argv_count <= 32768 &&
    self.argv_units <= 16777216 &&
    self.match_steps <= 100000000 else {
    raise Language("resource limits exceed hard safety ceilings")
  }
}

///|
priv struct MatchBudget {
  mut remaining : Int32
}

///|
fn MatchBudget::charge(
  self : MatchBudget,
  cost : Int32,
) -> Unit raise DocoptError {
  guard cost <= self.remaining else {
    raise Limit("matching work budget exhausted")
  }
  self.remaining -= cost
}