use super::Context;
use sapio_base::effects::PathFragment;
use std::collections::LinkedList;
pub enum ConditionalCompileType {
Skippable,
Nullable,
Required,
Never,
NoConstraint,
Fail(LinkedList<String>),
}
impl ConditionalCompileType {
pub fn merge(self, other: Self) -> Self {
match (self, other) {
(ConditionalCompileType::NoConstraint, x) => x,
(x, ConditionalCompileType::NoConstraint) => x,
(ConditionalCompileType::Fail(mut v), ConditionalCompileType::Fail(mut v2)) => {
ConditionalCompileType::Fail({
v.append(&mut v2);
v
})
}
(ConditionalCompileType::Fail(v), _) | (_, ConditionalCompileType::Fail(v)) => {
ConditionalCompileType::Fail(v)
}
(ConditionalCompileType::Required, ConditionalCompileType::Never)
| (ConditionalCompileType::Never, ConditionalCompileType::Required) => {
let mut l = LinkedList::new();
l.push_front(String::from("Never and Required incompatible"));
ConditionalCompileType::Fail(l)
}
(ConditionalCompileType::Never, ConditionalCompileType::Skippable)
| (ConditionalCompileType::Skippable, ConditionalCompileType::Never)
| (ConditionalCompileType::Never, ConditionalCompileType::Nullable)
| (ConditionalCompileType::Nullable, ConditionalCompileType::Never)
| (ConditionalCompileType::Never, ConditionalCompileType::Never) => {
ConditionalCompileType::Never
}
(ConditionalCompileType::Required, ConditionalCompileType::Skippable)
| (ConditionalCompileType::Skippable, ConditionalCompileType::Required)
| (ConditionalCompileType::Required, ConditionalCompileType::Nullable)
| (ConditionalCompileType::Nullable, ConditionalCompileType::Required)
| (ConditionalCompileType::Required, ConditionalCompileType::Required) => {
ConditionalCompileType::Required
}
(ConditionalCompileType::Skippable, ConditionalCompileType::Skippable)
| (ConditionalCompileType::Skippable, ConditionalCompileType::Nullable)
| (ConditionalCompileType::Nullable, ConditionalCompileType::Skippable) => {
ConditionalCompileType::Skippable
}
(ConditionalCompileType::Nullable, ConditionalCompileType::Nullable) => {
ConditionalCompileType::Nullable
}
}
}
}
pub enum ConditionallyCompileIf<ContractSelf> {
Fresh(fn(&ContractSelf, Context) -> ConditionalCompileType),
}
pub type ConditionallyCompileIfList<'a, T> = &'a [fn() -> Option<ConditionallyCompileIf<T>>];
pub(crate) struct CCILWrapper<'a, T>(pub ConditionallyCompileIfList<'a, T>);
impl<'a, T> CCILWrapper<'a, T> {
pub fn assemble(&self, self_ref: &T, context: &mut Context) -> ConditionalCompileType {
self.0
.iter()
.filter_map(|compf| compf())
.zip((0..).flat_map(|i| context.derive(PathFragment::Branch(i)).ok()))
.fold(ConditionalCompileType::NoConstraint, |acc, (cond, c)| {
let ConditionallyCompileIf::Fresh(f) = cond;
acc.merge(f(self_ref, c))
})
}
}