use super::NativeConvertError;
use cadmpeg_core::decode::DecodeContext;
pub enum Phase<M, A, N, E> {
GroupA {
tag: Option<&'static str>,
note: NoteFn<M, A, N, E>,
},
GroupB {
tag: Option<&'static str>,
note: NoteFn<M, A, N, E>,
},
ArenaOnly,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NotePhase {
GroupA,
GroupB,
}
pub type NoteFn<M, A, N, E> = fn(
&DecodeContext<'_>,
&M,
&FamilyRow<M, A, N, E>,
Option<&'static str>,
&mut A,
) -> Result<(), cadmpeg_core::CodecError>;
pub type EmitFn<M, A, N, E> =
fn(&DecodeContext<'_>, &M, &FamilyRow<M, A, N, E>, &mut N) -> Result<(), NativeConvertError>;
pub struct FamilyRow<M, A, N, E> {
pub arena: &'static str,
pub exactness: E,
pub phase: Phase<M, A, N, E>,
pub emit: EmitFn<M, A, N, E>,
pub len: fn(&M) -> usize,
pub counts_toward_emptiness: bool,
}
pub struct Catalogue<'a, M, A, N, E> {
rows: &'a [FamilyRow<M, A, N, E>],
}
impl<'a, M, A, N, E> Catalogue<'a, M, A, N, E> {
pub const fn new(rows: &'a [FamilyRow<M, A, N, E>]) -> Self {
Self { rows }
}
pub fn emit_all(
&self,
ctx: &DecodeContext<'_>,
model: &M,
namespace: &mut N,
) -> Result<(), NativeConvertError> {
for row in self.rows {
(row.emit)(ctx, model, row, namespace)?;
}
Ok(())
}
pub fn note_phase(
&self,
ctx: &DecodeContext<'_>,
phase: NotePhase,
model: &M,
annotations: &mut A,
) -> Result<(), cadmpeg_core::CodecError> {
for row in self.rows {
match (&row.phase, phase) {
(Phase::GroupA { tag, note }, NotePhase::GroupA)
| (Phase::GroupB { tag, note }, NotePhase::GroupB) => {
note(ctx, model, row, *tag, annotations)?;
}
(Phase::GroupA { .. } | Phase::GroupB { .. } | Phase::ArenaOnly, _) => {}
}
}
Ok(())
}
pub fn is_empty(&self, model: &M) -> bool {
self.rows
.iter()
.filter(|row| row.counts_toward_emptiness)
.all(|row| (row.len)(model) == 0)
}
}