use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use crate::errors::OsoError;
use crate::Polar;
mod class;
mod class_method;
mod from_polar;
mod method;
mod to_polar;
mod value;
pub use class::{Class, ClassBuilder, Instance};
pub use from_polar::{FromPolar, FromPolarList};
use polar_core::terms::{Operator, Symbol};
pub use to_polar::{PolarIterator, ToPolar, ToPolarList};
pub use value::PolarValue;
lazy_static::lazy_static! {
static ref DEFAULT_CLASSES: Arc<RwLock<HashMap<std::any::TypeId, super::Class>>> = Default::default();
}
impl crate::PolarClass for Class {}
fn metaclass() -> Class {
Class::builder::<Class>().name("oso::host::Class").build()
}
#[derive(Clone)]
pub struct Host {
polar: Arc<Polar>,
classes: HashMap<String, Class>,
instances: HashMap<u64, class::Instance>,
class_names: HashMap<std::any::TypeId, String>,
pub accept_expression: bool,
}
impl Host {
pub fn new(polar: Arc<Polar>) -> Self {
let mut host = Self {
class_names: HashMap::new(),
classes: HashMap::new(),
instances: HashMap::new(),
accept_expression: false,
polar,
};
let type_class = metaclass();
let name = type_class.name.clone();
host.cache_class(type_class, name)
.expect("could not register the metaclass");
host
}
pub fn get_class(&self, name: &str) -> crate::Result<&Class> {
self.classes
.get(name)
.ok_or_else(|| OsoError::MissingClassError {
name: name.to_string(),
})
}
pub fn get_class_by_type_id(&self, id: std::any::TypeId) -> crate::Result<&Class> {
self.class_names
.get(&id)
.ok_or_else(|| OsoError::MissingClassError {
name: format!("TypeId: {:?}", id),
})
.and_then(|name| self.get_class(name))
}
pub fn get_class_mut(&mut self, name: &str) -> crate::Result<&mut Class> {
self.classes
.get_mut(name)
.ok_or_else(|| OsoError::MissingClassError {
name: name.to_string(),
})
}
pub fn cache_class(&mut self, class: Class, name: String) -> crate::Result<String> {
DEFAULT_CLASSES
.write()
.unwrap()
.entry(class.type_id)
.or_insert_with(|| class.clone());
if self.classes.contains_key(&name) {
Err(OsoError::DuplicateClassError { name })
} else {
self.class_names.insert(class.type_id, name.clone());
self.classes.insert(name.clone(), class);
Ok(name)
}
}
pub fn register_mros(&self) -> crate::Result<()> {
for name in self.classes.keys() {
if name != "oso::host::Class" {
self.polar.register_mro(Symbol(name.clone()), vec![])?;
}
}
Ok(())
}
pub fn get_instance(&self, id: u64) -> crate::Result<&class::Instance> {
tracing::trace!("instances: {:?}", self.instances.keys().collect::<Vec<_>>());
self.instances
.get(&id)
.ok_or(OsoError::MissingInstanceError)
}
pub fn cache_instance(&mut self, instance: class::Instance, id: Option<u64>) -> u64 {
let type_id = instance.type_id();
let class = self.get_class_by_type_id(type_id);
if class.is_err() {
let default_class = DEFAULT_CLASSES.read().unwrap().get(&type_id).cloned();
if let Some(class) = default_class {
let name = class.name.clone();
let _ = self.cache_class(class, name);
}
}
let id = id.unwrap_or_else(|| self.polar.get_external_id());
tracing::trace!(
"insert instance {:?} {:?}, instances: {:?}",
id,
instance,
self.instances.keys().collect::<Vec<_>>()
);
self.instances.insert(id, instance);
id
}
pub fn make_instance(
&mut self,
name: &str,
fields: Vec<PolarValue>,
id: u64,
) -> crate::Result<()> {
let class = self.get_class(name)?.clone();
debug_assert!(self.instances.get(&id).is_none());
let fields = fields;
let instance = class.init(fields)?;
self.cache_instance(instance, Some(id));
Ok(())
}
pub fn isa(&self, value: PolarValue, class_tag: &str) -> crate::Result<bool> {
let res = match value {
PolarValue::Instance(instance) => {
let class = self.get_class(class_tag)?;
instance.instance_of(class)
}
PolarValue::Boolean(_) => class_tag == "Boolean",
PolarValue::Map(_) => class_tag == "Dictionary",
PolarValue::List(_) => class_tag == "List",
PolarValue::Integer(_) => class_tag == "Integer",
PolarValue::Float(_) => class_tag == "Float",
PolarValue::String(_) => class_tag == "String",
_ => false,
};
Ok(res)
}
pub fn is_subspecializer(&self, _id: u64, _left_tag: &str, _right_tag: &str) -> bool {
false
}
pub fn operator(&self, op: Operator, args: [class::Instance; 2]) -> crate::Result<bool> {
match op {
Operator::Eq => args[0].equals(&args[1], self),
_ => Err(OsoError::UnimplementedOperation {
operation: String::from("comparison operators"),
}),
}
}
}