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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
//! System-wide constants and limits for `libvctrl_handler`.
//!
//! # Purpose
//!
//! This module centralizes all magic numbers and structural limits used across
//! the version control system. Defining them here ensures that validation
//! logic in type constructors, encoders, and storage backends remains
//! consistent and easily tunable.
//!
//! # Design Rationale
//!
//! - **Resource Exhaustion Prevention**: Limits like [`MAX_BLOB_SIZE`] and
//! [`MAX_TREE_ENTRIES`] exist to prevent malicious or accidental resource
//! exhaustion (e.g., a 100GB blob crashing the indexer). They define safe
//! upper bounds for memory and disk usage.
//! - **Compatibility**: [`HASH_LENGTH`] is fixed to 64 bytes (512 bits),
//! aligning with SHA-512 or BLAKE3 (extended) outputs.
//! - **Wire Format Separation**: The [`entry_mode`] submodule isolates raw
//! Unix-style mode bits used in the serialized tree format from the
//! high-level [`EntryKind`](crate::EntryKind) enum.
//!
//! # How Constants Are Used
//!
//! These constants are referenced by validators such as
//! [`validate_name`](crate::types::validate_name),
//! [`validate_tree_entry_name`](crate::types::validate_tree_entry_name), and
//! by constructors like [`Hash::from_bytes`](crate::Hash::from_bytes).
//! Keeping them as plain `pub const` items makes them eligible for
//! compile-time evaluation and ensures zero runtime overhead.
//!
//! # Examples
//!
//! Importing frequently used constants from the crate root:
//!
//! ```
//! use libvctrl_handler::{
//! HASH_LENGTH,
//! MAX_BLOB_SIZE,
//! MAX_MESSAGE_LENGTH,
//! MAX_NAME_LENGTH,
//! MAX_TREE_ENTRIES,
//! };
//!
//! assert_eq!(HASH_LENGTH, 64);
//! assert_eq!(MAX_NAME_LENGTH, 255);
//! assert_eq!(MAX_BLOB_SIZE, 100 * 1024 * 1024);
//! assert_eq!(MAX_TREE_ENTRIES, 100_000);
//! assert_eq!(MAX_MESSAGE_LENGTH, 1024 * 1024);
//! ```
/// The expected length of a [`Hash`](crate::Hash) in bytes (64 bytes = 512 bits).
///
/// # Design Rationale
///
/// A 512-bit digest is chosen to provide a very low probability of collision
/// in a version control system that may store millions of objects. It aligns
/// with cryptographic hash functions such as SHA-512 or BLAKE3 configured for
/// 64-byte output.
///
/// # How It Is Used
///
/// This constant is used by [`Hash::from_bytes`](crate::Hash::from_bytes) to
/// validate slice lengths, and by [`Hash`](crate::Hash) itself as the size of
/// its internal byte array.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::HASH_LENGTH;
///
/// assert_eq!(HASH_LENGTH, 64);
/// ```
pub const HASH_LENGTH: usize = 64;
/// The maximum allowed byte length for names (e.g., branches, tags, file entries).
///
/// # Design Rationale
///
/// 255 bytes is a common filesystem limit for filenames. Enforcing this
/// ensures compatibility with most mainstream filesystems when objects are
/// checked out to disk. It also prevents pathologically long identifiers
/// that could degrade sorting or hashing performance.
///
/// # How It Is Used
///
/// This constant is checked by [`validate_name`](crate::types::validate_name)
/// and [`validate_tree_entry_name`](crate::types::validate_tree_entry_name).
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::MAX_NAME_LENGTH;
///
/// assert_eq!(MAX_NAME_LENGTH, 255_u64);
/// ```
pub const MAX_NAME_LENGTH: u64 = 255;
/// The maximum allowed size in bytes for a single [`Blob`](crate::Blob).
///
/// # Design Rationale
///
/// Set to 100 MiB to prevent out-of-memory errors when loading objects into
/// memory for hashing or encoding, while still accommodating large binary
/// assets like media files. This value balances operational safety with
/// practical use cases.
///
/// # How It Is Used
///
/// Backends that accept raw blob data should enforce this limit before
/// storing the object. This constant is a contract-level bound; concrete
/// [`ObjectStore`](crate::ObjectStore) implementations may choose stricter
/// limits if necessary.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::MAX_BLOB_SIZE;
///
/// assert_eq!(MAX_BLOB_SIZE, 100 * 1024 * 1024_u64);
/// ```
pub const MAX_BLOB_SIZE: u64 = 100 * 1024 * 1024;
/// The maximum number of entries allowed in a single [`Tree`](crate::Tree).
///
/// # Design Rationale
///
/// Set to 100,000 to prevent pathologically large directory listings that
/// would degrade traversal and encoding performance. Even with 100,000
/// entries, a tree object remains manageable in memory and can be encoded
/// efficiently.
///
/// # How It Is Used
///
/// Implementations of [`Encoder`](crate::Encoder) and
/// [`Decoder`](crate::Decoder) may consult this constant when validating
/// input or output sizes.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::MAX_TREE_ENTRIES;
///
/// assert_eq!(MAX_TREE_ENTRIES, 100_000_u64);
/// ```
pub const MAX_TREE_ENTRIES: u64 = 100_000;
/// The maximum allowed byte length for commit or tag messages.
///
/// # Design Rationale
///
/// Set to 1 MiB to allow detailed changelogs while preventing abuse via
/// gigabyte-sized text payloads. This ensures that commit and tag objects
/// remain lightweight enough for efficient storage and transport.
///
/// # How It Is Used
///
/// Constructors for [`Commit`](crate::Commit) and [`Tag`](crate::Tag)
/// may consult this limit to reject oversized messages before they enter
/// the object database.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::MAX_MESSAGE_LENGTH;
///
/// assert_eq!(MAX_MESSAGE_LENGTH, 1024 * 1024_u64);
/// ```
pub const MAX_MESSAGE_LENGTH: u64 = 1024 * 1024;
/// Standard Unix filesystem mode bits used in the serialized tree format.
///
/// # Purpose
///
/// In version control systems like Git, tree entries store raw 32-bit mode
/// integers to represent file types and permissions. This module provides
/// those exact constants.
///
/// # Design Rationale
///
/// These constants are separated into their own module to keep the global
/// namespace clean. They represent the *wire format* and storage format,
/// distinct from the logical [`EntryKind`](crate::EntryKind) enum used in
/// Rust memory. An encoder or decoder implementation will use these when
/// translating between [`TreeEntry`](crate::TreeEntry) and raw bytes.
///
/// # Internal Mechanism
///
/// The values are standard Unix mode bits expressed in octal. They are
/// intentionally stored as `u32` because the serialized tree format uses a
/// fixed-width 32-bit integer field for modes.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::constants::entry_mode;
///
/// assert_eq!(entry_mode::BLOB, 0o100_644);
/// assert_eq!(entry_mode::TREE, 0o040_000);
/// ```