use crate::circuit::classical_expr::ClassicalExpr;
use crate::circuit::{CircuitError, ClassicalType, ClassicalVar};
use std::collections::BTreeSet;
pub(crate) fn validate_for_types(
var: ClassicalVar,
start: &ClassicalExpr,
stop: &ClassicalExpr,
step: &ClassicalExpr,
) -> Result<(), CircuitError> {
if !matches!(var.ty(), ClassicalType::UInt(_)) {
return Err(CircuitError::InvalidOperation(format!(
"for loop variable must be UInt, got {:?}",
var.ty()
)));
}
if start.ty() != var.ty() {
return Err(CircuitError::InvalidOperation(format!(
"for start type must match loop variable {:?}, got {:?}",
var.ty(),
start.ty()
)));
}
if stop.ty() != var.ty() {
return Err(CircuitError::InvalidOperation(format!(
"for stop type must match loop variable {:?}, got {:?}",
var.ty(),
stop.ty()
)));
}
if step.ty() != var.ty() {
return Err(CircuitError::InvalidOperation(format!(
"for step type must match loop variable {:?}, got {:?}",
var.ty(),
step.ty()
)));
}
Ok(())
}
pub(crate) fn validate_switch(
target: &ClassicalExpr,
case_values: impl IntoIterator<Item = u128>,
) -> Result<(), CircuitError> {
let width = match target.ty() {
ClassicalType::UInt(width) => width.get(),
ty => {
return Err(CircuitError::InvalidOperation(format!(
"switch target must be UInt, got {ty:?}"
)));
}
};
let mut values = BTreeSet::new();
for value in case_values {
if width < 128 && value >= (1u128 << width) {
return Err(CircuitError::InvalidOperation(format!(
"switch case value {} does not fit in target width {width}",
value
)));
}
if !values.insert(value) {
return Err(CircuitError::InvalidOperation(format!(
"duplicate switch case value {}",
value
)));
}
}
Ok(())
}