use std::{borrow::Borrow, collections::HashMap, fmt::Display};
use serde::{Deserialize, Serialize};
use slop_algebra::Field;
use crate::ir::{FuncCtx, IrVar};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ExprRef<F> {
IrVar(IrVar<F>),
Expr(usize),
}
impl<F: Field> ExprRef<F> {
#[must_use]
pub fn public(index: usize) -> Self {
ExprRef::IrVar(IrVar::Public(index))
}
#[must_use]
pub fn preprocessed(index: usize) -> Self {
ExprRef::IrVar(IrVar::Preprocessed(index))
}
#[must_use]
pub fn main(index: usize) -> Self {
ExprRef::IrVar(IrVar::Main(index))
}
pub fn constant(value: F) -> Self {
ExprRef::IrVar(IrVar::Constant(value))
}
pub fn input_arg(ctx: &mut FuncCtx) -> Self {
let index = ctx.input_idx;
ctx.input_idx += 1;
ExprRef::IrVar(IrVar::InputArg(index))
}
pub fn input_from_struct<T>(ctx: &mut FuncCtx) -> T
where
T: Copy,
[Self]: Borrow<T>,
{
let size = std::mem::size_of::<T>() / std::mem::size_of::<Self>();
let values = (0..size).map(|_| Self::input_arg(ctx)).collect::<Vec<_>>();
let value_ref: &T = values.as_slice().borrow();
*value_ref
}
pub fn output_arg(ctx: &mut FuncCtx) -> Self {
let index = ctx.output_idx;
ctx.output_idx += 1;
ExprRef::IrVar(IrVar::OutputArg(index))
}
pub fn output_from_struct<T>(ctx: &mut FuncCtx) -> T
where
T: Copy,
[Self]: Borrow<T>,
{
let size = std::mem::size_of::<T>() / std::mem::size_of::<Self>();
let values = (0..size).map(|_| Self::output_arg(ctx)).collect::<Vec<_>>();
let value_ref: &T = values.as_slice().borrow();
*value_ref
}
pub fn to_lean_string(&self, input_mapping: &HashMap<usize, String>) -> String {
match self {
ExprRef::Expr(idx) => format!("E{idx}"),
ExprRef::IrVar(IrVar::Main(idx)) => format!("Main[{idx}]"),
ExprRef::IrVar(IrVar::Constant(idx)) => format!("{idx}"),
ExprRef::IrVar(IrVar::InputArg(idx)) => input_mapping.get(idx).unwrap().clone(),
ExprRef::IrVar(IrVar::Public(idx)) => format!("public_value () {idx}"),
_ => todo!(),
}
}
pub fn expr_to_lean_string(&self) -> String {
match self {
ExprRef::Expr(idx) => format!("E{idx}"),
_ => unimplemented!(),
}
}
}
impl<F: Field> Display for ExprRef<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExprRef::IrVar(ir_var) => write!(f, "{ir_var}"),
ExprRef::Expr(expr) => write!(f, "Expr({expr})"),
}
}
}
impl<F: Field> ExprRef<F> {
pub fn to_lean(&self, is_operation: bool, input_mapping: &HashMap<usize, String>) -> String {
match self {
ExprRef::IrVar(var) => var.to_lean(is_operation, input_mapping),
ExprRef::Expr(i) => format!("E{i}"),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ExprExtRef<EF> {
ExtConstant(EF),
Expr(usize),
}
impl<EF: Field> ExprExtRef<EF> {
pub fn input_arg(ctx: &mut FuncCtx) -> Self {
let index = ctx.input_idx;
ctx.input_idx += 1;
ExprExtRef::Expr(index)
}
pub fn output_arg(ctx: &mut FuncCtx) -> Self {
let index = ctx.output_idx;
ctx.output_idx += 1;
ExprExtRef::Expr(index)
}
}
impl<EF: Field> Display for ExprExtRef<EF> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExprExtRef::ExtConstant(ext_constant) => write!(f, "{ext_constant}"),
ExprExtRef::Expr(expr) => write!(f, "ExprExt({expr})"),
}
}
}
impl<EF: Field> ExprExtRef<EF> {
pub fn to_lean(&self, _is_operation: bool, _input_mapping: &HashMap<usize, String>) -> String {
match self {
ExprExtRef::ExtConstant(c) => format!("{c}"),
ExprExtRef::Expr(i) => format!("EExt{i}"),
}
}
}