verit-core 0.2.0

Internal: portable core engine for Exavian Veritate. Not a public API — depend on `verit`.
Documentation
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
    /// Message does not start with the "VRT" magic family at all — not a
    /// Veritate message.
    BadMagic,
    /// A Veritate message ("VRT" prefix) whose version byte this decoder does
    /// not implement. `found` is the version digit in the magic; `supported`
    /// is what this build understands. Guarantees a vN message can never be
    /// silently misread as vM.
    UnsupportedVersion { found: u8, supported: u8 },
    /// The fixed header is structurally invalid for this version: an unknown
    /// flag bit, or a reserved field that is not zero.
    MalformedHeader(&'static str),
    /// Buffer too short for the fixed header or a declared region.
    Truncated,
    /// An offset or length points outside the message buffer.
    OutOfBounds,
    /// List element index past the end of the list.
    IndexOutOfBounds,
    /// A string field holds invalid UTF-8.
    BadUtf8,
    /// The (inline) schema bytes are malformed or non-canonical.
    BadSchema(String),
    /// A value's type does not match the schema field type (write path),
    /// or a typed getter was used on a differently-typed field (read path).
    TypeMismatch { expected: String, got: String },
    /// Writer and reader schema cannot be resolved (e.g. int narrowing).
    Incompatible(String),
    /// A value referenced a field ID that is not in the schema.
    UnknownFieldId(u16),
    /// The same field ID appeared twice in one struct value.
    DuplicateField(u16),
    /// The same key appeared twice in one map value.
    DuplicateMapKey,
    /// A `union` value or wire tag selected a variant index that does not exist.
    BadUnionTag(u32),
    /// A dense struct was encoded without one of its (mandatory) fields.
    MissingField(u16),
    /// The message's schema id does not match the resolver's writer schema
    /// (or the inline schema bytes hash to something else).
    SchemaIdMismatch { message: u128, expected: u128 },
    /// dump_json needs an inline schema but the message was hash-only.
    NoInlineSchema,
    /// Recursion (nested structs/lists) exceeded the safety depth limit — the
    /// message may contain an offset cycle or hostile nesting.
    DepthLimitExceeded,
    /// A bounded read exhausted its traversal budget: the message followed
    /// offsets that would touch more bytes than the budget allows (an
    /// amplification guard for untrusted input — see `Budget` / the wire spec §5.2).
    TraversalBudgetExceeded,
    /// Message would exceed the 4 GiB u32-offset limit.
    MessageTooLarge,
    /// A `.vertc` container file is malformed: bad magic/version, an index
    /// pointing out of bounds, a misaligned or overlapping record, etc.
    BadContainer(&'static str),
    /// A `.verit` file is structurally malformed: bad magic or version, a
    /// nonzero reserved field, an index entry pointing outside the record
    /// region, a misaligned offset, and so on.
    BadFile(&'static str),
    /// The `.verit` file sets a bit in `required_features` that this build does
    /// not implement, so it cannot be read correctly (File Format
    /// Specification §3.1). Unknown *optional* feature bits are ignored, not
    /// reported here.
    UnsupportedFileFeature(u32),
    /// No valid footer was found anywhere in a `.verit` file, so no committed
    /// state is recoverable — the file was destroyed, not merely torn.
    NoValidFooter,
    /// A `.verit` file's index references a schema id its schema section does
    /// not contain, so the file is not self-contained.
    MissingSchema(u128),
    /// Another writer already holds this file's advisory lock. The format
    /// allows one writer and many readers (File Format Specification §7.3);
    /// concurrent writers are undefined, so this refuses rather than racing.
    /// Carries the lock file's path — delete it by hand if a previous writer
    /// was killed.
    AlreadyLocked(String),
    /// A record's bytes do not match the CRC-32 the file stored for it — bit
    /// rot, or a tampered record. Only reachable on a file written with
    /// per-record checksums (`OPT_RECORD_CRC`). Names the record's stable id
    /// rather than its position, since positions shift.
    ChecksumMismatch {
        /// The record's stable id.
        id: u64,
        /// What the file says the CRC should be.
        expected: u32,
        /// What the bytes actually hash to.
        found: u32,
    },
    /// The underlying I/O operation failed. Carried as a string so `Error`
    /// stays `Clone + PartialEq` (`std::io::Error` is neither).
    Io(String),
    /// Internal invariant violation (a bug in this library).
    Internal(&'static str),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::BadMagic => write!(f, "not a Veritate message (bad magic)"),
            Error::UnsupportedVersion { found, supported } => write!(
                f,
                "unsupported Veritate wire version: message is v{}, this build implements v{}",
                *found as char, *supported as char
            ),
            Error::MalformedHeader(s) => write!(f, "malformed message header: {s}"),
            Error::Truncated => write!(f, "message truncated"),
            Error::OutOfBounds => write!(f, "offset out of bounds"),
            Error::IndexOutOfBounds => write!(f, "list index out of bounds"),
            Error::BadUtf8 => write!(f, "string field is not valid UTF-8"),
            Error::BadSchema(s) => write!(f, "bad schema: {s}"),
            Error::TypeMismatch { expected, got } => {
                write!(f, "type mismatch: expected {expected}, got {got}")
            }
            Error::Incompatible(s) => write!(f, "schemas incompatible: {s}"),
            Error::UnknownFieldId(id) => write!(f, "field id {id} not in schema"),
            Error::DuplicateField(id) => write!(f, "field id {id} set twice"),
            Error::DuplicateMapKey => write!(f, "the same map key was set twice"),
            Error::BadUnionTag(t) => write!(f, "union tag {t} is not a valid variant index"),
            Error::MissingField(id) => {
                write!(f, "dense struct requires field id {id}, which was not set")
            }
            Error::SchemaIdMismatch { message, expected } => write!(
                f,
                "schema id mismatch: message has {message:#034x}, expected {expected:#034x}"
            ),
            Error::NoInlineSchema => write!(f, "message carries no inline schema"),
            Error::DepthLimitExceeded => {
                write!(f, "nesting depth limit exceeded (possible offset cycle)")
            }
            Error::TraversalBudgetExceeded => {
                write!(
                    f,
                    "traversal budget exceeded (possible amplification attack)"
                )
            }
            Error::MessageTooLarge => write!(f, "message exceeds 4 GiB limit"),
            Error::BadContainer(s) => write!(f, "bad container: {s}"),
            Error::BadFile(s) => write!(f, "bad .verit file: {s}"),
            Error::UnsupportedFileFeature(bits) => write!(
                f,
                ".verit file requires feature bits {bits:#010x} this build does not implement"
            ),
            Error::NoValidFooter => {
                write!(f, "no valid footer in .verit file (no recoverable commit)")
            }
            Error::MissingSchema(id) => write!(
                f,
                ".verit file index references schema {id:#034x}, which its schema section does not contain"
            ),
            Error::ChecksumMismatch { id, expected, found } => write!(
                f,
                "record {id} fails its checksum: file says {expected:#010x}, bytes hash to {found:#010x}"
            ),
            Error::AlreadyLocked(p) => write!(
                f,
                "another writer holds this .verit file (lock: {p}); \
                 one writer at a time, many readers"
            ),
            Error::Io(s) => write!(f, "i/o error: {s}"),
            Error::Internal(s) => write!(f, "internal error: {s}"),
        }
    }
}

impl std::error::Error for Error {}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Error {
        Error::Io(e.to_string())
    }
}

pub type Result<T> = std::result::Result<T, Error>;