// Structured error model shared by the parser, validator and builder.
//
// Every error carries the parsing stage, the failure kind, the raw byte
// offset in the input stream (a real stream position, never a made-up
// one), the zero-based record index and a short context string such as
// the name of the field being processed.
///|
/// The processing stage in which an error occurred.
pub enum WarcErrorStage {
Input
Version
Header
Field
Number
ContentLength
Block
Separator
Date
Uri
Digest
Record
Archive
Segment
Limit
Builder
} derive(Eq, @debug.Debug)
///|
/// The precise failure kind. Parse-time failures and semantic
/// validation failures share this model; advisory findings are reported
/// separately by the audit engine.
pub enum WarcErrorKind {
UnexpectedEof
InvalidVersion
MissingColon
InvalidFieldName
InvalidUtf8
InvalidContentLength
IntegerOverflow
ContentLengthMismatch
MissingRequiredField
DuplicateField
InvalidDate
InvalidUri
InvalidDigest
InvalidRecordType
InvalidSeparator
TrailingGarbage
LimitExceeded
InvalidFieldValue
MisplacedField
InvalidIpAddress
} derive(Eq, @debug.Debug)
///|
/// A structured WARC error.
pub struct WarcError {
stage : WarcErrorStage
kind : WarcErrorKind
byte_offset : Int64
record_index : Int64
context : String
}
///|
/// Create an error at a byte offset within a specific record.
pub fn WarcError::new(
stage : WarcErrorStage,
kind : WarcErrorKind,
byte_offset : Int64,
record_index : Int64,
context : String,
) -> WarcError {
{ stage, kind, byte_offset, record_index, context }
}
///|
/// Every stage code in declaration order. Stable across versions so
/// callers can render error documentation without matching enums.
pub fn all_stage_codes() -> Array[String] {
[
"input", "version", "header", "field", "number", "content-length", "block", "separator",
"date", "uri", "digest", "record", "archive", "segment", "limit", "builder",
]
}
///|
/// Every kind code in declaration order. Stable across versions.
pub fn all_kind_codes() -> Array[String] {
[
"unexpected-eof", "invalid-version", "missing-colon", "invalid-field-name", "invalid-utf8",
"invalid-content-length", "integer-overflow", "content-length-mismatch", "missing-required-field",
"duplicate-field", "invalid-date", "invalid-uri", "invalid-digest", "invalid-record-type",
"invalid-separator", "trailing-garbage", "limit-exceeded", "invalid-field-value",
"misplaced-field", "invalid-ip-address",
]
}
///|
/// Resolve a machine-readable stage name back to a stage.
pub fn stage_of_code(code : String) -> WarcErrorStage? {
match code {
"input" => Some(Input)
"version" => Some(Version)
"header" => Some(Header)
"field" => Some(Field)
"number" => Some(Number)
"content-length" => Some(ContentLength)
"block" => Some(Block)
"separator" => Some(Separator)
"date" => Some(Date)
"uri" => Some(Uri)
"digest" => Some(Digest)
"record" => Some(Record)
"archive" => Some(Archive)
"segment" => Some(Segment)
"limit" => Some(Limit)
"builder" => Some(Builder)
_ => None
}
}
///|
/// Resolve a machine-readable kind name back to a kind.
pub fn kind_of_code(code : String) -> WarcErrorKind? {
match code {
"unexpected-eof" => Some(UnexpectedEof)
"invalid-version" => Some(InvalidVersion)
"missing-colon" => Some(MissingColon)
"invalid-field-name" => Some(InvalidFieldName)
"invalid-utf8" => Some(InvalidUtf8)
"invalid-content-length" => Some(InvalidContentLength)
"integer-overflow" => Some(IntegerOverflow)
"content-length-mismatch" => Some(ContentLengthMismatch)
"missing-required-field" => Some(MissingRequiredField)
"duplicate-field" => Some(DuplicateField)
"invalid-date" => Some(InvalidDate)
"invalid-uri" => Some(InvalidUri)
"invalid-digest" => Some(InvalidDigest)
"invalid-record-type" => Some(InvalidRecordType)
"invalid-separator" => Some(InvalidSeparator)
"trailing-garbage" => Some(TrailingGarbage)
"limit-exceeded" => Some(LimitExceeded)
"invalid-field-value" => Some(InvalidFieldValue)
"misplaced-field" => Some(MisplacedField)
"invalid-ip-address" => Some(InvalidIpAddress)
_ => None
}
}
///|
/// The lowercase machine-readable stage name.
pub fn WarcErrorStage::stage_name(self : WarcErrorStage) -> String {
match self {
Input => "input"
Version => "version"
Header => "header"
Field => "field"
Number => "number"
ContentLength => "content-length"
Block => "block"
Separator => "separator"
Date => "date"
Uri => "uri"
Digest => "digest"
Record => "record"
Archive => "archive"
Segment => "segment"
Limit => "limit"
Builder => "builder"
}
}
///|
/// The lowercase machine-readable kind name.
pub fn WarcErrorKind::kind_name(self : WarcErrorKind) -> String {
match self {
UnexpectedEof => "unexpected-eof"
InvalidVersion => "invalid-version"
MissingColon => "missing-colon"
InvalidFieldName => "invalid-field-name"
InvalidUtf8 => "invalid-utf8"
InvalidContentLength => "invalid-content-length"
IntegerOverflow => "integer-overflow"
ContentLengthMismatch => "content-length-mismatch"
MissingRequiredField => "missing-required-field"
DuplicateField => "duplicate-field"
InvalidDate => "invalid-date"
InvalidUri => "invalid-uri"
InvalidDigest => "invalid-digest"
InvalidRecordType => "invalid-record-type"
InvalidSeparator => "invalid-separator"
TrailingGarbage => "trailing-garbage"
LimitExceeded => "limit-exceeded"
InvalidFieldValue => "invalid-field-value"
MisplacedField => "misplaced-field"
InvalidIpAddress => "invalid-ip-address"
}
}
///|
/// A human-readable one-line description of the error.
pub fn WarcError::to_string(self : WarcError) -> String {
"[\{self.stage.stage_name()}] \{self.kind.kind_name()} at byte \{self.byte_offset} (record \{self.record_index}): \{self.context}"
}