1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum BytecodeError {
20 InvalidLength(usize),
22 MisalignedPointer,
24}
25
26impl fmt::Display for BytecodeError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 Self::InvalidLength(len) => {
30 write!(f, "SPIR-V byte length {len} is not a multiple of 4")
31 }
32 Self::MisalignedPointer => {
33 write!(f, "SPIR-V byte slice pointer is not 4-byte aligned")
34 }
35 }
36 }
37}
38
39impl std::error::Error for BytecodeError {}
40
41pub fn cast_to_u32(bytes: &[u8]) -> Result<&[u32], BytecodeError> {
59 if bytes.is_empty() {
60 return Ok(&[]);
61 }
62 if bytes.len() % 4 != 0 {
63 return Err(BytecodeError::InvalidLength(bytes.len()));
64 }
65 if (bytes.as_ptr() as usize) % 4 != 0 {
66 return Err(BytecodeError::MisalignedPointer);
67 }
68 Ok(unsafe { std::slice::from_raw_parts(bytes.as_ptr() as *const u32, bytes.len() / 4) })
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn aligned_input_succeeds() {
78 #[repr(align(4))]
79 struct Aligned([u8; 8]);
80 let data = Aligned([0x03, 0x02, 0x23, 0x07, 0, 0, 0, 0]);
81 let words = cast_to_u32(&data.0).expect("aligned input should succeed");
82 assert_eq!(words.len(), 2);
83 assert_eq!(words[0], 0x07230203); }
85
86 #[test]
87 fn invalid_length_returns_error() {
88 #[repr(align(4))]
89 struct Aligned([u8; 5]);
90 let data = Aligned([1, 2, 3, 4, 5]);
91 assert_eq!(cast_to_u32(&data.0), Err(BytecodeError::InvalidLength(5)));
92 }
93
94 #[test]
95 fn empty_input_succeeds() {
96 let empty: &[u8] = &[];
97 let words = cast_to_u32(empty).expect("empty input should succeed");
98 assert!(words.is_empty());
99 }
100
101 #[test]
102 fn misaligned_pointer_display() {
103 let err = BytecodeError::MisalignedPointer;
104 assert_eq!(
105 err.to_string(),
106 "SPIR-V byte slice pointer is not 4-byte aligned"
107 );
108 }
109
110 #[test]
111 fn invalid_length_display() {
112 let err = BytecodeError::InvalidLength(7);
113 assert_eq!(
114 err.to_string(),
115 "SPIR-V byte length 7 is not a multiple of 4"
116 );
117 }
118
119 #[test]
120 fn misaligned_pointer_returns_error() {
121 #[repr(align(4))]
124 struct Aligned([u8; 8]);
125 let data = Aligned([0; 8]);
126 let misaligned = &data.0[1..5];
127 assert_eq!(
128 cast_to_u32(misaligned),
129 Err(BytecodeError::MisalignedPointer)
130 );
131 }
132
133 #[test]
134 fn bytecode_error_is_std_error() {
135 let err: &dyn std::error::Error = &BytecodeError::InvalidLength(3);
136 assert!(err.source().is_none());
138 }
139}