blob: c08bf440734e2cb1c214e7c9faa8c7c05596c5ac [file] [log] [blame]
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)
}
}
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
fn has_safety_invariants(&self) -> bool;
}
pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
fn min_align(&self) -> usize;
fn size(&self) -> usize;
fn is_mutable(&self) -> bool;
}
impl Def for ! {
fn has_safety_invariants(&self) -> bool {
unreachable!()
}
}
impl Ref for ! {
fn min_align(&self) -> usize {
unreachable!()
}
fn size(&self) -> usize {
unreachable!()
}
fn is_mutable(&self) -> bool {
unreachable!()
}
}
#[cfg(test)]
impl<const N: usize> Ref for [(); N] {
fn min_align(&self) -> usize {
N
}
fn size(&self) -> usize {
N
}
fn is_mutable(&self) -> bool {
false
}
}
#[cfg(feature = "rustc")]
pub mod rustc {
use std::fmt::{self, Write};
use rustc_abi::Layout;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
use rustc_middle::ty::{self, Ty};
/// A reference in the layout.
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
pub struct Ref<'tcx> {
pub lifetime: ty::Region<'tcx>,
pub ty: Ty<'tcx>,
pub mutability: Mutability,
pub align: usize,
pub size: usize,
}
impl<'tcx> super::Ref for Ref<'tcx> {
fn min_align(&self) -> usize {
self.align
}
fn size(&self) -> usize {
self.size
}
fn is_mutable(&self) -> bool {
match self.mutability {
Mutability::Mut => true,
Mutability::Not => false,
}
}
}
impl<'tcx> Ref<'tcx> {}
impl<'tcx> fmt::Display for Ref<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('&')?;
if self.mutability == Mutability::Mut {
f.write_str("mut ")?;
}
self.ty.fmt(f)
}
}
/// 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
}
}
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)
}
}