use std::convert::From;
use binding::class;
use binding::global::rb_cObject;
use binding::util as binding_util;
use typed_data::DataTypeWrapper;
use types::{Value, ValueType};
use util;
use {AnyObject, Array, Object, VerifiedObject};
#[derive(Debug, PartialEq)]
pub struct Class {
value: Value,
}
impl Class {
pub fn new(name: &str, superclass: Option<&Self>) -> Self {
let superclass = Self::superclass_to_value(superclass);
Self::from(class::define_class(name, superclass))
}
pub fn from_existing(name: &str) -> Self {
let object_class = unsafe { rb_cObject };
Self::from(binding_util::get_constant(name, object_class))
}
pub fn new_instance(&self, arguments: Vec<AnyObject>) -> AnyObject {
let (argc, argv) = util::create_arguments(arguments);
let instance = class::new_instance(self.value(), argc, argv.as_ptr());
AnyObject::from(instance)
}
pub fn superclass(&self) -> Option<Class> {
let superclass_value = class::superclass(self.value());
if superclass_value.is_nil() {
None
} else {
Some(Self::from(superclass_value))
}
}
pub fn ancestors(&self) -> Vec<Class> {
let ancestors = Array::from(class::ancestors(self.value()));
ancestors.into_iter()
.map(|class| unsafe { class.to::<Self>() })
.collect()
}
pub fn get_nested_class(&self, name: &str) -> Self {
Self::from(binding_util::get_constant(name, self.value()))
}
pub fn define_nested_class(&mut self, name: &str, superclass: Option<&Class>) -> Self {
let superclass = Self::superclass_to_value(superclass);
Self::from(class::define_nested_class(self.value(), name, superclass))
}
pub fn const_get(&self, name: &str) -> AnyObject {
let value = class::const_get(self.value(), name);
AnyObject::from(value)
}
pub fn const_set<T: Object>(&mut self, name: &str, value: &T) {
class::const_set(self.value(), name, value.value());
}
pub fn attr_reader(&mut self, name: &str) {
class::define_attribute(self.value(), name, true, false);
}
pub fn attr_writer(&mut self, name: &str) {
class::define_attribute(self.value(), name, false, true);
}
pub fn attr_accessor(&mut self, name: &str) {
class::define_attribute(self.value(), name, true, true);
}
pub fn wrap_data<T, O: Object>(&self, data: T, wrapper: &DataTypeWrapper<T>) -> O {
let value = class::wrap_data(self.value(), data, wrapper);
O::from(value)
}
fn superclass_to_value(superclass: Option<&Class>) -> Value {
match superclass {
Some(class) => class.value(),
None => unsafe { rb_cObject },
}
}
}
impl From<Value> for Class {
fn from(value: Value) -> Self {
Class { value: value }
}
}
impl Object for Class {
#[inline]
fn value(&self) -> Value {
self.value
}
}
impl VerifiedObject for Class {
fn is_correct_type<T: Object>(object: &T) -> bool {
object.value().ty() == ValueType::Class
}
fn error_message() -> &'static str {
"Error converting to Class"
}
}