use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use std::marker::PhantomData;
use std::rc::Rc;
use crate::error::Error;
use crate::exec::ExecError;
use crate::function::value_is;
use crate::name::{Name, NameMapSlice, NameStore};
use crate::scope::Scope;
use crate::value::{ForeignValue, Value};
pub trait StructValue: Sized + Clone + ForeignValue {
fn struct_name() -> &'static str;
fn from_fields(scope: &Scope, def: &Rc<StructDef>,
fields: &mut [(Name, Value)]) -> Result<Self, Error>;
fn field_names() -> &'static [&'static str];
fn get_field(&self, scope: &Scope, def: &Rc<StructDef>, name: Name) -> Result<Value, Error>;
fn replace_fields(&mut self, scope: &Scope, def: &Rc<StructDef>,
fields: &mut [(Name, Value)]) -> Result<(), Error>;
}
pub trait StructDefinition: Any {
fn is_instance(&self, value: &Value, def: &Rc<StructDef>) -> bool;
fn from_fields(&self, scope: &Scope, def: &Rc<StructDef>,
fields: &mut [(Name, Value)]) -> Result<Value, Error>;
fn get_field(&self, scope: &Scope, def: &Rc<StructDef>,
value: &Value, field: Name) -> Result<Value, Error>;
fn field_names(&self) -> Vec<Name>;
fn replace_fields(&self, scope: &Scope, def: &Rc<StructDef>,
value: Value, fields: &mut [(Name, Value)]) -> Result<Value, Error>;
fn size(&self) -> usize { 2 }
}
impl_any_cast!{ StructDefinition }
pub struct ForeignStructDef<T> {
fields: Vec<Name>,
data: PhantomData<T>,
}
impl<T: StructValue> ForeignStructDef<T> {
pub fn new(names: &mut NameStore) -> ForeignStructDef<T> {
ForeignStructDef{
fields: T::field_names().iter().map(|s| names.add(s)).collect(),
data: PhantomData,
}
}
fn get<'a>(&self, value: &'a Value) -> &'a T {
match *value {
Value::Foreign(ref fv) => {
fv.downcast_ref::<T>()
.expect("invalid foreign value for ForeignStructDef")
}
_ => panic!("invalid value for ForeignStructDef")
}
}
fn get_rc(&self, value: Value) -> Rc<T> {
match value {
Value::Foreign(fv) => {
ForeignValue::downcast_rc::<T>(fv)
.expect("invalid foreign value for ForeignStructDef")
}
_ => panic!("invalid value for ForeignStructDef")
}
}
}
impl<T: StructValue> StructDefinition for ForeignStructDef<T> {
fn is_instance(&self, value: &Value, _def: &Rc<StructDef>) -> bool {
match *value {
Value::Foreign(ref fv) => fv.is::<T>(),
_ => false
}
}
fn from_fields(&self, scope: &Scope, def: &Rc<StructDef>,
fields: &mut [(Name, Value)]) -> Result<Value, Error> {
T::from_fields(scope, def, fields).map(Value::new_foreign)
}
fn get_field(&self, scope: &Scope, def: &Rc<StructDef>, value: &Value, field: Name) -> Result<Value, Error> {
let v = self.get(value);
v.get_field(scope, def, field)
}
fn field_names(&self) -> Vec<Name> {
self.fields.clone()
}
fn replace_fields(&self, scope: &Scope, def: &Rc<StructDef>,
value: Value, fields: &mut [(Name, Value)]) -> Result<Value, Error> {
let mut v = self.get_rc(value);
Rc::make_mut(&mut v).replace_fields(scope, def, fields)?;
Ok(Value::Foreign(v))
}
}
pub struct StructValueDef {
fields: NameMapSlice<Name>,
}
impl StructValueDef {
pub fn new(fields: NameMapSlice<Name>) -> StructValueDef {
StructValueDef{ fields }
}
pub fn fields(&self) -> &NameMapSlice<Name> {
&self.fields
}
fn get(&self, name: Name, def: &Rc<StructDef>) -> Result<(usize, Name), ExecError> {
self.fields.iter().enumerate()
.find(|&(_, &(n, _))| n == name)
.map(|(i, &(_, ty))| (i, ty))
.ok_or_else(|| ExecError::FieldError{
struct_name: def.name(),
field: name,
})
}
}
impl StructDefinition for StructValueDef {
fn is_instance(&self, value: &Value, def: &Rc<StructDef>) -> bool {
match *value {
Value::Struct(ref s) => s.def() == def,
_ => false
}
}
fn from_fields(&self, scope: &Scope, def: &Rc<StructDef>, fields: &mut [(Name, Value)]) -> Result<Value, Error> {
let mut res = vec![Value::Unbound; self.fields.len()];
for &mut (name, ref mut value) in fields {
let (idx, ty) = self.get(name, def)?;
if !value_is(scope, value, ty) {
return Err(ExecError::FieldTypeError{
struct_name: def.name(),
field: name,
expected: ty,
found: value.type_name(),
value: Some(value.take()),
}.into());
}
res[idx] = value.take();
}
for (i, field) in res.iter().enumerate() {
if let Value::Unbound = *field {
let name = self.fields.values()[i].0;
return Err(ExecError::MissingField{
struct_name: def.name(),
field: name,
}.into());
}
}
Ok(Value::Struct(Rc::new(Struct::new(def.clone(), res.into_boxed_slice()))))
}
fn get_field(&self, _scope: &Scope, def: &Rc<StructDef>,
value: &Value, field: Name) -> Result<Value, Error> {
match *value {
Value::Struct(ref v) => {
let (idx, _) = self.get(field, def)?;
Ok(v.fields[idx].clone())
}
ref v => Err(ExecError::expected("struct", v).into())
}
}
fn field_names(&self) -> Vec<Name> {
self.fields.iter().map(|&(name, _)| name).collect()
}
fn replace_fields(&self, scope: &Scope, def: &Rc<StructDef>,
value: Value, fields: &mut [(Name, Value)]) -> Result<Value, Error> {
let mut struc = match value {
Value::Struct(s) => s,
ref v => return Err(ExecError::expected("struct", v).into())
};
{
let struc_inner = Rc::make_mut(&mut struc);
let values = struc_inner.fields_mut();
for &mut (name, ref mut value) in fields {
let (idx, ty) = self.get(name, def)?;
if !value_is(scope, value, ty) {
return Err(ExecError::FieldTypeError{
struct_name: def.name(),
field: name,
expected: ty,
found: value.type_name(),
value: Some(value.take()),
}.into());
}
values[idx] = value.take();
}
}
Ok(Value::Struct(struc))
}
fn size(&self) -> usize {
2 + self.fields.len()
}
}
#[derive(Clone, Debug)]
pub struct Struct {
def: Rc<StructDef>,
fields: Box<[Value]>,
}
impl Struct {
pub fn new(def: Rc<StructDef>, fields: Box<[Value]>) -> Struct {
Struct{ def, fields }
}
pub fn def(&self) -> &Rc<StructDef> {
&self.def
}
pub fn fields(&self) -> &[Value] {
&self.fields
}
pub fn fields_mut(&mut self) -> &mut [Value] {
&mut self.fields
}
}
pub struct StructDef {
name: Name,
def: Box<dyn StructDefinition>,
}
impl fmt::Debug for StructDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("StructDef")
.field("name", &self.name)
.finish()
}
}
impl Eq for StructDef {}
impl PartialEq for StructDef {
fn eq(&self, rhs: &StructDef) -> bool {
ptr_eq(self, rhs)
}
}
pub type StructDefMap = HashMap<TypeId, Rc<StructDef>>;
fn ptr_eq<T>(a: *const T, b: *const T) -> bool {
a == b
}
impl StructDef {
pub fn new(name: Name, def: Box<dyn StructDefinition>) -> StructDef {
StructDef{ name, def }
}
pub fn name(&self) -> Name {
self.name
}
pub fn def(&self) -> &dyn StructDefinition {
&*self.def
}
}