use alloc::vec::Vec;
use core::fmt;
use crate::Model;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Ctor {
Wild,
Other,
Variant(u32),
Product,
Bool(bool),
Int {
lo: i128,
hi: i128,
},
Char {
lo: char,
hi: char,
},
Lit(u64),
Slice {
len: u32,
},
SliceRest {
prefix: u32,
suffix: u32,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct WNode<T> {
pub(crate) ctor: Ctor,
pub(crate) ty: T,
pub(crate) arity: u32,
pub(crate) size: u32,
}
#[derive(Clone, PartialEq, Eq)]
pub struct Witness<T> {
nodes: Vec<WNode<T>>,
}
impl<T> Witness<T> {
pub(crate) fn from_nodes(nodes: Vec<WNode<T>>) -> Witness<T> {
Witness { nodes }
}
#[must_use]
pub fn root(&self) -> WitnessRef<'_, T> {
WitnessRef {
nodes: &self.nodes,
pos: self.nodes.len().saturating_sub(1),
}
}
#[must_use]
pub fn ctor(&self) -> Ctor {
self.root().ctor()
}
#[must_use]
pub fn ty(&self) -> &T {
self.root().ty()
}
pub fn fields(&self) -> WitnessFields<'_, T> {
self.root().fields()
}
pub fn display<'a, M: Model<Ty = T>>(&'a self, model: &'a M) -> WitnessDisplay<'a, M> {
WitnessDisplay {
witness: self.root(),
model,
}
}
}
impl<T> fmt::Display for Witness<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.root().fmt(f)
}
}
impl<T> fmt::Debug for Witness<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Witness({})", self.root())
}
}
pub struct WitnessRef<'a, T> {
nodes: &'a [WNode<T>],
pos: usize,
}
impl<T> Clone for WitnessRef<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for WitnessRef<'_, T> {}
impl<'a, T> WitnessRef<'a, T> {
fn node(&self) -> Option<&'a WNode<T>> {
self.nodes.get(self.pos)
}
#[must_use]
pub fn ctor(&self) -> Ctor {
self.node().map_or(Ctor::Wild, |n| n.ctor)
}
#[must_use]
pub fn ty(&self) -> &'a T {
match self.nodes.get(self.pos) {
Some(node) => &node.ty,
None => &self.nodes[0].ty,
}
}
#[must_use]
pub fn arity(&self) -> usize {
self.node().map_or(0, |n| n.arity as usize)
}
#[must_use]
pub fn fields(&self) -> WitnessFields<'a, T> {
WitnessFields {
nodes: self.nodes,
next: self.pos.checked_sub(1),
remaining: self.arity(),
}
}
pub fn display<M: Model<Ty = T>>(self, model: &'a M) -> WitnessDisplay<'a, M> {
WitnessDisplay {
witness: self,
model,
}
}
fn write_with<'n>(
&self,
f: &mut fmt::Formatter<'_>,
name: impl Fn(&T, u32) -> Option<&'n str>,
) -> fmt::Result {
enum Step<'a, T> {
Node(WitnessRef<'a, T>),
Text(&'static str),
}
let mut stack = Vec::new();
stack.push(Step::Node(*self));
let mut fields = Vec::new();
while let Some(step) = stack.pop() {
let node = match step {
Step::Text(text) => {
f.write_str(text)?;
continue;
}
Step::Node(node) => node,
};
let (open, close) = match node.ctor() {
Ctor::Wild | Ctor::Other => {
f.write_str("_")?;
continue;
}
Ctor::Bool(b) => {
write!(f, "{b}")?;
continue;
}
Ctor::Int { lo, hi } if lo == hi => {
write!(f, "{lo}")?;
continue;
}
Ctor::Int { lo, hi } => {
write!(f, "{lo}..={hi}")?;
continue;
}
Ctor::Char { lo, hi } if lo == hi => {
write!(f, "{lo:?}")?;
continue;
}
Ctor::Char { lo, hi } => {
write!(f, "{lo:?}..={hi:?}")?;
continue;
}
Ctor::Lit(id) => {
write!(f, "lit#{id}")?;
continue;
}
Ctor::Variant(index) => {
match name(node.ty(), index) {
Some(n) => f.write_str(n)?,
None => write!(f, "#{index}")?,
}
if node.arity() == 0 {
continue;
}
("(", ")")
}
Ctor::Product => match name(node.ty(), 0) {
Some(n) => {
f.write_str(n)?;
if node.arity() == 0 {
continue;
}
("(", ")")
}
None if node.arity() == 1 => ("(", ",)"),
None => ("(", ")"),
},
Ctor::Slice { .. } => ("[", "]"),
Ctor::SliceRest { prefix, .. } => {
f.write_str("[")?;
stack.push(Step::Text("]"));
fields.clear();
fields.extend(node.fields());
let split = (prefix as usize).min(fields.len());
let (pre, post) = fields.split_at(split);
for (i, field) in post.iter().enumerate().rev() {
stack.push(Step::Node(*field));
if i > 0 {
stack.push(Step::Text(", "));
}
}
stack.push(Step::Text(match (pre.is_empty(), post.is_empty()) {
(true, true) => "..",
(true, false) => ".., ",
(false, true) => ", ..",
(false, false) => ", .., ",
}));
for (i, field) in pre.iter().enumerate().rev() {
stack.push(Step::Node(*field));
if i > 0 {
stack.push(Step::Text(", "));
}
}
continue;
}
};
f.write_str(open)?;
stack.push(Step::Text(close));
fields.clear();
fields.extend(node.fields());
for (i, field) in fields.iter().enumerate().rev() {
stack.push(Step::Node(*field));
if i > 0 {
stack.push(Step::Text(", "));
}
}
}
Ok(())
}
}
impl<T> fmt::Display for WitnessRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_with(f, |_, _| None)
}
}
impl<T> fmt::Debug for WitnessRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "WitnessRef({self})")
}
}
pub struct WitnessFields<'a, T> {
nodes: &'a [WNode<T>],
next: Option<usize>,
remaining: usize,
}
impl<'a, T> Iterator for WitnessFields<'a, T> {
type Item = WitnessRef<'a, T>;
fn next(&mut self) -> Option<WitnessRef<'a, T>> {
if self.remaining == 0 {
return None;
}
let pos = self.next?;
let node = self.nodes.get(pos)?;
self.remaining -= 1;
self.next = pos.checked_sub(node.size as usize);
Some(WitnessRef {
nodes: self.nodes,
pos,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T> ExactSizeIterator for WitnessFields<'_, T> {}
impl<T> fmt::Debug for WitnessFields<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WitnessFields")
.field("remaining", &self.remaining)
.finish()
}
}
pub struct WitnessDisplay<'a, M: Model> {
witness: WitnessRef<'a, M::Ty>,
model: &'a M,
}
impl<M: Model> fmt::Display for WitnessDisplay<'_, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.witness
.write_with(f, |ty, variant| self.model.variant_name(ty, variant))
}
}
impl<M: Model> fmt::Debug for WitnessDisplay<'_, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}