| 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<u8>) -> 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<RangeInclusive<u8>> for Byte { |
| fn from(src: RangeInclusive<u8>) -> Self { |
| Self::new(src) |
| } |
| } |
| |
| impl From<u8> 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<R, T> |
| 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<R, T> fmt::Display for Reference<R, T> |
| 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<Layout<'tcx>, &'tcx LayoutError<'tcx>> { |
| use rustc_middle::ty::layout::LayoutOf; |
| let ty = cx.tcx().erase_regions(ty); |
| cx.layout_of(ty).map(|tl| tl.layout) |
| } |
| } |