No, only structs with no invariants. As soon as you have invariants, there are illegal bit patterns. Of course, these illegal bit pattern may not necessarily result in memory unsafety, but there's no way for the compiler to know this automatically^.
This functionality could be implemented something like
fn from_bytes<T: JustBits>(bytes: &[u8]) -> Option<&T> {
if bytes.len() >= std::mem::size_of::<T>() {
unsafe {
Some(&*(bytes.as_ptr() as *const T))
}
} else {
None
}
}
/// Values for which any bit pattern is valid.
pub unsafe trait JustBits {}
unsafe impl JustBits for u8 {}
unsafe impl JustBits for i8 {}
unsafe impl JustBits for u16 {}
unsafe impl JustBits for i16 {}
// ...
Some custom struct that can be any bit pattern can then do:
Of course, there's `unsafe` there, but there has to be: it's asserting that "yes, I'm sure that anything works".
^Notably, there's been proposals for `unsafe` fields which will make expressing "invariants exist" more focused, and adjust the trade-offs here.
(I'll note that a TCP header has 3 reserved bits (100, 101, 102) which, I believe, should be set to zero, making some bit patterns theoretically illegal.)
Structs which contain only primitives have that property. Consider a TCP header.