use std::fmt::{self, Debug}; use std::hash::Hash; use std::ops::RangeInclusive; pub(crate) mod tree; pub(crate) use tree::Tree; pub(crate) mod dfa; pub(crate) use dfa::{Dfa, union}; #[derive(Debug)] pub(crate) struct Uninhabited; /// A range of byte values (including an uninit byte value). #[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] pub(crate) struct Byte { // An inclusive-exclusive range. We use this instead of `Range` because `Range: !Copy`. // // Uninit byte value is represented by 256. pub(crate) start: u16, pub(crate) end: u16, } impl Byte { const UNINIT: u16 = 256; #[inline] fn new(range: RangeInclusive) -> Self { let start: u16 = (*range.start()).into(); let end: u16 = (*range.end()).into(); Byte { start, end: end + 1 } } #[inline] fn from_val(val: u8) -> Self { let val: u16 = val.into(); Byte { start: val, end: val + 1 } } #[inline] fn uninit() -> Byte { Byte { start: 0, end: Self::UNINIT + 1 } } #[inline] fn is_empty(&self) -> bool { self.start == self.end } #[inline] fn contains_uninit(&self) -> bool { self.start <= Self::UNINIT && Self::UNINIT < self.end } } impl fmt::Debug for Byte { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.start == Self::UNINIT && self.end == Self::UNINIT + 1 { write!(f, "uninit") } else if self.start <= Self::UNINIT && self.end == Self::UNINIT + 1 { write!(f, "{}..{}|uninit", self.start, self.end - 1) } else { write!(f, "{}..{}", self.start, self.end) } } } impl From> for Byte { fn from(src: RangeInclusive) -> Self { Self::new(src) } } impl From for Byte { #[inline] fn from(src: u8) -> Self { Self::from_val(src) } } /// A reference, i.e., `&'region T` or `&'region mut T`. #[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] pub(crate) struct Reference where R: Region, T: Type, { pub(crate) region: R, pub(crate) is_mut: bool, pub(crate) referent: T, pub(crate) referent_size: usize, pub(crate) referent_align: usize, } impl fmt::Display for Reference where R: Region, T: Type, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("&")?; if self.is_mut { f.write_str("mut ")?; } self.referent.fmt(f) } } pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone { fn has_safety_invariants(&self) -> bool; } pub(crate) trait Region: Debug + Hash + Eq + PartialEq + Copy + Clone {} pub(crate) trait Type: Debug + Hash + Eq + PartialEq + Copy + Clone {} impl Def for ! { fn has_safety_invariants(&self) -> bool { unreachable!() } } impl Region for ! {} impl Type for ! {} #[cfg(test)] impl Region for usize {} #[cfg(test)] impl Type for () {} #[cfg(feature = "rustc")] pub mod rustc { use rustc_abi::Layout; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; use rustc_middle::ty::{self, Region, Ty}; /// A visibility node in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] pub enum Def<'tcx> { Adt(ty::AdtDef<'tcx>), Variant(&'tcx ty::VariantDef), Field(&'tcx ty::FieldDef), Primitive, } impl<'tcx> super::Def for Def<'tcx> { fn has_safety_invariants(&self) -> bool { // Rust presently has no notion of 'unsafe fields', so for now we // make the conservative assumption that everything besides // primitive types carry safety invariants. self != &Self::Primitive } } impl<'tcx> super::Region for Region<'tcx> {} impl<'tcx> super::Type for Ty<'tcx> {} pub(crate) fn layout_of<'tcx>( cx: LayoutCx<'tcx>, ty: Ty<'tcx>, ) -> Result, &'tcx LayoutError<'tcx>> { use rustc_middle::ty::layout::LayoutOf; let ty = cx.tcx().erase_regions(ty); cx.layout_of(ty).map(|tl| tl.layout) } }