1 //! A UUID (See Core Spec 5.3 Vol 1E 2.9.1. Basic Types) 2 3 use crate::packets::{ 4 ParseError, Uuid128Builder, Uuid128View, Uuid16Builder, Uuid16View, UuidBuilder, UuidView, 5 }; 6 7 /// A UUID (See Core Spec 5.3 Vol 1E 2.9.1. Basic Types) 8 /// 9 /// Note that the underlying storage is BIG-ENDIAN! But this should be viewed 10 /// as an implementation detail for C++ interop ONLY - all converters etc. 11 /// should act as though the backing storage is LITTLE-ENDIAN. 12 #[derive(PartialEq, Eq, Clone, Copy, Debug)] 13 #[repr(transparent)] 14 pub struct Uuid([u8; 16]); 15 16 const BASE_UUID: u128 = 0x00000000_0000_1000_8000_0080_5F9B_34FB; 17 18 impl Uuid { 19 /// Constructor from a u32. new(val: u32) -> Self20 pub const fn new(val: u32) -> Self { 21 Self((BASE_UUID + ((val as u128) << 96)).to_be_bytes()) 22 } 23 new_from_le_bytes(mut bytes: [u8; 16]) -> Self24 fn new_from_le_bytes(mut bytes: [u8; 16]) -> Self { 25 bytes.reverse(); 26 Self(bytes) 27 } 28 le_bytes(&self) -> [u8; 16]29 fn le_bytes(&self) -> [u8; 16] { 30 let mut out = self.0; 31 out.reverse(); 32 out 33 } 34 } 35 36 impl TryFrom<UuidView<'_>> for Uuid { 37 type Error = ParseError; 38 try_from(value: UuidView<'_>) -> Result<Self, ParseError>39 fn try_from(value: UuidView<'_>) -> Result<Self, ParseError> { 40 let bytes = value.get_data_iter().collect::<Vec<_>>(); 41 Ok(match bytes.len() { 42 2 => Self::new(u16::from_le_bytes([bytes[0], bytes[1]]) as u32), 43 4 => Self::new(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])), 44 // TODO(aryarahul) - should we handle >16 byte Uuids and drop extra bytes? 45 _ => Self::new_from_le_bytes( 46 bytes.try_into().map_err(|_| ParseError::OutOfBoundsAccess)?, 47 ), 48 }) 49 } 50 } 51 52 impl From<Uuid16View<'_>> for Uuid { from(uuid: Uuid16View) -> Self53 fn from(uuid: Uuid16View) -> Self { 54 Self::new(uuid.get_data() as u32) 55 } 56 } 57 58 impl From<Uuid128View<'_>> for Uuid { from(uuid: Uuid128View) -> Self59 fn from(uuid: Uuid128View) -> Self { 60 Self::new_from_le_bytes( 61 uuid.get_data_iter() 62 .collect::<Vec<_>>() 63 .try_into() 64 .expect("Uuid128View MUST have exactly 16 bytes"), 65 ) 66 } 67 } 68 69 impl From<Uuid> for UuidBuilder { from(value: Uuid) -> Self70 fn from(value: Uuid) -> Self { 71 // TODO(aryarahul): compress to UUID-16 if possible 72 UuidBuilder { data: value.le_bytes().into_iter().collect() } 73 } 74 } 75 76 impl TryFrom<Uuid> for Uuid16Builder { 77 type Error = Uuid; 78 try_from(value: Uuid) -> Result<Self, Self::Error>79 fn try_from(value: Uuid) -> Result<Self, Self::Error> { 80 let backing = u128::from_be_bytes(value.0); 81 if backing & ((1u128 << 96) - 1) == BASE_UUID { 82 if let Ok(data) = u16::try_from(backing >> 96) { 83 return Ok(Uuid16Builder { data }); 84 } 85 } 86 Err(value) 87 } 88 } 89 90 impl From<Uuid> for Uuid128Builder { from(value: Uuid) -> Self91 fn from(value: Uuid) -> Self { 92 Uuid128Builder { data: value.le_bytes().to_vec().into() } 93 } 94 } 95 96 #[cfg(test)] 97 mod test { 98 use crate::utils::packet::build_view_or_crash; 99 100 use super::*; 101 102 #[test] test_uuid16_builder_successful()103 fn test_uuid16_builder_successful() { 104 let uuid = Uuid::new(0x0102); 105 let builder: Uuid16Builder = uuid.try_into().unwrap(); 106 assert_eq!(builder.data, 0x0102); 107 } 108 109 #[test] test_uuid16_builder_fail_nonzero_trailing_bytes()110 fn test_uuid16_builder_fail_nonzero_trailing_bytes() { 111 let uuid = Uuid::new(0x01020304); 112 let res: Result<Uuid16Builder, _> = uuid.try_into(); 113 assert!(res.is_err()); 114 } 115 116 #[test] test_uuid16_builder_fail_invalid_prefix()117 fn test_uuid16_builder_fail_invalid_prefix() { 118 let mut uuid = Uuid::new(0x0102); 119 uuid.0[0] = 1; 120 121 let res: Result<Uuid16Builder, _> = uuid.try_into(); 122 assert!(res.is_err()); 123 } 124 125 #[test] test_uuid128_builder()126 fn test_uuid128_builder() { 127 let uuid = Uuid::new(0x01020304); 128 let builder: Uuid128Builder = uuid.into(); 129 assert_eq!(builder.data[..12], BASE_UUID.to_le_bytes()[..12]); 130 assert_eq!(builder.data[12..], [4, 3, 2, 1]); 131 } 132 133 #[test] test_uuid_builder()134 fn test_uuid_builder() { 135 let uuid = Uuid::new(0x01020304); 136 let builder: UuidBuilder = uuid.into(); 137 assert_eq!(builder.data[..12], BASE_UUID.to_le_bytes()[..12]); 138 assert_eq!(builder.data[12..], [4, 3, 2, 1]); 139 } 140 141 #[test] test_uuid_from_16_fixed_view()142 fn test_uuid_from_16_fixed_view() { 143 let expected = Uuid::new(0x0102); 144 let actual: Uuid = build_view_or_crash(Uuid16Builder { data: 0x0102 }).view().into(); 145 assert_eq!(expected, actual); 146 } 147 148 #[test] test_uuid_from_128_fixed_view()149 fn test_uuid_from_128_fixed_view() { 150 let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 151 let expected = Uuid::new_from_le_bytes(data); 152 let actual: Uuid = build_view_or_crash(Uuid128Builder { data: data.into() }).view().into(); 153 assert_eq!(expected, actual); 154 } 155 156 #[test] test_uuid_from_16_view()157 fn test_uuid_from_16_view() { 158 let expected = Uuid::new(0x0102); 159 let actual: Uuid = 160 build_view_or_crash(UuidBuilder { data: [2, 1].into() }).view().try_into().unwrap(); 161 assert_eq!(expected, actual); 162 } 163 164 #[test] test_uuid_from_32_view()165 fn test_uuid_from_32_view() { 166 let expected = Uuid::new(0x01020304); 167 let actual: Uuid = build_view_or_crash(UuidBuilder { data: [4, 3, 2, 1].into() }) 168 .view() 169 .try_into() 170 .unwrap(); 171 assert_eq!(expected, actual); 172 } 173 174 #[test] test_uuid_from_128_view()175 fn test_uuid_from_128_view() { 176 let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 177 let expected = Uuid::new_from_le_bytes(data); 178 let actual: Uuid = 179 build_view_or_crash(UuidBuilder { data: data.into() }).view().try_into().unwrap(); 180 assert_eq!(expected, actual); 181 } 182 183 #[test] test_uuid_from_invalid_view()184 fn test_uuid_from_invalid_view() { 185 let packet = 186 build_view_or_crash(UuidBuilder { data: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1].into() }); 187 let res = Uuid::try_from(packet.view()); 188 assert!(res.is_err()); 189 } 190 } 191