1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! Contains both a trait and a type to contrain some type with `Zeroable`.

use crate::Zeroable;

use bytemuck::Pod;

use core::{
    cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
    fmt::{self, Debug},
    hash::{Hash, Hasher},
    marker::PhantomData,
    mem,
};

/// A marker type representing that `T` is `Zeroable`.
///
/// This type is zero-sized.
#[repr(C)]
pub struct AssertZeroable<T: ?Sized>(PhantomData<T>);

const _ZERO_SIZED: [(); 1 - core::mem::size_of::<AssertZeroable<()>>()] = [()];

impl<T> AssertZeroable<T>
where
    T: Zeroable + ?Sized,
{
    /// Constructs a `AssertZeroable<T>`
    pub const NEW: Self = AssertZeroable(PhantomData);
}

impl<T> AssertZeroable<T> {
    /// Gets a zeroed `T`.
    ///
    /// This is safe to call,
    /// since constructing a `AssertZeroable<T>` requires that `T` is `Zeroable`.
    #[inline(always)]
    pub fn zeroed(self) -> T {
        unsafe { mem::zeroed() }
    }
}

unsafe impl<T> Zeroable for AssertZeroable<T> where T: Zeroable {}

unsafe impl<T> Pod for AssertZeroable<T> where T: Pod {}

impl<T: ?Sized> Copy for AssertZeroable<T> {}

impl<T: ?Sized> Clone for AssertZeroable<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T: ?Sized> PartialEq for AssertZeroable<T> {
    #[inline]
    fn eq(&self, _other: &Self) -> bool {
        true
    }
}

impl<T: ?Sized> Eq for AssertZeroable<T> {}

impl<T: ?Sized> PartialOrd for AssertZeroable<T> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: ?Sized> Ord for AssertZeroable<T> {
    #[inline]
    fn cmp(&self, _other: &Self) -> Ordering {
        Ordering::Equal
    }
}

impl<T: ?Sized> Hash for AssertZeroable<T> {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        ().hash(state)
    }
}

impl<T: ?Sized> Debug for AssertZeroable<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut ds = f.debug_struct("AssertZeroable");

        #[cfg(feature = "print_type")]
        let ds = ds.field("type", &core::any::type_name::<T>());

        ds.finish()
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Constructs an `AssertZeroable<Self>`.
/// Declared to improve the error message when a field does not implement `Zeroable`.
pub trait GetAssertZeroable: Zeroable {
    /// Gets an `AssertZeroable<Self>`,
    /// a marker type representing that `T` is `Zeroable`
    const GET: AssertZeroable<Self> = AssertZeroable::NEW;
}

impl<This: ?Sized + Zeroable> GetAssertZeroable for This {}