use anyhow::{Context, Result};
use std::{collections::hash_map::Entry, collections::BTreeSet, collections::HashMap};
pub use uniffi_meta::{AsType, NamespaceMetadata, ObjectImpl, Type, TypeIterator};
#[derive(Clone, Debug, Default)]
pub(crate) struct TypeUniverse {
pub namespace: NamespaceMetadata,
pub namespace_docstring: Option<String>,
pub(super) type_definitions: HashMap<String, Type>,
pub(super) all_known_types: BTreeSet<Type>,
}
impl TypeUniverse {
pub fn new(namespace: NamespaceMetadata) -> Self {
Self {
namespace,
..Default::default()
}
}
fn add_type_definition(&mut self, name: &str, type_: &Type) -> Result<()> {
match self.type_definitions.entry(name.to_string()) {
Entry::Occupied(o) => {
let cur = o.get();
anyhow::ensure!(
type_ == cur,
"conflicting types:\ncur: {cur:?}\nnew: {type_:?}",
);
Ok(())
}
Entry::Vacant(e) => {
e.insert(type_.clone());
Ok(())
}
}
}
pub(super) fn get_type_definition(&self, name: &str) -> Option<Type> {
self.type_definitions.get(name).cloned()
}
pub fn add_known_type(&mut self, type_: &Type) -> Result<()> {
if !self.all_known_types.contains(type_) {
self.all_known_types.insert(type_.to_owned());
}
for sub in type_.iter_nested_types() {
self.add_known_type(sub)?;
}
if let Some(name) = type_.name() {
self.add_type_definition(name, type_)
.with_context(|| format!("adding named type {name}"))?;
}
Ok(())
}
pub fn add_known_types(&mut self, types: TypeIterator<'_>) -> Result<()> {
for t in types {
self.add_known_type(t)
.with_context(|| format!("adding type {t:?}"))?
}
Ok(())
}
pub fn is_external(&self, t: &Type) -> bool {
t.module_path()
.map(|p| p != self.namespace.crate_name)
.unwrap_or(false)
}
#[cfg(test)]
pub fn contains(&self, type_: &Type) -> bool {
self.all_known_types.contains(type_)
}
pub fn iter_local_types(&self) -> impl Iterator<Item = &Type> {
self.filter_local_types(self.all_known_types.iter())
}
pub fn iter_external_types(&self) -> impl Iterator<Item = &Type> {
self.all_known_types.iter().filter(|t| self.is_external(t))
}
pub fn filter_local_types<'a>(
&'a self,
types: impl Iterator<Item = &'a Type>,
) -> impl Iterator<Item = &'a Type> {
types.filter(|t| !self.is_external(t))
}
}
#[cfg(test)]
mod test_type_universe {
}