use std::fmt;
use std::rc::Rc;
use indexmap::IndexMap;
use crate::interner::Interned;
use crate::method::Method;
use crate::value::Value;
use crate::{SOMRef, SOMWeakRef};
#[derive(Debug, Clone)]
pub enum MaybeWeak<A> {
Strong(SOMRef<A>),
Weak(SOMWeakRef<A>),
}
#[derive(Clone)]
pub struct Class {
pub name: String,
pub class: MaybeWeak<Class>,
pub super_class: SOMWeakRef<Class>,
pub locals: IndexMap<Interned, Value>,
pub methods: IndexMap<Interned, Rc<Method>>,
pub is_static: bool,
}
impl Class {
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn class(&self) -> SOMRef<Self> {
match self.class {
MaybeWeak::Weak(ref weak) => weak.upgrade().unwrap_or_else(|| {
panic!("superclass dropped, cannot upgrade ref ({})", self.name())
}),
MaybeWeak::Strong(ref owned) => owned.clone(),
}
}
pub fn set_class(&mut self, class: &SOMRef<Self>) {
self.class = MaybeWeak::Weak(Rc::downgrade(class));
}
pub fn set_class_owned(&mut self, class: &SOMRef<Self>) {
self.class = MaybeWeak::Strong(class.clone());
}
pub fn super_class(&self) -> Option<SOMRef<Self>> {
self.super_class.upgrade()
}
pub fn set_super_class(&mut self, class: &SOMRef<Self>) {
self.super_class = Rc::downgrade(class);
}
pub fn lookup_method(&self, signature: Interned) -> Option<Rc<Method>> {
self.methods.get(&signature).cloned().or_else(|| {
self.super_class
.upgrade()?
.borrow()
.lookup_method(signature)
})
}
pub fn lookup_local(&self, idx: usize) -> Option<Value> {
self.locals.values().nth(idx).cloned().or_else(|| {
let super_class = self.super_class()?;
let local = super_class.borrow_mut().lookup_local(idx)?;
Some(local)
})
}
pub fn assign_local(&mut self, idx: usize, value: Value) -> Option<()> {
if let Some(local) = self.locals.values_mut().nth(idx) {
*local = value;
return Some(());
}
let super_class = self.super_class()?;
super_class.borrow_mut().assign_local(idx, value)?;
Some(())
}
}
impl fmt::Debug for Class {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Class")
.field("name", &self.name)
.finish()
}
}