pinapod 0.4.3

Zero-copy pod types with derive macros. Alignment-1 representations for zero-overhead data access.
Documentation
use core::fmt;

/// Alignment-one boolean storage for a schema field declared as `bool`.
///
/// The stored value is a single byte that is either `0` or `1`, so `PodBool` is
/// `#[repr(transparent)]` over `[u8; 1]` and can be read at any byte offset.
///
/// [`get`](Self::get) treats any non-zero byte as `true`, while validation rejects a
/// byte above `1`. A forged `2` is therefore a read error rather than a truthy value.
///
/// A schema field declared as `bool` maps to this pod through the [`ZcField`]
/// implementation, so `PinaPod` derives accept the native spelling.
///
/// [`ZcField`]: crate::ZcField
#[repr(transparent)]
#[derive(Copy, Clone, Default)]
pub struct PodBool([u8; 1]);

impl PodBool {
	/// Returns the contained [`bool`] value. Any non-zero byte yields `true`.
	#[inline(always)]
	pub fn get(&self) -> bool {
		self.0[0] != 0
	}

	/// Returns `true` when the stored byte is non-zero.
	///
	/// This is the same comparison as [`get`](Self::get), named for call sites that
	/// read as a predicate.
	#[inline(always)]
	pub fn is_true(&self) -> bool {
		self.get()
	}

	/// Returns `true` when the stored byte is zero.
	#[inline(always)]
	pub fn is_false(&self) -> bool {
		!self.get()
	}

	/// Replaces the stored byte with `0` for `false` or `1` for `true`.
	#[inline(always)]
	pub fn set(&mut self, value: bool) {
		self.0 = [value as u8];
	}
}

impl From<bool> for PodBool {
	#[inline(always)]
	fn from(v: bool) -> Self {
		Self([v as u8])
	}
}

impl From<PodBool> for bool {
	#[inline(always)]
	fn from(v: PodBool) -> Self {
		v.get()
	}
}

impl PartialEq for PodBool {
	#[inline(always)]
	fn eq(&self, other: &Self) -> bool {
		self.get() == other.get()
	}
}
impl Eq for PodBool {}

impl PartialEq<bool> for PodBool {
	#[inline(always)]
	fn eq(&self, other: &bool) -> bool {
		self.get() == *other
	}
}

impl core::ops::Not for PodBool {
	type Output = Self;

	#[inline(always)]
	fn not(self) -> Self {
		Self::from(!self.get())
	}
}

impl core::hash::Hash for PodBool {
	fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
		self.get().hash(state);
	}
}

impl core::ops::BitAnd<bool> for PodBool {
	type Output = PodBool;

	fn bitand(self, rhs: bool) -> PodBool {
		PodBool::from(self.get() & rhs)
	}
}

impl core::ops::BitOr<bool> for PodBool {
	type Output = PodBool;

	fn bitor(self, rhs: bool) -> PodBool {
		PodBool::from(self.get() | rhs)
	}
}

impl PartialEq<PodBool> for bool {
	fn eq(&self, other: &PodBool) -> bool {
		*self == other.get()
	}
}

impl fmt::Display for PodBool {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		self.get().fmt(f)
	}
}

impl fmt::Debug for PodBool {
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
		fmt::Debug::fmt(&self.get(), f)
	}
}

impl AsRef<[u8]> for PodBool {
	#[inline(always)]
	fn as_ref(&self) -> &[u8] {
		&self.0
	}
}

const _: () = assert!(core::mem::align_of::<PodBool>() == 1);
const _: () = assert!(core::mem::size_of::<PodBool>() == 1);

// ---------------------------------------------------------------------------
// Kani model-checking proof harnesses
// ---------------------------------------------------------------------------

#[cfg(all(kani, feature = "kani"))]
mod kani_proofs {
	use super::*;

	#[kani::proof]
	fn bool_roundtrip() {
		let v: bool = kani::any();
		let pod = PodBool::from(v);
		assert!(pod.get() == v, "bool roundtrip must preserve value");
	}

	#[kani::proof]
	fn any_nonzero_is_true() {
		let byte: u8 = kani::any();
		// Construct PodBool from a raw byte. PodBool is #[repr(transparent)]
		// over [u8; 1], so this transmute is sound for any bit pattern.
		let pod: PodBool = unsafe { core::mem::transmute([byte]) };
		assert!(pod.get() == (byte != 0), "any nonzero byte must be true");
	}

	#[kani::proof]
	fn not_involution() {
		let v: bool = kani::any();
		let pod = PodBool::from(v);
		assert!(!!pod == pod, "double negation must be identity");
	}
}