Skip to main content

ubiquisync_core/
uuid.rs

1//! The protocol's UUID representation: 16 raw bytes.
2//!
3//! Ubiquisync treats UUIDs as opaque 16-byte identifiers — it never inspects
4//! version or variant bits, and stores them as raw bytes (`BLOB`/`BYTEA`),
5//! not as strings or native UUID column types. Applications generate them
6//! however they like (v4, v7, ...); the protocol only requires uniqueness.
7
8/// A 16-byte UUID, stored and compared as raw bytes.
9pub type Uuid = [u8; 16];
10
11/// Validate a byte slice as a 16-byte UUID.
12pub fn try_uuid(bytes: &[u8]) -> Result<Uuid, UuidLengthError> {
13    bytes.try_into().map_err(|_| UuidLengthError(bytes.len()))
14}
15
16/// Error returned by [`try_uuid`] when the slice is not exactly 16 bytes.
17/// Carries the actual length seen.
18#[derive(Debug)]
19pub struct UuidLengthError(pub usize);
20
21impl std::fmt::Display for UuidLengthError {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "expected 16-byte UUID, got {} bytes", self.0)
24    }
25}
26
27impl std::error::Error for UuidLengthError {}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32
33    #[test]
34    fn try_uuid_accepts_exactly_16_bytes() {
35        // Goal: a 16-byte slice converts; anything else errors with the
36        // length actually seen.
37        // Given: a 16-byte slice. When: validating. Then: it round-trips.
38        assert_eq!(try_uuid(&[7u8; 16]).unwrap(), [7u8; 16]);
39
40        // Given: too-short and too-long slices. Then: the error carries
41        // the offending length.
42        assert_eq!(try_uuid(&[0u8; 15]).unwrap_err().0, 15);
43        assert_eq!(try_uuid(&[0u8; 17]).unwrap_err().0, 17);
44    }
45}