Skip to content

Commit 9ffc426

Browse files
committed
[WIP] TryFromBytes
TODO: How to support `project!` when `Projectable` is implemented multiple times for `ByteArray`, `Align`, and `AlignedByteArray`? If we only emit an impl for `AlignedByteArray`, everything is fine, but once we emit the other two, type inference fails. Makes progress on #5
1 parent 865a9b5 commit 9ffc426

File tree

2 files changed

+139
-27
lines changed

2 files changed

+139
-27
lines changed

src/derive_util.rs

+26
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,29 @@ macro_rules! union_has_padding {
6262
false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
6363
};
6464
}
65+
66+
#[doc(hidden)]
67+
pub use project::project as __project;
68+
69+
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
70+
#[macro_export]
71+
macro_rules! impl_try_from_bytes {
72+
($ty:ty { $($f:tt: $f_ty:ty),* } $(=> $validation_method:ident)?) => {
73+
#[allow(unused_qualifications)]
74+
unsafe impl zerocopy::TryFromBytes for $ty {
75+
fn is_bit_valid(bytes: &zerocopy::AlignedByteArray<Self>) -> bool {
76+
true $(&& {
77+
let f: &zerocopy::AlignedByteArray<$f_ty>
78+
= zerocopy::derive_util::__project!(&bytes.$f);
79+
zerocopy::TryFromBytes::is_bit_valid(f)
80+
})*
81+
$(&& {
82+
let bytes_ptr: *const zerocopy::AlignedByteArray<Self> = bytes;
83+
let slf = unsafe { &*bytes_ptr.cast::<Self>() };
84+
// TODO: What about interior mutability?
85+
slf.$validation_method()
86+
})?
87+
}
88+
}
89+
}
90+
}

src/lib.rs

+113-27
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,98 @@ pub unsafe trait FromBytes: FromZeroes {
502502
}
503503
}
504504

505+
/// TODO
506+
pub type AlignedByteArray<T> = Align<ByteArray<T>, T>;
507+
508+
unsafe impl<T, F> Projectable<F, AlignedByteArray<F>> for AlignedByteArray<T> {
509+
type Inner = T;
510+
}
511+
512+
/// TODO
513+
pub unsafe trait TryFromBytes {
514+
/// TODO
515+
fn is_bit_valid(bytes: &AlignedByteArray<Self>) -> bool
516+
where
517+
Self: Sized;
518+
519+
/// TODO
520+
// Note that, in a future in which we distinguish between `FromBytes` and `RefFromBytes`,
521+
// this requires `where Self: RefFromBytes` to disallow interior mutability.
522+
fn try_from_ref(bytes: &[u8]) -> Option<&Self>
523+
where
524+
Self: Sized,
525+
{
526+
let byte_array: &ByteArray<Self> = TryFrom::try_from(bytes).ok()?;
527+
let aligned = Align::try_from_ref(byte_array)?;
528+
529+
if Self::is_bit_valid(aligned) {
530+
Some(unsafe { &*bytes.as_ptr().cast::<Self>() })
531+
} else {
532+
None
533+
}
534+
}
535+
536+
/// TODO
537+
fn try_from_mut(bytes: &mut [u8]) -> Option<&mut Self>
538+
where
539+
Self: AsBytes + Sized,
540+
{
541+
let byte_array: &ByteArray<Self> = TryFrom::try_from(&*bytes).ok()?;
542+
let aligned = Align::try_from_ref(byte_array)?;
543+
544+
if Self::is_bit_valid(aligned) {
545+
Some(unsafe { &mut *bytes.as_mut_ptr().cast::<Self>() })
546+
} else {
547+
None
548+
}
549+
}
550+
551+
/// TODO
552+
fn try_read_from(bytes: &[u8]) -> Option<Self>
553+
where
554+
Self: Sized,
555+
{
556+
let byte_array: &ByteArray<Self> = TryFrom::try_from(bytes).ok()?;
557+
let aligned = Align::new(byte_array.clone());
558+
559+
if Self::is_bit_valid(&aligned) {
560+
Some(unsafe { transmute_size_unchecked(aligned) })
561+
} else {
562+
None
563+
}
564+
}
565+
}
566+
567+
unsafe impl<T: FromBytes> TryFromBytes for T {
568+
fn is_bit_valid(_bytes: &AlignedByteArray<Self>) -> bool
569+
where
570+
Self: Sized,
571+
{
572+
true
573+
}
574+
}
575+
576+
mod try_from_bytes_derive_example {
577+
use super::*;
578+
579+
struct Foo {
580+
a: u8,
581+
b: u16,
582+
}
583+
584+
impl_try_from_bytes!(Foo { a: u8, b: u16 });
585+
586+
struct Bar(Foo);
587+
588+
impl Bar {
589+
fn is_valid(&self) -> bool {
590+
u16::from(self.0.a) < self.0.b
591+
}
592+
}
593+
594+
impl_try_from_bytes!(Bar { 0: Foo } => is_valid);
595+
}
596+
505597
/// Types which are safe to treat as an immutable byte slice.
506598
///
507599
/// WARNING: Do not implement this trait yourself! Instead, use
@@ -1543,21 +1635,9 @@ impl<T: Display + ?Sized, A> Display for Align<T, A> {
15431635
}
15441636
}
15451637

