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
//! Binary large object type for the `libvctrl_handler` version control
//! contracts.
//!
//! # Purpose
//! A [`Blob`](crate::Blob) is the fundamental content-addressed payload in a
//! version control system. It stores the raw bytes of a file's contents at a
//! given point in time, with no name, no filesystem mode, and no parent
//! relationship attached. Those concerns are owned by
//! [`TreeEntry`](crate::TreeEntry) and [`Tree`](crate::Tree) respectively,
//! which reference a blob indirectly through its [`Hash`](crate::Hash).
//!
//! # Design rationale
//! The inner `Vec<u8>` is intentionally kept private. Exposing the field
//! directly would allow callers to mutate the bytes after construction,
//! breaking the invariant that a blob's content is immutable for the
//! lifetime of its owning [`Hash`](crate::Hash). Every accessor therefore
//! returns either a shared reference (`&[u8]`) or a copied scalar, so the
//! type is effectively a frozen handle around its data.
//!
//! [`Blob::new`](crate::Blob::new) is a `const fn` for forward compatibility
//! with `const`-context construction. `Vec<u8>` is not yet
//! `const`-constructible on stable Rust, so today the practical benefit is
//! API uniformity with the other `const fn` accessors; once `const` heap
//! allocation stabilizes this entry point will already support zero-cost
//! compile-time blobs without a breaking change.
//!
//! Size validation against
//! [`MAX_BLOB_SIZE`](crate::MAX_BLOB_SIZE) is deliberately **not** performed
//! inside [`Blob::new`](crate::Blob::new). The [`Blob`](crate::Blob) type is
//! a pure data carrier; enforcing storage limits is the responsibility of
//! the [`Encoder`](crate::Encoder) or [`ObjectStore`](crate::ObjectStore)
//! implementation that persists the blob. This keeps construction cheap in
//! hot paths (for example, when streaming content through a
//! [`Hasher`](crate::Hasher)) where the limit does not yet apply.
//!
//! # Internal mechanism
//! [`Blob`](crate::Blob) is a thin wrapper around `Vec<u8>`. There is no
//! allocation on read: [`data`](crate::Blob::data) returns a borrowed slice
//! into the underlying buffer, and [`size`](crate::Blob::size) /
//! [`is_empty`](crate::Blob::is_empty) read the vector's length field
//! directly without traversing the contents.
/// An immutable binary large object representing raw file content.
///
/// # Purpose
/// A `Blob` holds the bytes of a tracked file at a single point in time. It
/// carries no metadata about the file's path or permissions; that
/// information lives in the enclosing [`Tree`](crate::Tree) via
/// [`TreeEntry`](crate::TreeEntry).
///
/// # Design rationale
/// The wrapped `Vec<u8>` is private to preserve the immutability invariant
/// that a blob's content must not change after the blob's
/// [`Hash`](crate::Hash) has been computed. Mutation would silently
/// invalidate every [`Hash`](crate::Hash) and [`Tree`](crate::Tree) that
/// references this blob, so the API exposes only shared (`&[u8]`) accessors.
///
/// Construction does not enforce
/// [`MAX_BLOB_SIZE`](crate::MAX_BLOB_SIZE); that limit is enforced by the
/// storage layer (see [`ObjectStore`](crate::ObjectStore) and
/// [`Encoder`](crate::Encoder)) when the blob is actually persisted. This
/// keeps [`Blob::new`](crate::Blob::new) a zero-cost move in hot paths such
/// as hashing.
///
/// # Internal mechanism
/// The struct is a single-field wrapper around `Vec<u8>`. All accessors are
/// either `O(1)` length reads or borrowed slice views; none allocate.
///
/// # Examples
///
/// Constructing a blob from a byte vector and inspecting it:
///
/// ```
/// use libvctrl_handler::Blob;
///
/// let blob = Blob::new(b"hello, world\n".to_vec());
/// assert_eq!(blob.size(), 13);
/// assert_eq!(blob.data(), b"hello, world\n");
/// assert!(!blob.is_empty());
/// ```
///
/// Cloning a blob copies the underlying buffer:
///
/// ```
/// use libvctrl_handler::Blob;
///
/// let original = Blob::new(vec![0u8; 32]);
/// let clone = original.clone();
/// assert_eq!(original, clone);
/// ```