byteable/derive_safety_helpers.rs
1//! Safety helpers for validating types suitable for byte casting.
2//!
3//! This module provides the `ValidBytecastMarker` trait, which marks types that are safe
4//! to transmute to/from byte arrays. This trait acts as a compile-time safety mechanism
5//! to prevent UB when using the `Byteable` derive macros.
6
7use crate::{BigEndian, LittleEndian};
8
9/// Marker trait for types that are safe to transmute to and from byte arrays.
10///
11/// # Safety
12///
13/// This trait should only be implemented for types where:
14/// 1. **All byte patterns are valid** - Any combination of bytes represents a valid value
15/// 2. **No interior pointers** - The type doesn't contain references, `Box`, `Vec`, etc.
16/// 3. **No invalid bit patterns** - Unlike `bool` (only 0/1 valid) or `char` (invalid Unicode)
17/// 4. **No Drop semantics** - The type doesn't implement `Drop` with side effects
18/// 5. **Deterministic layout** - The type has `#[repr(C)]`, `#[repr(transparent)]`, or similar
19/// 6. **Explicit endianness** - Multi-byte types must specify byte order for portability
20///
21/// # Endianness Requirement
22///
23/// **Multi-byte primitive types (u16, u32, i32, f32, etc.) are NOT implemented for this trait.**
24///
25/// You must explicitly wrap them in `BigEndian<T>` or `LittleEndian<T>`, or use the
26/// `#[byteable(little_endian)]` or `#[byteable(big_endian)]` attributes in the `Byteable` derive macro.
27///
28/// This design choice ensures:
29/// - **Cross-platform compatibility**: Data is portable between different architectures
30/// - **No silent bugs**: Won't compile if endianness is forgotten
31/// - **Explicit intent**: Makes byte order visible in the code
32///
33/// Raw multi-byte primitives would use the platform's native byte order, causing subtle bugs
34/// when data is exchanged between systems with different endianness (e.g., x86 vs ARM big-endian).
35///
36/// # Types that implement this trait
37///
38/// - **Single-byte primitives**: `u8`, `i8` (no endianness needed)
39/// - **Endianness wrappers**: `BigEndian<T>` and `LittleEndian<T>` for multi-byte types
40/// - **Arrays**: `[T; N]` where `T: ValidBytecastMarker`
41/// - **Custom structs**: Explicitly marked with `unsafe impl ValidBytecastMarker` (use with caution!)
42///
43/// # Types that should NOT implement this trait
44///
45/// - **Raw multi-byte primitives**: `u16`, `u32`, `u64`, `u128`, `i16`, `i32`, `i64`, `i128`, `f32`, `f64`
46/// (use `BigEndian<T>` or `LittleEndian<T>` instead)
47/// - **Bool/char**: `bool` (only 0x00/0x01 valid), `char` (invalid Unicode ranges)
48/// - **NonZero types**: `NonZero*` types (0x00 is invalid)
49/// - **Pointers/references**: `&T`, `&mut T`, `*const T`, `*mut T`
50/// - **Smart pointers**: `Box<T>`, `Rc<T>`, `Arc<T>`
51/// - **Collections**: `Vec<T>`, `String`, `HashMap`, etc.
52/// - **Complex enums**: `Option<T>`, `Result<T, E>` with niches
53/// - **Function types**: Function pointers or trait objects
54///
55/// # Examples
56///
57/// ## Safe types (compile successfully):
58///
59/// ```
60/// use byteable::{ValidBytecastMarker, LittleEndian, BigEndian};
61///
62/// fn ensure_valid<T: ValidBytecastMarker>() {}
63///
64/// // Single-byte types - no endianness needed
65/// ensure_valid::<u8>();
66/// ensure_valid::<i8>();
67///
68/// // Multi-byte types with explicit endianness - safe and portable
69/// ensure_valid::<LittleEndian<u16>>();
70/// ensure_valid::<BigEndian<u32>>();
71/// ensure_valid::<LittleEndian<f64>>();
72/// ensure_valid::<BigEndian<i64>>();
73///
74/// // Arrays of valid types
75/// ensure_valid::<[u8; 16]>();
76/// ensure_valid::<[LittleEndian<u32>; 4]>();
77/// ```
78///
79/// ## Unsafe types (won't compile):
80///
81/// ```compile_fail
82/// use byteable::ValidBytecastMarker;
83///
84/// fn ensure_valid<T: ValidBytecastMarker>() {}
85///
86/// // Multi-byte primitives without endianness wrapper - REJECTED
87/// ensure_valid::<u16>(); // Error: no explicit endianness
88/// ensure_valid::<u32>(); // Error: no explicit endianness
89/// ensure_valid::<i64>(); // Error: no explicit endianness
90/// ensure_valid::<f32>(); // Error: no explicit endianness
91///
92/// // Types with invalid bit patterns - REJECTED
93/// ensure_valid::<bool>(); // Error: only 0/1 valid
94/// ensure_valid::<char>(); // Error: invalid Unicode ranges
95///
96/// // Types with pointers - REJECTED
97/// ensure_valid::<&u8>(); // Error: contains pointer
98/// ensure_valid::<String>(); // Error: contains pointer + length
99/// ```
100///
101/// ## Correct usage in structs:
102///
103/// ```
104/// # #![cfg(feature = "derive")]
105/// use byteable::Byteable;
106///
107/// // CORRECT: Explicit endianness
108/// #[derive(Clone, Copy, Byteable)]
109/// struct GoodPacket {
110/// id: u8, // Single byte - OK
111/// #[byteable(little_endian)]
112/// length: u16, // Multi-byte with explicit endianness
113/// #[byteable(big_endian)]
114/// checksum: u32, // Multi-byte with explicit endianness
115/// }
116/// # fn main() {}
117/// ```
118///
119/// ```compile_fail
120/// use byteable::Byteable;
121///
122/// // WRONG: Will not compile - no endianness specified
123/// #[derive(Clone, Copy, Byteable)]
124/// struct BadPacket {
125/// id: u8,
126/// length: u16, // Error: needs endianness wrapper or attribute
127/// checksum: u32, // Error: needs endianness wrapper or attribute
128/// }
129/// # fn main() {}
130/// ```
131pub unsafe trait ValidBytecastMarker {}
132
133// Implement for the one-byte primitive numeric types (all bit patterns valid)
134unsafe impl ValidBytecastMarker for u8 {}
135unsafe impl ValidBytecastMarker for i8 {}
136
137// Implement for LittleEndian wrappers
138unsafe impl ValidBytecastMarker for LittleEndian<u16> {}
139unsafe impl ValidBytecastMarker for LittleEndian<u32> {}
140unsafe impl ValidBytecastMarker for LittleEndian<u64> {}
141unsafe impl ValidBytecastMarker for LittleEndian<u128> {}
142unsafe impl ValidBytecastMarker for LittleEndian<i16> {}
143unsafe impl ValidBytecastMarker for LittleEndian<i32> {}
144unsafe impl ValidBytecastMarker for LittleEndian<i64> {}
145unsafe impl ValidBytecastMarker for LittleEndian<i128> {}
146unsafe impl ValidBytecastMarker for LittleEndian<f32> {}
147unsafe impl ValidBytecastMarker for LittleEndian<f64> {}
148
149// Implement for BigEndian wrappers
150unsafe impl ValidBytecastMarker for BigEndian<u16> {}
151unsafe impl ValidBytecastMarker for BigEndian<u32> {}
152unsafe impl ValidBytecastMarker for BigEndian<u64> {}
153unsafe impl ValidBytecastMarker for BigEndian<u128> {}
154unsafe impl ValidBytecastMarker for BigEndian<i16> {}
155unsafe impl ValidBytecastMarker for BigEndian<i32> {}
156unsafe impl ValidBytecastMarker for BigEndian<i64> {}
157unsafe impl ValidBytecastMarker for BigEndian<i128> {}
158unsafe impl ValidBytecastMarker for BigEndian<f32> {}
159unsafe impl ValidBytecastMarker for BigEndian<f64> {}
160
161// Arrays of valid types are also valid
162unsafe impl<T: ValidBytecastMarker, const SIZE: usize> ValidBytecastMarker for [T; SIZE] {}