/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::collections::HashSet; use super::*; #[derive(Default, Clone)] pub struct Context { pub cdylib: Option, pub current_config: Option, pub module_namespace: Option, pub recursive_type_names: HashSet, pub builtin_types: Option, } impl Context { pub fn update_from_root(&mut self, root: &general::Root) -> Result<()> { self.cdylib = root.cdylib.clone(); self.builtin_types = Some(root.builtin_types.clone().map_node(self)?); Ok(()) } pub fn update_from_namespace(&mut self, namespace: &general::Namespace) -> Result<()> { self.current_config = Some(match &namespace.config_toml { Some(toml) => PythonConfig::from_uniffi_toml(toml)?, None => PythonConfig::default(), }); self.module_namespace = Some(namespace.name.clone()); let mut recursive_type_names = HashSet::new(); namespace.visit(|e: &general::Enum| { if e.recursive { recursive_type_names.insert(e.name.clone()); } }); namespace.visit(|r: &general::Record| { if r.recursive { recursive_type_names.insert(r.name.clone()); } }); self.recursive_type_names = recursive_type_names; Ok(()) } pub fn builtin_types(&self) -> Result { self.builtin_types .clone() .ok_or_else(|| anyhow!("Context.builtin_types not set")) } pub fn is_recursive(&self, name: &str) -> bool { self.recursive_type_names.contains(name) } pub fn module_namespace(&self) -> Result<&str> { self.module_namespace .as_deref() .ok_or_else(|| anyhow!("Context.module_namespace not set")) } pub fn config(&self) -> Result<&PythonConfig> { self.current_config .as_ref() .ok_or_else(|| anyhow!("Context.config not set")) } pub fn cdylib(&self) -> Result { let default_cdylib = self.cdylib.as_deref().unwrap_or("uniffi"); Ok(match &self.config()?.cdylib_name { Some(cdylib) => cdylib.clone(), None => default_cdylib.to_string(), }) } pub fn external_package_name(&self, namespace: &str) -> Result> { match &self.module_namespace { None => bail!("Config.module_namespace not set"), Some(current_namespace) if current_namespace == namespace => return Ok(None), _ => (), } let config = self.config()?; Ok(Some(match config.external_packages.get(namespace) { None => namespace.to_string(), Some(package_name) if package_name.is_empty() => namespace.to_string(), Some(package_name) => package_name.clone(), })) } pub fn custom_type_config( &self, custom: &general::CustomType, ) -> Result> { Ok(self.config()?.custom_types.get(&custom.orig_name).cloned()) } }