Skip to main content

steel_utils/
uuid_ext.rs

1//! UUID extension trait for Minecraft-compatible NBT serialization.
2//!
3//! Vanilla Minecraft stores UUIDs as int arrays with 4 elements,
4//! where each i32 represents 4 bytes of the UUID in big-endian order.
5
6use uuid::Uuid;
7
8/// Extension trait for UUID to support Minecraft's NBT int array format.
9pub trait UuidExt {
10    /// Converts a UUID to an int array for NBT storage (vanilla format).
11    ///
12    /// The UUID is split into 4 big-endian i32 values, matching
13    /// vanilla's `UUIDUtil.uuidToIntArray()`.
14    fn to_int_array(&self) -> [i32; 4];
15
16    /// Parses a UUID from an int array (vanilla NBT format).
17    ///
18    /// Returns `None` if the slice doesn't have exactly 4 elements.
19    fn from_int_array(arr: &[i32]) -> Option<Uuid>;
20}
21
22impl UuidExt for Uuid {
23    fn to_int_array(&self) -> [i32; 4] {
24        let bytes = self.as_bytes();
25        [
26            i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
27            i32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
28            i32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
29            i32::from_be_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
30        ]
31    }
32
33    fn from_int_array(arr: &[i32]) -> Option<Uuid> {
34        if arr.len() != 4 {
35            return None;
36        }
37        let b0 = arr[0].to_be_bytes();
38        let b1 = arr[1].to_be_bytes();
39        let b2 = arr[2].to_be_bytes();
40        let b3 = arr[3].to_be_bytes();
41        Some(Uuid::from_bytes([
42            b0[0], b0[1], b0[2], b0[3], b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3],
43            b3[0], b3[1], b3[2], b3[3],
44        ]))
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_uuid_roundtrip() {
54        let uuid = Uuid::new_v4();
55        let arr = uuid.to_int_array();
56        let recovered = Uuid::from_int_array(&arr).expect("Failed to recover UUID");
57        assert_eq!(uuid, recovered);
58    }
59
60    #[test]
61    fn test_uuid_from_invalid_array() {
62        assert!(Uuid::from_int_array(&[1, 2, 3]).is_none());
63        assert!(Uuid::from_int_array(&[1, 2, 3, 4, 5]).is_none());
64        assert!(Uuid::from_int_array(&[]).is_none());
65    }
66}