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    /// Matches vanilla's `UUIDUtil.uuidFromIntArray()`.
20    fn from_int_array(arr: &[i32]) -> Option<Uuid>;
21}
22
23impl UuidExt for Uuid {
24    fn to_int_array(&self) -> [i32; 4] {
25        let bytes = self.as_bytes();
26        [
27            i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
28            i32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
29            i32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
30            i32::from_be_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
31        ]
32    }
33
34    fn from_int_array(arr: &[i32]) -> Option<Uuid> {
35        if arr.len() != 4 {
36            return None;
37        }
38        let b0 = arr[0].to_be_bytes();
39        let b1 = arr[1].to_be_bytes();
40        let b2 = arr[2].to_be_bytes();
41        let b3 = arr[3].to_be_bytes();
42        Some(Uuid::from_bytes([
43            b0[0], b0[1], b0[2], b0[3], b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3],
44            b3[0], b3[1], b3[2], b3[3],
45        ]))
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn test_uuid_roundtrip() {
55        let uuid = Uuid::new_v4();
56        let arr = uuid.to_int_array();
57        let recovered = Uuid::from_int_array(&arr).expect("Failed to recover UUID");
58        assert_eq!(uuid, recovered);
59    }
60
61    #[test]
62    fn test_uuid_from_invalid_array() {
63        assert!(Uuid::from_int_array(&[1, 2, 3]).is_none());
64        assert!(Uuid::from_int_array(&[1, 2, 3, 4, 5]).is_none());
65        assert!(Uuid::from_int_array(&[]).is_none());
66    }
67}