diff options
Diffstat (limited to 'src/util.rs')
-rw-r--r-- | src/util.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..ed810dc --- /dev/null +++ b/src/util.rs @@ -0,0 +1,105 @@ +// Copyright 2023 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use core::mem; + +pub(crate) trait AsAddress { + fn addr(self) -> usize; +} + +impl<'a, T: ?Sized> AsAddress for &'a T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +impl<'a, T: ?Sized> AsAddress for &'a mut T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +impl<T: ?Sized> AsAddress for *const T { + #[inline(always)] + fn addr(self) -> usize { + // TODO(https://github.com/rust-lang/rust/issues/95228): Use `.addr()` + // instead of `as usize` once it's stable, and get rid of this `allow`. + // Currently, `as usize` is the only way to accomplish this. + #[allow(clippy::as_conversions)] + return self.cast::<()>() as usize; + } +} + +impl<T: ?Sized> AsAddress for *mut T { + #[inline(always)] + fn addr(self) -> usize { + let ptr: *const T = self; + AsAddress::addr(ptr) + } +} + +/// Is `t` aligned to `mem::align_of::<U>()`? +#[inline(always)] +pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool { + // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in + // turn guarantees that this mod operation will not panic. + #[allow(clippy::arithmetic_side_effects)] + let remainder = t.addr() % mem::align_of::<U>(); + remainder == 0 +} + +#[cfg(test)] +pub(crate) mod testutil { + use core::fmt::{self, Display, Formatter}; + + use crate::*; + + /// A `T` which is aligned to at least `align_of::<A>()`. + #[derive(Default)] + pub(crate) struct Align<T, A> { + pub(crate) t: T, + _a: [A; 0], + } + + impl<T: Default, A> Align<T, A> { + pub(crate) fn set_default(&mut self) { + self.t = T::default(); + } + } + + impl<T, A> Align<T, A> { + pub(crate) const fn new(t: T) -> Align<T, A> { + Align { t, _a: [] } + } + } + + // A `u64` with alignment 8. + // + // Though `u64` has alignment 8 on some platforms, it's not guaranteed. + // By contrast, `AU64` is guaranteed to have alignment 8. + #[derive( + FromZeroes, FromBytes, AsBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, + )] + #[repr(C, align(8))] + pub(crate) struct AU64(pub(crate) u64); + + impl AU64 { + // Converts this `AU64` to bytes using this platform's endianness. + pub(crate) fn to_bytes(self) -> [u8; 8] { + crate::transmute!(self) + } + } + + impl Display for AU64 { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + impl_known_layout!(AU64); +} |