use std::sync::Arc;
use super::mark::{Context, Drawing};
use crate::expr::compile::{Compiler, Fields, Program};
use crate::{Data, Error, Kind, Mark, Name, Result, Table};
pub(crate) struct Compiled {
pub(crate) program: Arc<Program>,
pub(crate) drawing: Drawing,
pub(crate) schemas: Vec<(Name, u64)>,
}
pub(crate) fn compile(mark: &Mark, all: &[Data], context: Context<'_>) -> Result<Option<Compiled>> {
let style = mark.style();
let Some(data) = all.iter().find(|d| *d.name() == style.data) else { return Ok(None) };
let Some(table) = data.table(&style.table) else { return Ok(None) };
let fields = Schema { table, all };
let mut compiler = Compiler::new(&fields);
let drawing = mark.compile(&mut compiler, context)?;
let program = compiler.finish();
if program.channels.len() > 32 {
return Err(Error::invalid("more than 32 options read data"));
}
let mut schemas = vec![(data.name().clone(), data.schema())];
for column in &program.columns {
if let Some((name, _)) = &column.of
&& !schemas.iter().any(|(n, _)| n == name)
&& let Some(other) = all.iter().find(|d| d.name() == name)
{
schemas.push((name.clone(), other.schema()));
}
}
Ok(Some(Compiled { program: Arc::new(program), drawing, schemas }))
}
struct Schema<'a> {
table: &'a Table,
all: &'a [Data],
}
impl Fields for Schema<'_> {
fn kind(&self, of: Option<&(Name, Name)>, name: &str) -> Option<Kind> {
match of {
None => self.table.kind(name),
Some((data, table)) => self.all.iter().find(|d| d.name() == data)?.table(table)?.kind(name),
}
}
fn target(&self, name: &str) -> Option<Name> {
match self.table.field_named(name)? {
crate::data::Field::Reference(reference) => Some(reference.to.clone()),
_ => None,
}
}
}