1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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>;