use std::collections::{HashMap, HashSet};
use super::*;
pub struct RegistryBuilder<M> {
registry: Registry<M>,
built: HashMap<Crossing, TypeEntry<M>>,
order: Option<Vec<Crossing>>,
}
impl<M> Registry<M> {
pub fn builder(flat: prebindgen_flat::flat::Flat) -> Result<RegistryBuilder<M>, ScanError> {
let entries: Vec<NotExpressibleEntry> = flat
.unsupported()
.map(|u| NotExpressibleEntry {
name: u.name.clone(),
reason: u.error.to_string(),
location: (*u.origin.location).clone(),
})
.collect();
if !entries.is_empty() {
return Err(ScanError::NotExpressible { entries });
}
let mut registry = Registry::empty();
registry.flat = flat;
Ok(RegistryBuilder {
registry,
built: HashMap::new(),
order: None,
})
}
}
impl<M> RegistryBuilder<M> {
pub fn export(mut self, name: &syn::Ident) -> Self {
self.registry.declared.functions.insert(name.clone());
self
}
pub fn export_const(mut self, name: &syn::Ident) -> Self {
self.registry
.declared
.consts
.get_or_insert_with(HashSet::new)
.insert(name.clone());
self
}
pub fn declares_consts(mut self) -> Self {
self.registry
.declared
.consts
.get_or_insert_with(HashSet::new);
self
}
pub fn export_type(mut self, ty: Origin<syn::Type>) -> Self {
self.registry.declared.types.entry(ty.key()).or_insert(ty);
self
}
pub fn cross(mut self, dir: Direction, ty: &syn::Type) -> Self {
self.registry.declared.crossings.push((dir, ty.clone()));
self
}
pub fn depends(mut self, from: Crossing, on: Crossing) -> Self {
self.registry.declared.edges.push((from, on));
self
}
pub fn reference(mut self, name: &syn::Ident) -> Self {
self.registry.declared.helper_functions.insert(name.clone());
self
}
pub fn local_function(
mut self,
item_fn: syn::ItemFn,
origin: String,
) -> Result<Self, ScanError> {
let ident = item_fn.sig.ident.clone();
let lowered = self
.registry
.flat
.lower_signature(&item_fn)
.map_err(|error| ScanError::AdapterInvariant {
message: format!("binding-local fn `{ident}`: {error}"),
})?;
if self.registry.flat.element(&ident).is_some() {
return Err(ScanError::AdapterInvariant {
message: format!(
"binding-local fn `{ident}` collides with a `#[prebindgen]` item — \
the generated call would resolve the wrong fn; rename the \
binding-local fn"
),
});
}
self.registry.flat.add_local_function(lowered, origin);
Ok(self)
}
pub fn accessor(mut self, name: &syn::Ident) -> Self {
self.registry.declared.accessors.insert(name.clone());
self
}
pub fn method_receiver(mut self, name: &syn::Ident, receiver: TypeKey) -> Self {
self.registry
.declared
.method_receivers
.insert(name.clone(), receiver);
self
}
pub fn decompose(mut self, d: Decompositions) -> Self {
self.registry.declared.decompositions = d;
self
}
}
impl<M> RegistryBuilder<M> {
pub fn flat(&self) -> &prebindgen_flat::flat::Flat {
&self.registry.flat
}
pub fn all_source_modules(&self) -> Vec<syn::Path> {
self.registry.all_source_modules()
}
pub fn origin_module(&self, ident: &syn::Ident) -> Option<syn::Path> {
self.registry.origin_module(ident)
}
pub fn default_module(&self) -> Option<syn::Path> {
self.registry.default_module()
}
pub fn named_item_idents(&self) -> impl Iterator<Item = &syn::Ident> {
self.registry.named_item_idents()
}
#[cfg(test)]
pub(crate) fn declares_type(&self, ident: &syn::Ident) -> bool {
self.registry.declares_type(ident)
}
fn derive(&mut self) -> Result<&[Crossing], WriteRustError> {
if self.order.is_none() {
let mut declared = std::mem::take(&mut self.registry.declared);
let out = (|| {
self.registry.scan_declared_items(&declared)?;
self.registry.apply_adapter_plans(&mut declared)
})();
self.registry.declared = declared;
out?;
self.order = Some(self.registry.crossings());
}
Ok(self.order.as_deref().unwrap_or_default())
}
fn view(&self) -> Building<'_, M> {
Building::new(
&self.registry,
&self.built,
self.order.as_deref().unwrap_or_default(),
)
}
pub fn validate_with<E>(mut self, adapter: &E) -> Result<Self, WriteRustError>
where
E: Prebindgen<Metadata = M>,
{
self.derive()?;
adapter
.validate(&self.view())
.map_err(|message| ScanError::AdapterInvariant { message })?;
Ok(self)
}
pub fn crossings(&mut self) -> Result<Vec<Crossing>, WriteRustError> {
Ok(self.derive()?.to_vec())
}
pub fn convert_with<F>(mut self, mut f: F) -> Result<Self, WriteRustError>
where
F: FnMut(
&Crossing,
&Building<'_, M>,
&prebindgen_flat::Emit,
) -> Option<crate::prebindgen::ConverterImpl<M>>,
{
let emit = prebindgen_flat::Emit::new();
let order = self.derive()?.to_vec();
for crossing in &order {
let conv = f(crossing, &self.view(), &emit);
if let Some(c) = conv {
self.built
.insert(crossing.clone(), TypeEntry::from_converter(c));
}
}
Ok(self)
}
pub fn conversions(mut self, conversions: HashMap<Crossing, TypeEntry<M>>) -> Self {
self.built.extend(conversions);
self
}
#[cfg(test)]
pub(crate) fn scanned(mut self) -> Result<Registry<M>, ScanError> {
match self.derive() {
Ok(_) => Ok(self.registry),
Err(WriteRustError::Scan(e)) => Err(e),
Err(other) => panic!("scanned(): unexpected non-scan failure: {other}"),
}
}
pub fn build(mut self) -> Result<Registry<M>, WriteRustError> {
self.derive()?;
for ((dir, key), entry) in self.built {
if let Some(cell) = self.registry.type_table_mut(dir).get_mut(&key) {
cell.entry = Some(entry);
}
}
crate::resolve::check_complete(&self.registry)?;
Ok(self.registry)
}
}
impl<M> Conversions<M> for RegistryBuilder<M> {
fn reading(&self, key: &TypeKey) -> Option<prebindgen_flat::flat::TypeRef> {
self.registry.reading(key)
}
fn flat(&self) -> &prebindgen_flat::flat::Flat {
&self.registry.flat
}
fn conversion(
&self,
dir: Direction,
reading: &prebindgen_flat::flat::TypeRef,
) -> Option<&TypeEntry<M>> {
self.built.get(&(dir, reading.key()))
}
fn crossing_keys(&self, dir: Direction) -> Vec<TypeKey> {
self.order
.as_deref()
.unwrap_or_default()
.iter()
.filter(|(d, _)| *d == dir)
.map(|(_, k)| k.clone())
.collect()
}
fn callback_arg_plan(&self, key: &TypeKey) -> Option<&crate::unfold::UnfoldPlan> {
self.registry.callback_arg_plans.get(key)
}
fn callback_arg_plans(&self) -> &HashMap<TypeKey, crate::unfold::UnfoldPlan> {
&self.registry.callback_arg_plans
}
fn unfold_plans(&self) -> &HashMap<syn::Ident, crate::unfold::UnfoldPlan> {
&self.registry.unfold_plans
}
fn error_plans(&self) -> &HashMap<syn::Ident, crate::unfold::UnfoldPlan> {
&self.registry.error_plans
}
fn decon_plans(&self) -> &HashMap<crate::unfold::DeconId, crate::unfold::DeconSpec> {
&self.registry.decon_plans
}
}