Skip to main content

libvctrl/
lib.rs

1//! # `libvctrl` - The Ultimate Version Control SDK
2//!
3//! **The all-in-one Version Control System (VCS) Software Development Kit.**
4//!
5//! This crate provides a unified, batteries-included interface for building
6//! custom version control systems. It aggregates three foundational layers
7//! into a single coherent namespace, allowing developers to bootstrap a fully
8//! functional VCS backend without stitching multiple crates together manually.
9//!
10//! ## Architecture
11//!
12//! The SDK is composed of three re-exported sub-crates:
13//!
14//! 1. **Contracts** ([`handler`]): Core data types ([`Blob`], [`Commit`], [`Tree`]),
15//!    behavior traits ([`ObjectStore`], [`Encoder`]), and error definitions
16//!    ([`VctrlError`]). These are pure, dependency-light definitions.
17//! 2. **Implementations** ([`mod@reference`]): Ready-to-use backends including an
18//!    in-memory store ([`MemoryStore`]), binary encoder/decoder
19//!    ([`BinaryEncoder`], [`BinaryDecoder`]), SHA-512 hasher adapter
20//!    ([`Sha512Hasher`]), and ergonomic object builders ([`TreeBuilder`]).
21//! 3. **Cryptography** ([`crypto`]): A pure-Rust, `no_std`-compatible SHA-512,
22//!    HMAC-SHA-512, and HKDF-SHA-512 implementation.
23//!
24//! ## Design Rationale
25//!
26//! - **Facade Pattern**: By re-exporting the essential types at the root level,
27//!   users can simply `use libvctrl::*;` without worrying about deep module
28//!   paths. Complex internal dependencies are abstracted away.
29//! - **Namespace Isolation**: To prevent name clashes (e.g., between the VCS
30//!   [`struct@Hash`] type and the cryptographic [`crypto::Hash`]), the low-level
31//!   cryptographic primitives are grouped under the [`crypto`] module.
32//! - **Robustness**: All underlying crates enforce `#![forbid(unsafe_code)]`
33//!   and strict Clippy lints, guaranteeing memory safety and high code quality
34//!   across the entire stack.
35//!
36//! # Examples
37//!
38//! Building a tree, encoding it, hashing it, and storing it:
39//!
40//! ```
41//! use libvctrl::{
42//!     EntryKind, Hash, TreeBuilder, TreeEntryBuilder, BinaryEncoder, Sha512Hasher,
43//!     MemoryStore, Encoder, Hasher, ObjectStore, VctrlError,
44//! };
45//! use std::io::Read;
46//!
47//! // 1. Build a Tree containing a single file entry
48//! let blob_hash = Hash::from_bytes(&[0xAB; 64])?;
49//! let entry = TreeEntryBuilder::new("file.txt".to_string(), EntryKind::Blob, blob_hash).build()?;
50//! let tree = TreeBuilder::new().entry(entry).build()?;
51//!
52//! // 2. Encode the Tree into binary format
53//! let encoder = BinaryEncoder;
54//! let encoded_bytes = encoder.encode_tree(&tree)?;
55//!
56//! // 3. Hash the encoded bytes to get an address
57//! let hasher = Sha512Hasher;
58//! let tree_hash = hasher.hash(&encoded_bytes)?;
59//!
60//! // 4. Store the encoded object in memory
61//! let mut store = MemoryStore::new();
62//! store.put(&tree_hash, &encoded_bytes)?;
63//!
64//! // 5. Retrieve and verify the object
65//! assert!(store.exists(&tree_hash)?);
66//! let mut reader = store.get(&tree_hash)?;
67//! let mut buf = Vec::new();
68//! reader.read_to_end(&mut buf).map_err(VctrlError::IoError)?;
69//! assert_eq!(buf, encoded_bytes);
70//!
71//! # Ok::<(), VctrlError>(())
72//! ```
73
74#![forbid(unsafe_code)]
75#![deny(
76    clippy::all,
77    clippy::pedantic,
78    clippy::nursery,
79    clippy::cargo,
80    missing_docs,
81    rust_2018_idioms,
82    unreachable_pub,
83    unused_qualifications
84)]
85
86// ---------------------------------------------------------------------------
87// Sub-crate Re-exports
88// ---------------------------------------------------------------------------
89
90/// The core contracts (types, traits, errors) for the version control system.
91///
92/// # Purpose
93/// This module exposes the pure data structures and behavior definitions
94/// from `libvctrl_handler`. It acts as the foundational layer of the SDK,
95/// defining *what* a version control object is and *how* it should behave,
96/// without providing any actual storage or serialization logic.
97///
98/// # Design Rationale
99/// Exposing this as a sub-module allows users to explicitly depend on the
100/// contracts if they only need the type definitions (e.g., for a frontend
101/// that doesn't implement storage), while still being part of the unified SDK.
102///
103/// # Examples
104///
105/// Accessing the `Blob` type via the `handler` module:
106///
107/// ```
108/// use libvctrl::handler::Blob;
109///
110/// let blob = Blob::new(b"hello".to_vec());
111/// assert_eq!(blob.size(), 5);
112/// ```
113pub use libvctrl_handler as handler;
114
115/// The reference implementations (in-memory store, binary codec) for the VCS.
116///
117/// # Purpose
118/// This module exposes the ready-to-use backends from `libvctrl_core`. It
119/// provides concrete implementations for all the traits defined in the
120/// [`handler`] module.
121///
122/// # Design Rationale
123/// It serves as the "batteries-included" layer. Users can use these
124/// implementations directly for rapid prototyping or testing, or use them as
125/// reference examples when building custom backends (e.g., a disk-based store).
126///
127/// # Examples
128///
129/// Using the `MemoryStore` via the `reference` module:
130///
131/// ```
132/// use libvctrl::MemoryStore;
133/// use libvctrl::handler::{Hash, ObjectStore};
134///
135/// let mut store = MemoryStore::new();
136/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
137/// store.put(&hash, b"data").unwrap();
138/// assert!(store.exists(&hash).unwrap());
139/// ```
140pub use libvctrl_core as reference;
141
142/// The cryptographic primitives (SHA-512, HMAC, HKDF).
143///
144/// # Purpose
145/// This module exposes the pure-Rust cryptographic implementations from
146/// `libvctrl_sha512`.
147///
148/// # Design Rationale
149/// It is kept as a separate module to avoid naming conflicts with the VCS-level
150/// [`struct@Hash`] type. The VCS `Hash` is a 64-byte array wrapper, whereas
151/// [`crypto::Hash`] is the actual SHA-512 hasher state machine.
152///
153/// # Examples
154///
155/// Computing a SHA-512 hash:
156///
157/// ```
158/// use libvctrl::crypto::Hash as Sha512Hash;
159///
160/// let digest = Sha512Hash::hash(b"hello world");
161/// assert_eq!(digest.len(), 64);
162/// ```
163pub use libvctrl_sha512 as crypto;
164
165// ---------------------------------------------------------------------------
166// Root-level Re-exports (Contracts)
167// ---------------------------------------------------------------------------
168
169/// System-wide constants and structural limits.
170///
171/// # Purpose
172/// Centralizes all magic numbers and structural limits used across the version
173/// control system.
174///
175/// # Design Rationale
176/// Defining them in a single module ensures that validation logic in type
177/// constructors, encoders, and storage backends remains consistent and easily
178/// tunable.
179///
180/// # Examples
181///
182/// ```
183/// use libvctrl::constants::HASH_LENGTH;
184/// assert_eq!(HASH_LENGTH, 64);
185/// ```
186pub use handler::constants;
187
188/// Logical object type enumerations (e.g., [`EntryKind`]).
189///
190/// # Purpose
191/// Distinguishes between files and directories at a high level, decoupled from
192/// raw filesystem mode bits.
193///
194/// # Examples
195///
196/// ```
197/// use libvctrl::enums::EntryKind;
198/// assert_ne!(EntryKind::Blob, EntryKind::Tree);
199/// ```
200pub use handler::enums;
201
202/// Unified error handling ([`VctrlError`]).
203///
204/// # Purpose
205/// The single error type returned by all fallible operations in the SDK.
206///
207/// # Examples
208///
209/// ```
210/// use libvctrl::errors::VctrlError;
211/// let err = VctrlError::Other("fail".to_string());
212/// assert_eq!(err.to_string(), "fail");
213/// ```
214pub use handler::errors;
215
216/// Helper macros for ergonomic error construction.
217///
218/// # Purpose
219/// Provides macros like [`vctrl_error_other!`] to simplify creating formatted
220/// error messages. Note that the macro is exported at the crate root,
221/// so you should import it as `use libvctrl::vctrl_error_other`.
222///
223/// # Examples
224///
225/// ```
226/// use libvctrl::VctrlError;
227/// use libvctrl_handler::vctrl_error_other;
228///
229/// let err: VctrlError = vctrl_error_other!("code {}", 500);
230/// assert_eq!(err.to_string(), "code 500");
231/// ```
232pub use handler::macros;
233
234/// Core behavior contracts (traits).
235///
236/// # Purpose
237/// Defines the interfaces (e.g., [`ObjectStore`], [`Encoder`]) that any
238/// concrete backend must implement.
239///
240/// # Examples
241///
242/// ```
243/// use libvctrl::traits::Hasher;
244/// use libvctrl::Hash;
245/// use libvctrl::VctrlError;
246///
247/// struct DummyHasher;
248/// impl Hasher for DummyHasher {
249///     fn hash(&self, _data: &[u8]) -> Result<Hash, VctrlError> {
250///         Ok(Hash::from_bytes(&[0u8; 64]).unwrap())
251///     }
252/// }
253/// ```
254pub use handler::traits;
255
256/// Core data structures representing version control objects.
257///
258/// # Purpose
259/// Contains the immutable domain models: [`Blob`], [`Tree`], [`Commit`], [`Tag`],
260/// and supporting types like [`struct@Hash`] and [`UserID`].
261///
262/// # Examples
263///
264/// ```
265/// use libvctrl::types::Blob;
266/// let blob = Blob::new(vec![1, 2, 3]);
267/// assert_eq!(blob.size(), 3);
268/// ```
269pub use handler::types;
270
271/// Re-exports of fundamental system constants.
272///
273/// # Purpose
274/// These constants (like [`HASH_LENGTH`] and [`MAX_BLOB_SIZE`]) are used so
275/// frequently that they are re-exported at the crate root. This saves the caller
276/// from having to write `libvctrl::constants::HASH_LENGTH` everywhere.
277///
278/// # Examples
279///
280/// ```
281/// use libvctrl::HASH_LENGTH;
282/// assert_eq!(HASH_LENGTH, 64);
283/// ```
284pub use handler::{
285    HASH_LENGTH, MAX_BLOB_SIZE, MAX_MESSAGE_LENGTH, MAX_NAME_LENGTH, MAX_TREE_ENTRIES,
286};
287
288/// Re-export of the logical entry kind enum.
289///
290/// # Purpose
291/// Used in [`TreeEntry`] to distinguish between a file ([`Blob`]) and a
292/// subdirectory ([`Tree`]).
293///
294/// # Examples
295///
296/// ```
297/// use libvctrl::EntryKind;
298/// assert_eq!(EntryKind::Blob, EntryKind::Blob);
299/// ```
300pub use handler::EntryKind;
301
302/// Re-export of the unified error type.
303///
304/// # Purpose
305/// Every fallible operation in this SDK returns `Result<_, VctrlError>`.
306/// Making it available at the root streamlines error handling.
307///
308/// # Examples
309///
310/// ```
311/// use libvctrl::VctrlError;
312/// let err = VctrlError::Other("test".to_string());
313/// assert!(err.to_string().contains("test"));
314/// ```
315pub use handler::VctrlError;
316
317/// Re-exports of the core behavior traits.
318///
319/// # Purpose
320/// Provides direct access to the interfaces that define VCS behavior, such as
321/// [`ObjectStore`] for persistence and [`Encoder`] for serialization.
322///
323/// # Examples
324///
325/// ```
326/// use libvctrl::{Hasher, Hash, VctrlError};
327///
328/// struct MyHasher;
329/// impl Hasher for MyHasher {
330///     fn hash(&self, _data: &[u8]) -> Result<Hash, VctrlError> {
331///         Ok(Hash::from_bytes(&[0u8; 64]).unwrap())
332///     }
333/// }
334/// ```
335pub use handler::{Decoder, Encoder, Hasher, ObjectStore, RefStore, Signer, Transport, Verifier};
336
337/// Re-exports of the core data structures.
338///
339/// # Purpose
340/// All version-control objects ([`Blob`], [`Tree`], [`Commit`], [`Tag`]) and
341/// their supporting types are available directly from the crate root for
342/// ergonomic access.
343///
344/// # Examples
345///
346/// ```
347/// use libvctrl::Blob;
348/// let blob = Blob::new(vec![1, 2, 3]);
349/// assert_eq!(blob.size(), 3);
350/// ```
351pub use handler::{Blob, Commit, CommitMeta, Hash, Tag, Tree, TreeEntry, UserID};
352
353// ---------------------------------------------------------------------------
354// Root-level Re-exports (Reference Implementations)
355// ---------------------------------------------------------------------------
356
357/// Re-exports of binary serialization modules.
358///
359/// # Purpose
360/// Provides the [`BinaryEncoder`] and [`BinaryDecoder`] which translate
361/// in-memory objects into a compact, deterministic byte format.
362///
363/// # Examples
364///
365/// ```
366/// use libvctrl::codec::{BinaryEncoder, BinaryDecoder};
367/// use libvctrl::{Blob, Encoder, Decoder};
368///
369/// let blob = Blob::new(b"data".to_vec());
370/// let bytes = BinaryEncoder.encode_blob(&blob).unwrap();
371/// let decoded = BinaryDecoder.decode_blob(&bytes).unwrap();
372/// assert_eq!(decoded, blob);
373/// ```
374pub use reference::codec;
375
376/// Re-exports of object builder modules.
377///
378/// # Purpose
379/// Provides fluent APIs like [`CommitBuilder`] to ergonomically assemble
380/// complex objects step-by-step.
381///
382/// # Examples
383///
384/// ```
385/// use libvctrl::object::BlobBuilder;
386///
387/// let blob = BlobBuilder::new()
388///     .with_data(b"hello".to_vec())
389///     .build();
390/// assert_eq!(blob.size(), 5);
391/// ```
392pub use reference::object;
393
394/// Re-exports of in-memory storage modules.
395///
396/// # Purpose
397/// Provides concrete [`ObjectStore`] and [`RefStore`] implementations,
398/// such as [`MemoryStore`], for persisting data in RAM.
399///
400/// # Examples
401///
402/// ```
403/// use libvctrl::store::MemoryStore;
404/// use libvctrl::{Hash, ObjectStore};
405///
406/// let mut store = MemoryStore::new();
407/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
408/// store.put(&hash, b"data").unwrap();
409/// assert!(store.exists(&hash).unwrap());
410/// ```
411pub use reference::store;
412
413/// Re-exports of validation utility modules.
414///
415/// # Purpose
416/// Provides helper functions to validate raw inputs (like names and hashes)
417/// before they are turned into strongly-typed objects.
418///
419/// # Examples
420///
421/// ```
422/// use libvctrl::validate::name::validate_name;
423/// assert!(validate_name("valid_name").is_ok());
424/// assert!(validate_name("../invalid").is_err());
425/// ```
426pub use reference::validate;
427
428/// Re-export of the binary decoder struct.
429///
430/// # Purpose
431/// Implements the [`Decoder`] trait to parse the binary representation
432/// generated by [`BinaryEncoder`] back into in-memory objects.
433///
434/// # Design Rationale
435/// It is re-exported at the root to provide immediate access to the standard
436/// wire format decoder without requiring users to navigate deep module paths.
437///
438/// # Examples
439///
440/// ```
441/// use libvctrl::{BinaryDecoder, BinaryEncoder, Blob, Decoder, Encoder};
442///
443/// let blob = Blob::new(b"data".to_vec());
444/// let bytes = BinaryEncoder.encode_blob(&blob).unwrap();
445/// let decoded = BinaryDecoder.decode_blob(&bytes).unwrap();
446/// assert_eq!(decoded, blob);
447/// ```
448pub use reference::codec::BinaryDecoder;
449
450/// Re-export of the binary encoder struct.
451///
452/// # Purpose
453/// Implements the [`Encoder`] trait to convert in-memory objects into a
454/// deterministic binary representation suitable for storage.
455///
456/// # Examples
457///
458/// ```
459/// use libvctrl::{BinaryEncoder, Blob, Encoder};
460///
461/// let encoder = BinaryEncoder;
462/// let blob = Blob::new(vec![1, 2, 3]);
463/// assert!(encoder.encode_blob(&blob).is_ok());
464/// ```
465pub use reference::codec::BinaryEncoder;
466
467/// Re-export of the SHA-512 hasher adapter.
468///
469/// # Purpose
470/// Bridges the pure-Rust `libvctrl_sha512` crate with the core [`Hasher`]
471/// trait, allowing it to be used transparently by the VCS to generate
472/// content-addressable identifiers.
473///
474/// # Examples
475///
476/// ```
477/// use libvctrl::{Hasher, Sha512Hasher};
478///
479/// let hasher = Sha512Hasher;
480/// let hash = hasher.hash(b"data").unwrap();
481/// assert_eq!(hash.as_bytes().len(), 64);
482/// ```
483pub use reference::hash::Sha512Hasher;
484
485/// Re-export of the `Blob` builder.
486///
487/// # Purpose
488/// Provides a fluent interface for assembling a [`Blob`]'s data before
489/// finalizing it into an immutable object.
490///
491/// # Examples
492///
493/// ```
494/// use libvctrl::BlobBuilder;
495///
496/// let blob = BlobBuilder::default().build();
497/// assert!(blob.is_empty());
498/// ```
499pub use reference::object::BlobBuilder;
500
501/// Re-export of the `Commit` builder.
502///
503/// # Purpose
504/// Solves the "telescoping constructor" problem for [`Commit`] objects by
505/// allowing step-by-step configuration of required and optional fields.
506///
507/// # Examples
508///
509/// ```
510/// use libvctrl::{CommitBuilder, Hash, UserID};
511///
512/// let tree = Hash::from_bytes(&[0u8; 64]).unwrap();
513/// let user = UserID::new("A".to_string(), "a@a.com".to_string()).unwrap();
514///
515/// let commit = CommitBuilder::new()
516///     .tree(tree)
517///     .author(user.clone())
518///     .committer(user)
519///     .message("msg")
520///     .build()
521///     .unwrap();
522///
523/// assert_eq!(commit.parents().len(), 0);
524/// ```
525pub use reference::object::CommitBuilder;
526
527/// Re-export of the `Tag` builder.
528///
529/// # Purpose
530/// Provides a fluent API for constructing [`Tag`] objects, handling the
531/// combination of required (`name`, `target`) and optional (`tagger`, `meta`)
532/// fields.
533///
534/// # Examples
535///
536/// ```
537/// use libvctrl::{Hash, TagBuilder};
538///
539/// let target = Hash::from_bytes(&[0u8; 64]).unwrap();
540/// let tag = TagBuilder::new()
541///     .name("v2.0")
542///     .target(target)
543///     .build()
544///     .unwrap();
545///
546/// assert_eq!(tag.name(), "v2.0");
547/// ```
548pub use reference::object::TagBuilder;
549
550/// Re-export of the `Tree` builder.
551///
552/// # Purpose
553/// Accumulates [`TreeEntry`] objects and finalizes them into an immutable
554/// [`Tree`], enforcing structural invariants like sorted entries.
555///
556/// # Examples
557///
558/// ```
559/// use libvctrl::{EntryKind, Hash, TreeBuilder};
560///
561/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
562/// let tree = TreeBuilder::new()
563///     .add_entry("a.txt".to_string(), EntryKind::Blob, hash)
564///     .unwrap()
565///     .build()
566///     .unwrap();
567///
568/// assert_eq!(tree.entries().len(), 1);
569/// ```
570pub use reference::object::TreeBuilder;
571
572/// Re-export of the `TreeEntry` builder.
573///
574/// # Purpose
575/// Assembles a tree entry's data (name, kind, hash) before finalizing it,
576/// deferring name validation to the `build()` step.
577///
578/// # Examples
579///
580/// ```
581/// use libvctrl::{EntryKind, Hash, TreeEntryBuilder};
582///
583/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
584/// let entry = TreeEntryBuilder::new("file.txt".to_string(), EntryKind::Blob, hash)
585///     .build()
586///     .unwrap();
587///
588/// assert_eq!(entry.name(), "file.txt");
589/// ```
590pub use reference::object::TreeEntryBuilder;
591
592/// Re-export of the in-memory reference store.
593///
594/// # Purpose
595/// Maps human-readable reference names (e.g., "HEAD") to cryptographic
596/// [`struct@Hash`]es in RAM. Ideal for testing and ephemeral operations.
597///
598/// # Examples
599///
600/// ```
601/// use libvctrl::{Hash, MemoryRefStore, RefStore};
602///
603/// let mut store = MemoryRefStore::new();
604/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
605/// store.set_ref("HEAD", &hash).unwrap();
606/// assert!(store.get_ref("HEAD").is_ok());
607/// ```
608pub use reference::store::MemoryRefStore;
609
610/// Re-export of the in-memory object store.
611///
612/// # Purpose
613/// Stores raw, serialized version control objects in a `HashMap` residing in
614/// RAM, addressable by their [`struct@Hash`].
615///
616/// # Examples
617///
618/// ```
619/// use libvctrl::{Hash, MemoryStore, ObjectStore};
620/// use std::io::Read;
621///
622/// let mut store = MemoryStore::new();
623/// let hash = Hash::from_bytes(&[0u8; 64]).unwrap();
624/// store.put(&hash, b"data").unwrap();
625///
626/// let mut buf = Vec::new();
627/// store.get(&hash).unwrap().read_to_end(&mut buf).unwrap();
628/// assert_eq!(buf, b"data");
629/// ```
630pub use reference::store::MemoryStore;
631
632/// Re-export of the hash validation utility.
633///
634/// # Purpose
635/// Ensures that byte slices intended to represent hashes meet the strict
636/// length requirements (64 bytes) before being converted to the [`struct@Hash`] type.
637///
638/// # Examples
639///
640/// ```
641/// use libvctrl::validate_hash_bytes;
642/// use libvctrl::handler::HASH_LENGTH;
643///
644/// let valid_bytes = [0u8; HASH_LENGTH];
645/// assert!(validate_hash_bytes(&valid_bytes).is_ok());
646/// ```
647pub use reference::validate::hash::validate_hash_bytes;
648
649/// Re-export of the name validation utility.
650///
651/// # Purpose
652/// Acts as a gatekeeper for strings used as identifiers (e.g., branches, tags),
653/// ensuring they are non-empty, within length limits, and free of path
654/// traversal characters (`/`, `.`, `..`).
655///
656/// # Examples
657///
658/// ```
659/// use libvctrl::validate_name;
660///
661/// assert!(validate_name("valid_name").is_ok());
662/// assert!(validate_name("../invalid").is_err());
663/// ```
664pub use reference::validate::name::validate_name;