use crate::class::Class;
use std::{
cmp::Ordering,
error::Error,
fmt::{Debug, Display},
rc::Rc,
str::FromStr,
};
pub trait ObjectFromStr {
fn from_str(s: &str) -> Result<Rc<dyn Object>, Box<dyn Error + Send + Sync>>
where
Self: Sized;
}
impl<T: 'static + FromStr + Object> ObjectFromStr for T
where
T::Err: 'static + Error + Send + Sync,
{
fn from_str(s: &str) -> Result<Rc<dyn Object>, Box<dyn Error + Send + Sync>> {
<Self as FromStr>::from_str(s)
.map_err(Into::into)
.map(|o| Rc::new(o) as Rc<dyn Object>)
}
}
pub trait ObjectPartialEq {
fn eq(&self, other: Rc<dyn Object>) -> bool;
fn ne(&self, other: Rc<dyn Object>) -> bool {
!self.eq(other)
}
}
pub trait ObjectPartialOrd {
fn partial_cmp(&self, other: Rc<dyn Object>) -> Option<Ordering>;
fn lt(&self, other: Rc<dyn Object>) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Less))
}
fn le(&self, other: Rc<dyn Object>) -> bool {
matches!(
self.partial_cmp(other),
Some(Ordering::Less | Ordering::Equal)
)
}
fn gt(&self, other: Rc<dyn Object>) -> bool {
matches!(self.partial_cmp(other), Some(Ordering::Greater))
}
fn ge(&self, other: Rc<dyn Object>) -> bool {
matches!(
self.partial_cmp(other),
Some(Ordering::Greater | Ordering::Equal)
)
}
}
pub trait ObjectEq: ObjectPartialEq {}
pub trait ObjectOrd: ObjectEq + ObjectPartialOrd {
fn cmp(&self, other: Rc<dyn Object>) -> Ordering;
}
pub trait Object:
Display + Debug + ObjectFromStr + ObjectPartialEq + ObjectPartialOrd + ObjectEq + ObjectOrd
{
fn class(&self) -> Class;
fn as_string(&self) -> String {
self.to_string()
}
fn as_number(&self) -> f64;
fn as_bool(&self) -> bool;
fn get_field(&self, _field: Rc<dyn Object>) -> Rc<dyn Object> {
unimplemented!()
}
fn set_field(&mut self, _field: Rc<dyn Object>, _value: Rc<dyn Object>) {
unimplemented!()
}
fn cast_to(&self, to: &Class) -> Rc<dyn Object> {
if self.class().name == "any" {
(to.obj_from_str.unwrap())(&self.as_string()).unwrap()
} else {
unimplemented!()
}
}
}