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
//! Core data structures for version control objects.
//!
//! # Purpose
//! This module aggregates the fundamental, pure-data types used to represent
//! objects in a version control system. These include [`Blob`] (file contents),
//! [`Tree`] (directory listings), [`Commit`] (history snapshots), and [`Tag`]
//! (named references to commits).
//!
//! # Design rationale
//! The types defined here are intentionally separated from the behavior traits
//! (like [`Encoder`](crate::Encoder) or [`ObjectStore`](crate::ObjectStore)).
//! This separation follows the "data vs. behavior" design pattern:
//! - The structs here are plain data carriers with private fields and getter
//! methods, ensuring immutability after construction.
//! - The traits in the rest of the crate define *how* these objects are
//! serialized, stored, and transported.
//!
//! This allows different backends (e.g., in-memory vs. disk-based) to interact
//! with the exact same logical types without coupling the data definitions to
//! I/O logic.
//!
//! # Internal mechanism
//! The module also provides a private `validate_name` helper used by the
//! constructors of name-bearing types ([`Tag`], [`TreeEntry`], [`UserID`]) to
//! enforce length and non-emptiness constraints centrally.
use crateMAX_NAME_LENGTH;
use crateVctrlError;
/// Module containing the [`Blob`](crate::Blob) type, representing raw file content.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::blob::Blob;
///
/// let blob = Blob::new(vec![0u8; 4]);
/// assert_eq!(blob.size(), 4);
/// ```
/// Module containing the [`Commit`](crate::Commit) and [`CommitMeta`](crate::CommitMeta) types, representing historical snapshots.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::commit::{Commit, CommitMeta};
///
/// let meta = CommitMeta::default();
/// assert_eq!(meta.timestamp, 0);
/// ```
/// Module containing the [`Hash`](crate::Hash) type, a 64-byte cryptographic digest.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::hash::Hash;
///
/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
/// assert!(!hash.as_bytes().is_empty());
/// ```
/// Module containing the [`Tag`](crate::Tag) type, representing a named reference.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::tag::Tag;
/// use libvctrl_handler::Hash;
///
/// let target = Hash::from_bytes(&[0u8; 64]).unwrap();
/// let tag = Tag::new("v1.0".to_string(), target, None, "Release".to_string()).unwrap();
/// assert_eq!(tag.name(), "v1.0");
/// ```
/// Module containing the [`Tree`](crate::Tree) and [`TreeEntry`](crate::TreeEntry) types, representing directory structures.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::tree::{Tree, TreeEntry};
/// use libvctrl_handler::{EntryKind, Hash};
///
/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
/// let entry = TreeEntry::new("file.txt".to_string(), EntryKind::Blob, hash).unwrap();
/// let tree = Tree::new(vec![entry]).unwrap();
/// assert_eq!(tree.entries().len(), 1);
/// ```
/// Module containing the [`UserID`](crate::UserID) type, representing identities.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::types::user_id::UserID;
///
/// let user = UserID::new("Alice".to_string(), "alice@example.com".to_string()).unwrap();
/// assert_eq!(user.name(), "Alice");
/// ```
/// Re-export of the [`Blob`](crate::Blob) type for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::Blob;
///
/// let blob = Blob::new(vec![1, 2, 3]);
/// assert_eq!(blob.size(), 3);
/// ```
pub use Blob;
/// Re-export of the [`Commit`](crate::Commit) and [`CommitMeta`](crate::CommitMeta) types for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::{Commit, CommitMeta, Hash, UserID};
///
/// let tree = Hash::from_bytes(&[0u8; 64]).unwrap();
/// let author = UserID::new("Alice".to_string(), "alice@example.com".to_string()).unwrap();
/// let committer = UserID::new("Bob".to_string(), "bob@example.com".to_string()).unwrap();
/// let meta = CommitMeta { timestamp: 100, ..Default::default() };
///
/// let commit = Commit::with_meta(tree, Vec::new(), author, committer, "msg".to_string(), meta);
/// assert_eq!(commit.timestamp(), 100);
/// ```
pub use ;
/// Re-export of the [`Hash`](crate::Hash) type for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::Hash;
///
/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
/// assert_eq!(hash.as_bytes().len(), 64);
/// ```
pub use Hash;
/// Re-export of the [`Tag`](crate::Tag) type for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::{Hash, Tag};
///
/// let target = Hash::from_bytes(&[0u8; 64]).unwrap();
/// let tag = Tag::new("v1.0".to_string(), target, None, "Release".to_string()).unwrap();
/// assert_eq!(tag.name(), "v1.0");
/// ```
pub use Tag;
/// Re-export of the [`Tree`](crate::Tree) and [`TreeEntry`](crate::TreeEntry) types for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::{EntryKind, Hash, Tree, TreeEntry};
///
/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
/// let entry = TreeEntry::new("file.txt".to_string(), EntryKind::Blob, hash).unwrap();
/// let tree = Tree::new(vec![entry]).unwrap();
/// assert_eq!(tree.entries().len(), 1);
/// ```
pub use ;
/// Re-export of the [`UserID`](crate::UserID) type for convenience.
///
/// # Examples
///
/// ```
/// use libvctrl_handler::UserID;
///
/// let user = UserID::new("Alice".to_string(), "alice@example.com".to_string()).unwrap();
/// assert_eq!(user.name(), "Alice");
/// ```
pub use UserID;
/// Validates a name string according to the system's length and emptiness rules.
///
/// # Why this exists
/// Names in a version control system (e.g., references, tree entries, user names)
/// must be non-empty and bounded in length to prevent resource exhaustion and
/// ensure compatibility with filesystem limits. This helper centralizes the
/// validation logic so that all name-bearing types apply the same rules
/// consistently.
///
/// # How it works
/// It checks if the string slice is empty. If so, it returns an
/// [`InvalidName`](crate::VctrlError::InvalidName) error. Then it checks if the byte
/// length exceeds [`MAX_NAME_LENGTH`]. If it does, it returns an
/// [`InvalidName`](crate::VctrlError::InvalidName) error containing the offending name.
///
/// # Examples
///
/// While this function is private, its behavior is observable through public
/// constructors like [`UserID::new`](crate::UserID::new):
///
/// ```
/// use libvctrl_handler::{UserID, VctrlError};
///
/// // Empty names are rejected
/// let err = UserID::new("".to_string(), "test@example.com".to_string()).unwrap_err();
/// assert!(matches!(err, VctrlError::InvalidName(_)));
///
/// // Names exceeding the max length are rejected
/// let long_name = "a".repeat(libvctrl_handler::MAX_NAME_LENGTH + 1);
/// let err = UserID::new(long_name, "test@example.com".to_string()).unwrap_err();
/// assert!(matches!(err, VctrlError::InvalidName(_)));
/// ```