use core::marker::PhantomData;
use super::Pass;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Raw<S>(S);
impl<S> Raw<S> {
#[inline]
pub const fn new(artifact: S) -> Self {
Raw(artifact)
}
#[inline]
pub const fn get(&self) -> &S {
&self.0
}
#[inline]
pub const fn get_mut(&mut self) -> &mut S {
&mut self.0
}
#[inline]
pub fn into_inner(self) -> S {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Canonical<S>(S);
impl<S> Canonical<S> {
#[inline]
#[must_use]
pub fn produce<P: Pass>(raw: Raw<S>) -> Self {
let () = MandatoryCheck::<P>::PROOF;
Canonical(raw.into_inner())
}
#[inline]
pub const fn get(&self) -> &S {
&self.0
}
#[inline]
pub fn into_inner(self) -> S {
self.0
}
#[inline]
#[must_use]
pub fn into_raw(self) -> Raw<S> {
Raw(self.0)
}
}
struct MandatoryCheck<P>(PhantomData<P>);
impl<P: Pass> MandatoryCheck<P> {
const PROOF: () = assert!(
P::DESC.kind.is_mandatory(),
"only a mandatory pass may perform the raw -> canonical transition"
);
}
#[cfg(test)]
mod tests {
use super::{Canonical, Raw};
use crate::pass::{Fusability, Pass, PassDesc, PassKind, Preserved};
struct Lowerer;
impl Pass for Lowerer {
const DESC: PassDesc = PassDesc::new(
"lower",
PassKind::MandatoryLowering,
Fusability::Barrier,
Preserved::NONE,
);
}
struct Diagnoser;
impl Pass for Diagnoser {
const DESC: PassDesc = PassDesc::new(
"diagnose",
PassKind::MandatoryDiagnostic,
Fusability::Barrier,
Preserved::ALL,
);
}
#[test]
fn raw_wraps_and_unwraps_without_ceremony() {
let mut raw = Raw::new(7u32);
assert_eq!(*raw.get(), 7);
*raw.get_mut() += 1;
assert_eq!(raw.into_inner(), 8);
}
#[test]
fn a_mandatory_lowering_pass_can_canonicalize() {
let canonical = Canonical::produce::<Lowerer>(Raw::new("s2"));
assert_eq!(*canonical.get(), "s2");
assert_eq!(canonical.into_inner(), "s2");
}
#[test]
fn a_mandatory_diagnostic_pass_can_canonicalize_too() {
let canonical = Canonical::produce::<Diagnoser>(Raw::new(1u8));
assert_eq!(*canonical.get(), 1);
}
#[test]
fn demotion_back_to_raw_is_explicit_and_lossless() {
let canonical = Canonical::produce::<Lowerer>(Raw::new(41u32));
let mut raw = canonical.into_raw();
*raw.get_mut() += 1;
assert_eq!(raw.into_inner(), 42);
}
}