use std::num::NonZero;
use std::sync::Arc;
#[cfg(doc)]
use crate::Solver;
use crate::containers::StorageKey;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ConstraintTag(NonZero<u32>);
impl From<ConstraintTag> for NonZero<u32> {
fn from(value: ConstraintTag) -> Self {
value.0
}
}
impl ConstraintTag {
pub(crate) fn from_non_zero(non_zero: NonZero<u32>) -> ConstraintTag {
ConstraintTag(non_zero)
}
}
impl StorageKey for ConstraintTag {
fn index(&self) -> usize {
self.0.get() as usize - 1
}
fn create_from_index(index: usize) -> Self {
Self::from_non_zero(
NonZero::new(index as u32 + 1).expect("the '+ 1' ensures the value is non-zero"),
)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InferenceCode(ConstraintTag, Arc<str>);
impl InferenceCode {
pub fn new(tag: ConstraintTag, label: impl InferenceLabel) -> Self {
InferenceCode(tag, label.to_str())
}
pub fn unknown_label(tag: ConstraintTag) -> Self {
InferenceCode::new(tag, Unknown)
}
pub fn tag(&self) -> ConstraintTag {
self.0
}
pub fn label(&self) -> Arc<str> {
Arc::clone(&self.1)
}
}
#[doc(hidden)]
pub fn convert_label_name(ident_str: &str) -> Arc<str> {
use convert_case::Casing;
ident_str.to_case(convert_case::Case::Snake).into()
}
#[macro_export]
macro_rules! declare_inference_label {
($v:vis $name:ident) => {
declare_inference_label!($v $name, $crate::proof::convert_label_name(stringify!($name)));
};
($v:vis $name:ident, $label:expr) => {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
$v struct $name;
declare_inference_label!(@impl_trait $name, std::sync::Arc::from($label));
};
(@impl_trait $name:ident, $label:expr) => {
impl $crate::proof::InferenceLabel for $name {
fn to_str(&self) -> std::sync::Arc<str> {
static LABEL: std::sync::OnceLock<std::sync::Arc<str>> = std::sync::OnceLock::new();
let label = LABEL.get_or_init(|| $label);
std::sync::Arc::clone(label)
}
}
};
}
pub trait InferenceLabel {
fn to_str(&self) -> Arc<str>;
}
declare_inference_label!(pub Unknown);