use super::{FieldDef, MemberDef, PendingType, RecGroupBuilder, SuperDef, ValDef};
use crate::value::{ArrayType, FieldType, Finality, FuncType, Mutability, StructType, ValType};
const MAX_FIELDS: usize = 10_000;
pub struct StructTypeBuilder<'a> {
rec: &'a mut RecGroupBuilder,
index: u32,
finality: Finality,
supertype: Option<SuperDef>,
fields: Vec<FieldDef>,
}
impl<'a> StructTypeBuilder<'a> {
pub(super) fn new(rec: &'a mut RecGroupBuilder, index: u32) -> Self {
StructTypeBuilder {
rec,
index,
finality: Finality::Final,
supertype: None,
fields: Vec::new(),
}
}
pub fn finality(&mut self, finality: Finality) -> &mut Self {
self.finality = finality;
self
}
pub fn supertype(&mut self, supertype: StructType) -> &mut Self {
let same = supertype.engine().same(&self.rec.engine);
self.rec.check_engine(same, "supertype");
self.supertype = Some(SuperDef::Struct(supertype));
self
}
#[track_caller]
pub fn forward_supertype(&mut self, supertype: PendingType) -> &mut Self {
self.rec.check_owns(supertype);
self.supertype = Some(SuperDef::Forward(supertype.index));
self
}
pub fn field(&mut self, ty: FieldType) -> &mut Self {
self.rec.check_field_engine(&ty, "field type");
self.fields.push(FieldDef::Registered(ty));
self
}
#[track_caller]
pub fn forward_ref_field(&mut self, ty: PendingType) -> ForwardRefFieldBuilder<'_, 'a> {
self.rec.check_owns(ty);
ForwardRefFieldBuilder {
parent: self,
target: ty,
mutability: Mutability::Const,
nullable: true,
}
}
pub fn finish(&mut self) {
let fields = core::mem::take(&mut self.fields);
if fields.len() > MAX_FIELDS {
self.rec.record_error(crate::format_err!(
"attempted to define a struct type with {} fields, but that is more than the \
maximum supported number of fields ({MAX_FIELDS})",
fields.len(),
));
return;
}
self.rec.members[self.index as usize] = Some(MemberDef::Struct {
finality: self.finality,
supertype: self.supertype.take(),
fields,
});
}
}
pub struct ForwardRefFieldBuilder<'p, 'a> {
parent: &'p mut StructTypeBuilder<'a>,
target: PendingType,
mutability: Mutability,
nullable: bool,
}
impl<'p, 'a> ForwardRefFieldBuilder<'p, 'a> {
pub fn mutability(mut self, mutability: Mutability) -> Self {
self.mutability = mutability;
self
}
pub fn nullable(mut self, is_nullable: bool) -> Self {
self.nullable = is_nullable;
self
}
pub fn finish(self) -> &'p mut StructTypeBuilder<'a> {
self.parent.fields.push(FieldDef::Forward {
target: self.target,
mutable: matches!(self.mutability, Mutability::Var),
nullable: self.nullable,
});
self.parent
}
}
pub struct ArrayTypeBuilder<'a> {
rec: &'a mut RecGroupBuilder,
index: u32,
finality: Finality,
supertype: Option<SuperDef>,
element: Option<FieldDef>,
}
impl<'a> ArrayTypeBuilder<'a> {
pub(super) fn new(rec: &'a mut RecGroupBuilder, index: u32) -> Self {
ArrayTypeBuilder {
rec,
index,
finality: Finality::Final,
supertype: None,
element: None,
}
}
pub fn finality(&mut self, finality: Finality) -> &mut Self {
self.finality = finality;
self
}
pub fn supertype(&mut self, supertype: ArrayType) -> &mut Self {
let same = supertype.engine().same(&self.rec.engine);
self.rec.check_engine(same, "supertype");
self.supertype = Some(SuperDef::Array(supertype));
self
}
#[track_caller]
pub fn forward_supertype(&mut self, supertype: PendingType) -> &mut Self {
self.rec.check_owns(supertype);
self.supertype = Some(SuperDef::Forward(supertype.index));
self
}
pub fn element(&mut self, ty: FieldType) -> &mut Self {
self.rec.check_field_engine(&ty, "element type");
self.element = Some(FieldDef::Registered(ty));
self
}
#[track_caller]
pub fn forward_ref_element(&mut self, ty: PendingType) -> ForwardRefElementBuilder<'_, 'a> {
self.rec.check_owns(ty);
ForwardRefElementBuilder {
parent: self,
target: ty,
mutability: Mutability::Const,
nullable: true,
}
}
pub fn finish(&mut self) {
let index = self.index as usize;
let Some(element) = self.element.take() else {
self.rec.record_error(crate::format_err!(
"array type {index} was declared but its element type was never set"
));
return;
};
self.rec.members[index] = Some(MemberDef::Array {
finality: self.finality,
supertype: self.supertype.take(),
element,
});
}
}
pub struct ForwardRefElementBuilder<'p, 'a> {
parent: &'p mut ArrayTypeBuilder<'a>,
target: PendingType,
mutability: Mutability,
nullable: bool,
}
impl<'p, 'a> ForwardRefElementBuilder<'p, 'a> {
pub fn mutability(mut self, mutability: Mutability) -> Self {
self.mutability = mutability;
self
}
pub fn nullable(mut self, is_nullable: bool) -> Self {
self.nullable = is_nullable;
self
}
pub fn finish(self) -> &'p mut ArrayTypeBuilder<'a> {
self.parent.element = Some(FieldDef::Forward {
target: self.target,
mutable: matches!(self.mutability, Mutability::Var),
nullable: self.nullable,
});
self.parent
}
}
pub struct FuncTypeBuilder<'a> {
rec: &'a mut RecGroupBuilder,
index: u32,
finality: Finality,
supertype: Option<SuperDef>,
params: Vec<ValDef>,
results: Vec<ValDef>,
}
impl<'a> FuncTypeBuilder<'a> {
pub(super) fn new(rec: &'a mut RecGroupBuilder, index: u32) -> Self {
FuncTypeBuilder {
rec,
index,
finality: Finality::Final,
supertype: None,
params: Vec::new(),
results: Vec::new(),
}
}
pub fn finality(&mut self, finality: Finality) -> &mut Self {
self.finality = finality;
self
}
pub fn supertype(&mut self, supertype: FuncType) -> &mut Self {
let same = supertype.engine().same(&self.rec.engine);
self.rec.check_engine(same, "supertype");
self.supertype = Some(SuperDef::Func(supertype));
self
}
#[track_caller]
pub fn forward_supertype(&mut self, supertype: PendingType) -> &mut Self {
self.rec.check_owns(supertype);
self.supertype = Some(SuperDef::Forward(supertype.index));
self
}
pub fn param(&mut self, ty: ValType) -> &mut Self {
self.rec.check_val_engine(&ty, "type");
self.params.push(ValDef::Registered(ty));
self
}
pub fn result(&mut self, ty: ValType) -> &mut Self {
self.rec.check_val_engine(&ty, "type");
self.results.push(ValDef::Registered(ty));
self
}
#[track_caller]
pub fn forward_ref_param(&mut self, ty: PendingType) -> ForwardRefFuncValBuilder<'_, 'a> {
self.rec.check_owns(ty);
ForwardRefFuncValBuilder {
parent: self,
target: ty,
nullable: true,
is_result: false,
}
}
#[track_caller]
pub fn forward_ref_result(&mut self, ty: PendingType) -> ForwardRefFuncValBuilder<'_, 'a> {
self.rec.check_owns(ty);
ForwardRefFuncValBuilder {
parent: self,
target: ty,
nullable: true,
is_result: true,
}
}
pub fn finish(&mut self) {
self.rec.members[self.index as usize] = Some(MemberDef::Func {
finality: self.finality,
supertype: self.supertype.take(),
params: core::mem::take(&mut self.params),
results: core::mem::take(&mut self.results),
});
}
}
pub struct ForwardRefFuncValBuilder<'p, 'a> {
parent: &'p mut FuncTypeBuilder<'a>,
target: PendingType,
nullable: bool,
is_result: bool,
}
impl<'p, 'a> ForwardRefFuncValBuilder<'p, 'a> {
pub fn nullable(mut self, is_nullable: bool) -> Self {
self.nullable = is_nullable;
self
}
pub fn finish(self) -> &'p mut FuncTypeBuilder<'a> {
let val = ValDef::Forward {
target: self.target,
nullable: self.nullable,
};
if self.is_result {
self.parent.results.push(val);
} else {
self.parent.params.push(val);
}
self.parent
}
}
macro_rules! builder_debug {
($ty:ident) => {
impl core::fmt::Debug for $ty<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(stringify!($ty))
.field("index", &self.index)
.finish_non_exhaustive()
}
}
};
}
macro_rules! forward_ref_debug {
($ty:ident) => {
impl core::fmt::Debug for $ty<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(stringify!($ty))
.field("target", &self.target)
.finish_non_exhaustive()
}
}
};
}
builder_debug!(StructTypeBuilder);
builder_debug!(ArrayTypeBuilder);
builder_debug!(FuncTypeBuilder);
forward_ref_debug!(ForwardRefFieldBuilder);
forward_ref_debug!(ForwardRefElementBuilder);
forward_ref_debug!(ForwardRefFuncValBuilder);