use crate::ast::{PortType, Value};
#[derive(Debug, Clone, PartialEq)]
pub enum WriteError {
UnknownWire { key: String },
TypeMismatch {
slot: String,
expected: PortType,
got: PortType,
},
}
impl std::fmt::Display for WriteError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WriteError::UnknownWire { key } => {
write!(f, "unknown wire '{key}': no input slot by this name")
}
WriteError::TypeMismatch { slot, expected, got } => {
write!(
f,
"type mismatch writing to slot '{slot}': expected {expected:?}, got {got:?} (no auto-adapter available)"
)?;
if matches!(got, PortType::VecF32 | PortType::VecI32)
&& !matches!(expected, PortType::VecF32 | PortType::VecI32
| PortType::Str | PortType::Bytes | PortType::Json)
{
write!(
f,
" — collection → scalar requires an explicit \
choice; use `vec_len(v)` for the element \
count, `vec_first(v)` / `vec_last(v)` for an \
element, `vec_sum(v)` / `vec_mean(v)` for an \
aggregate"
)?;
}
Ok(())
}
}
}
}
impl std::error::Error for WriteError {}
pub trait WireKey: sealed::Sealed {
fn resolve<M: Metadata + ?Sized>(self, metadata: &M) -> Option<usize>;
fn describe(&self) -> String;
}
mod sealed {
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for &str {}
impl Sealed for String {}
impl Sealed for &String {}
}
impl WireKey for usize {
#[inline]
fn resolve<M: Metadata + ?Sized>(self, _: &M) -> Option<usize> {
Some(self)
}
#[inline]
fn describe(&self) -> String { format!("wire[{self}]") }
}
impl WireKey for &str {
#[inline]
fn resolve<M: Metadata + ?Sized>(self, metadata: &M) -> Option<usize> {
metadata.find_input(self)
}
#[inline]
fn describe(&self) -> String { (*self).to_string() }
}
impl WireKey for String {
#[inline]
fn resolve<M: Metadata + ?Sized>(self, metadata: &M) -> Option<usize> {
metadata.find_input(&self)
}
#[inline]
fn describe(&self) -> String { self.clone() }
}
impl WireKey for &String {
#[inline]
fn resolve<M: Metadata + ?Sized>(self, metadata: &M) -> Option<usize> {
metadata.find_input(self)
}
#[inline]
fn describe(&self) -> String { (*self).clone() }
}
pub trait Metadata {
fn find_input(&self, name: &str) -> Option<usize>;
fn input_names(&self) -> Vec<String>;
fn output_names(&self) -> Vec<String>;
fn coord_count(&self) -> usize;
fn input_port_type(&self, name: &str) -> Option<PortType>;
fn input_port_type_by_idx(&self, idx: usize) -> Option<PortType>;
fn output_port_type(&self, name: &str) -> Option<PortType>;
}
pub trait Dataflow: Metadata {
fn set_wire_idx(&mut self, idx: usize, value: Value) -> Result<(), WriteError>;
fn get_wire_idx(&self, idx: usize) -> Value;
#[inline]
fn set_wire<W: WireKey>(&mut self, key: W, value: Value) -> Result<(), WriteError> {
let key_desc = key.describe();
match key.resolve(self) {
Some(idx) => self.set_wire_idx(idx, value),
None => Err(WriteError::UnknownWire { key: key_desc }),
}
}
#[inline]
fn get_wire<W: WireKey>(&self, key: W) -> Option<Value> {
key.resolve(self).map(|idx| self.get_wire_idx(idx))
}
}
pub trait Construction: Sized {
type Error;
fn root(matter: super::subcontext::PolydatMatter<'_>) -> Result<Self, Self::Error>;
fn subscope(&self, matter: super::subcontext::PolydatMatter<'_>)
-> Result<Self, Self::Error>;
}