use alloc::format;
use core::fmt;
use core::fmt::Display;
use p3_field::{Dup, PrimeCharacteristicRing};
use crate::{AirBuilder, ExtensionBuilder, FilteredAirBuilder};
pub trait Name {
type Output: Display;
fn evaluate(self) -> Self::Output;
}
impl Name for &'static str {
type Output = &'static str;
#[inline]
fn evaluate(self) -> Self::Output {
self
}
}
impl<F, T> Name for F
where
F: FnOnce() -> T,
T: Display,
{
type Output = T;
#[inline]
fn evaluate(self) -> Self::Output {
self()
}
}
pub trait Namespace: Name + Copy {}
impl<T> Namespace for T where T: Name + Copy {}
#[derive(Copy, Clone)]
pub struct Joined<A, B> {
left: A,
right: B,
}
pub struct EvaluatedJoined<A, B> {
left: A,
right: B,
}
impl<A: Display, B: Display> Display for EvaluatedJoined<A, B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}::{}", self.left, self.right)
}
}
impl<A: Name, B: Name> Name for Joined<A, B> {
type Output = EvaluatedJoined<A::Output, B::Output>;
#[inline]
fn evaluate(self) -> Self::Output {
EvaluatedJoined {
left: self.left.evaluate(),
right: self.right.evaluate(),
}
}
}
pub trait NamespaceExt: Namespace + Sized {
fn join<Ns: Namespace>(self, sub_ns: Ns) -> Joined<Self, Ns> {
Joined {
left: self,
right: sub_ns,
}
}
fn name<N: Name>(self, name: N) -> Joined<Self, N> {
Joined {
left: self,
right: name,
}
}
}
impl<T> NamespaceExt for T where T: Namespace {}
pub trait NamedAirBuilder: AirBuilder {
fn assert_zero_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::Expr>,
N: Name;
fn assert_zeros_named<const M: usize, I, Ns>(&mut self, array: [I; M], name: Ns)
where
I: Into<Self::Expr>,
Ns: Namespace,
{
for (i, elem) in array.into_iter().enumerate() {
self.assert_zero_named(elem, name.name(|| format!("[{i}]")));
}
}
fn assert_one_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::Expr>,
N: Name,
{
self.assert_zero_named(x.into() - Self::Expr::ONE, name);
}
fn assert_eq_named<I1, I2, N>(&mut self, x: I1, y: I2, name: N)
where
I1: Into<Self::Expr>,
I2: Into<Self::Expr>,
N: Name,
{
self.assert_zero_named(x.into() - y.into(), name);
}
fn assert_bool_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::Expr>,
N: Name,
{
self.assert_zero_named(x.into().bool_check(), name);
}
fn assert_bools_named<const M: usize, I, Ns>(&mut self, array: [I; M], name: Ns)
where
I: Into<Self::Expr>,
Ns: Namespace,
{
let zero_array = array.map(|x| x.into().bool_check());
self.assert_zeros_named(zero_array, name);
}
}
pub trait PassthroughNamedAirBuilder: AirBuilder {}
impl<T: PassthroughNamedAirBuilder> NamedAirBuilder for T {
fn assert_zero_named<I, N>(&mut self, x: I, _name: N)
where
I: Into<Self::Expr>,
N: Name,
{
self.assert_zero(x);
}
fn assert_zeros_named<const M: usize, I, Ns>(&mut self, array: [I; M], _name: Ns)
where
I: Into<Self::Expr>,
Ns: Namespace,
{
self.assert_zeros(array);
}
}
impl<AB: NamedAirBuilder> NamedAirBuilder for FilteredAirBuilder<'_, AB> {
fn assert_zero_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::Expr>,
N: Name,
{
self.inner
.assert_zero_named(self.condition() * x.into(), name);
}
fn assert_zeros_named<const M: usize, I, Ns>(&mut self, array: [I; M], name: Ns)
where
I: Into<Self::Expr>,
Ns: Namespace,
{
let condition = self.condition();
self.inner
.assert_zeros_named(array.map(|elem| condition.dup() * elem.into()), name);
}
}
pub trait NamedExtensionBuilder: ExtensionBuilder + NamedAirBuilder {
fn assert_zero_ext_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::ExprEF>,
N: Name;
fn assert_eq_ext_named<I1, I2, N>(&mut self, x: I1, y: I2, name: N)
where
I1: Into<Self::ExprEF>,
I2: Into<Self::ExprEF>,
N: Name,
{
self.assert_zero_ext_named(x.into() - y.into(), name);
}
fn assert_one_ext_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::ExprEF>,
N: Name,
{
self.assert_zero_ext_named(x.into() - Self::ExprEF::ONE, name);
}
}
impl<T: PassthroughNamedAirBuilder + ExtensionBuilder> NamedExtensionBuilder for T {
fn assert_zero_ext_named<I, N>(&mut self, x: I, _name: N)
where
I: Into<Self::ExprEF>,
N: Name,
{
self.assert_zero_ext(x);
}
}
impl<AB: NamedExtensionBuilder> NamedExtensionBuilder for FilteredAirBuilder<'_, AB> {
fn assert_zero_ext_named<I, N>(&mut self, x: I, name: N)
where
I: Into<Self::ExprEF>,
N: Name,
{
let ext_x: Self::ExprEF = x.into();
let condition: AB::Expr = self.condition();
self.inner.assert_zero_ext_named(ext_x * condition, name);
}
}