1546-
unsafe impl<T: ?Sized, A> Projectable for Align<T, A> {
1547-
type Inner = T;
1548-
// SAFETY: We know that `U` can't be more aligned than `T` or else it
1549-
// couldn't be a field in `T`. Thus, any `U` within `Align<T, A>` is already
1550-
// aligned to `max(align_of::<U>(), align_of::<A>())`.
1551-
type Wrapped<U> = Align<U, A>;
1552-
1553-
fn foo(&self) -> *const T {
1554-
self as *const Self as *const T
1555-
}
1556-
1557-
fn foo_mut(&mut self) -> *mut T {
1558-
self as *mut Self as *mut T
1559-
}
1560-
}
1638+
// unsafe impl<T: ?Sized, F: ?Sized, A> Projectable<F, Align<F, A>> for Align<T, A> {
1639+
// type Inner = T;
1640+
// }
15611641

15621642
/// A type with no alignment requirement.
15631643
///
@@ -2171,18 +2251,9 @@ impl<T> Ord for ByteArray<T> {
21712251
}
21722252
}
21732253

2174-
unsafe impl<T> Projectable for ByteArray<T> {
2175-
type Inner = T;
2176-
type Wrapped<U> = ByteArray<U>;
2177-
2178-
fn foo(&self) -> *const T {
2179-
self as *const Self as *const T
2180-
}
2181-
2182-
fn foo_mut(&mut self) -> *mut T {
2183-
self as *mut Self as *mut T
2184-
}
2185-
}
2254+
// unsafe impl<T, F> Projectable<F, ByteArray<F>> for ByteArray<T> {
2255+
// type Inner = T;
2256+
// }
21862257

21872258
// Used in `transmute!` below.
21882259
#[doc(hidden)]
@@ -3668,6 +3739,21 @@ mod alloc_support {
36683739
#[doc(inline)]
36693740
pub use alloc_support::*;
36703741

3742+
/// Transmutes a `T` into a `U`.
3743+
///
3744+
/// # Safety
3745+
///
3746+
/// Safety requirements are the same as for `core::mem::transmute`, except that
3747+
/// the caller must also ensure that `size_of::<T>() == size_of::<U>()`.
3748+
unsafe fn transmute_size_unchecked<T, U>(t: T) -> U {
3749+
union Transmute<T, U> {
3750+
t: ManuallyDrop<T>,
3751+
u: ManuallyDrop<U>,
3752+
}
3753+
3754+
unsafe { ManuallyDrop::into_inner(Transmute { t: ManuallyDrop::new(t) }.u) }
3755+
}
3756+
36713757
#[cfg(test)]
36723758
mod tests {
36733759
#![allow(clippy::unreadable_literal)]

0 commit comments

Comments
 (0)