use crate::config::Config;
use crate::context::Context;
use crate::error::{Error, Result};
use crate::ops::OpVec;
use crate::transforms::Transform;
use crate::types::TransformDirection;
use std::cell::Cell;
pub trait BuildOps {
fn build_ops(
&self,
ops: &mut OpVec,
config: &Config,
context: &Context,
dir: TransformDirection,
) -> Result<()>;
}
pub trait Validate {
fn validate(&self) -> Result<()>;
}
thread_local! {
static BUILD_DEPTH: Cell<u32> = const { Cell::new(0) };
}
pub fn build_ops(
ops: &mut OpVec,
config: &Config,
context: &Context,
transform: &Transform,
dir: TransformDirection,
) -> Result<()> {
let depth = BUILD_DEPTH.with(|d| {
let v = d.get() + 1;
d.set(v);
v
});
struct Guard;
impl Drop for Guard {
fn drop(&mut self) {
BUILD_DEPTH.with(|d| d.set(d.get() - 1));
}
}
let _guard = Guard;
if depth > 64 {
return Err(Error::msg(
"Cycle detected while building ops for transforms.",
));
}
crate::for_each_transform!(transform, t => t.build_ops(ops, config, context, dir))
}
use crate::transforms::GroupTransform;
impl Validate for GroupTransform {
fn validate(&self) -> Result<()> {
for t in &self.transforms {
t.validate()?;
}
Ok(())
}
}
impl BuildOps for GroupTransform {
fn build_ops(
&self,
ops: &mut OpVec,
config: &Config,
context: &Context,
dir: TransformDirection,
) -> Result<()> {
match self.direction.combine(dir) {
TransformDirection::Forward => {
for t in &self.transforms {
build_ops(ops, config, context, t, TransformDirection::Forward)?;
}
}
TransformDirection::Inverse => {
for t in self.transforms.iter().rev() {
build_ops(ops, config, context, t, TransformDirection::Inverse)?;
}
}
}
Ok(())
}
}