use crate::{FieldAlg, ShapeAlg, ShapeExt, Sorts, Words};
use alux_ext::ext;
pub trait ShapeProgramAlg<Alg> {
type Ty;
fn compile_shape(self, alg: &Alg) -> Self::Ty;
}
#[ext(name = ShapeProgramExt, supertraits = Sized)]
pub impl<This> This {
fn compile_shape<Program>(&self, program: Program) -> Program::Ty
where
Program: ShapeProgramAlg<This>,
{
program.compile_shape(self)
}
}
#[ext(name = ShapeDeclareExt, supertraits = Sorts + Sized)]
pub impl<This> This
where
This: ShapeAlg + FieldAlg,
{
fn record<'a>(&'a self, words: Words<'a>) -> Record<'a, Self> {
Record { alg: self, words, members: Vec::new() }
}
fn program<Program>(&self, program: Program) -> Self::Ty
where
Program: ShapeProgramAlg<Self, Ty = Self::Ty>,
{
program.compile_shape(self)
}
}
pub struct Record<'a, A>
where
A: Sorts,
{
alg: &'a A,
words: Words<'a>,
members: Vec<A::Field>,
}
impl<'a, A> Record<'a, A>
where
A: ShapeAlg + FieldAlg,
{
#[must_use]
pub fn field(mut self, words: Words<'_>, shape: A::Ty) -> Self {
self.members.push(self.alg.field(words, shape));
self
}
#[must_use]
pub fn field_as<Carrier>(mut self, words: Words<'_>, shape: A::Ty) -> Self {
self.members.push(self.alg.field(words, shape));
self
}
#[must_use]
pub fn field_of<Carrier>(mut self, words: Words<'_>) -> Self
where
Carrier: crate::ShapeOf<A, Shape = A::Ty>,
{
let shape = Carrier::shape_of(self.alg);
self.members.push(self.alg.field(words, shape));
self
}
#[must_use]
pub fn merge(mut self, shape: A::Ty) -> Self {
self.members.push(self.alg.merge(shape));
self
}
#[must_use]
pub fn into_shape(self) -> A::Ty {
self.alg.named_product(self.words, self.members)
}
}