use std::any::Any;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::fmt;
use std::hash::Hash;
use std::sync::Arc;
use crate::error::{Error, ErrorKind};
use crate::value::{mapped_enumerator, Value, ValueRepr};
use crate::vm::State;
pub trait Object: fmt::Debug + Send + Sync {
fn repr(self: &Arc<Self>) -> ObjectRepr {
ObjectRepr::Map
}
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
let _ = key;
None
}
fn get_value_by_str(self: &Arc<Self>, key: &str) -> Option<Value> {
self.get_value(&Value::from(key))
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
match self.repr() {
ObjectRepr::Plain => Enumerator::NonEnumerable,
ObjectRepr::Iterable | ObjectRepr::Map | ObjectRepr::Seq => Enumerator::Empty,
}
}
fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
self.enumerate().query_len()
}
fn is_true(self: &Arc<Self>) -> bool {
self.enumerator_len() != Some(0)
}
fn call(self: &Arc<Self>, state: &State<'_, '_>, args: &[Value]) -> Result<Value, Error> {
let (_, _) = (state, args);
Err(Error::new(
ErrorKind::InvalidOperation,
"object is not callable",
))
}
fn call_method(
self: &Arc<Self>,
state: &State<'_, '_>,
method: &str,
args: &[Value],
) -> Result<Value, Error> {
if let Some(value) = self.get_value(&Value::from(method)) {
return value.call(state, args);
}
Err(Error::from(ErrorKind::UnknownMethod))
}
fn custom_cmp(self: &Arc<Self>, other: &DynObject) -> Option<Ordering> {
let _ = other;
None
}
fn render(self: &Arc<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
Self: Sized + 'static,
{
match self.repr() {
ObjectRepr::Map => {
let mut dbg = f.debug_map();
for (key, value) in self.try_iter_pairs().into_iter().flatten() {
dbg.entry(&key, &value);
}
dbg.finish()
}
ObjectRepr::Seq | ObjectRepr::Iterable if self.enumerator_len().is_some() => {
let mut dbg = f.debug_list();
for value in self.try_iter().into_iter().flatten() {
dbg.entry(&value);
}
dbg.finish()
}
_ => {
write!(f, "{self:?}")
}
}
}
}
macro_rules! impl_object_helpers {
($vis:vis $self_ty: ty) => {
$vis fn try_iter(self: $self_ty) -> Option<Box<dyn Iterator<Item = Value> + Send + Sync>>
where
Self: 'static,
{
match self.enumerate() {
Enumerator::NonEnumerable => None,
Enumerator::Empty => Some(Box::new(None::<Value>.into_iter())),
Enumerator::Seq(l) => {
let self_clone = self.clone();
Some(Box::new((0..l).map(move |idx| {
self_clone.get_value(&Value::from(idx)).unwrap_or_default()
})))
}
Enumerator::Iter(iter) => Some(iter),
Enumerator::RevIter(iter) => Some(Box::new(iter)),
Enumerator::Str(s) => Some(Box::new(s.iter().copied().map(Value::from))),
Enumerator::Values(v) => Some(Box::new(v.into_iter())),
}
}
$vis fn try_iter_pairs(
self: $self_ty,
) -> Option<Box<dyn Iterator<Item = (Value, Value)> + Send + Sync>> {
let iter = some!(self.try_iter());
let repr = self.repr();
let self_clone = self.clone();
Some(Box::new(iter.enumerate().map(move |(idx, item)| {
match repr {
ObjectRepr::Map => {
let value = self_clone.get_value(&item);
(item, value.unwrap_or_default())
}
_ => (Value::from(idx), item)
}
})))
}
};
}
pub trait ObjectExt: Object + Send + Sync + 'static {
fn mapped_enumerator<F>(self: &Arc<Self>, maker: F) -> Enumerator
where
F: for<'a> FnOnce(&'a Self) -> Box<dyn Iterator<Item = Value> + Send + Sync + 'a>
+ Send
+ Sync
+ 'static,
Self: Sized,
{
mapped_enumerator(self, maker)
}
fn mapped_rev_enumerator<F>(self: &Arc<Self>, maker: F) -> Enumerator
where
F: for<'a> FnOnce(
&'a Self,
)
-> Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync + 'a>
+ Send
+ Sync
+ 'static,
Self: Sized,
{
struct Iter {
iter: Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync + 'static>,
_object: DynObject,
}
impl Iterator for Iter {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl DoubleEndedIterator for Iter {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
let iter = unsafe {
std::mem::transmute::<
Box<dyn DoubleEndedIterator<Item = _>>,
Box<dyn DoubleEndedIterator<Item = _> + Send + Sync>,
>(maker(self))
};
let _object = DynObject::new(self.clone());
Enumerator::RevIter(Box::new(Iter { iter, _object }))
}
impl_object_helpers!(&Arc<Self>);
}
impl<T: Object + Send + Sync + 'static> ObjectExt for T {}
#[non_exhaustive]
pub enum Enumerator {
NonEnumerable,
Empty,
Str(&'static [&'static str]),
Iter(Box<dyn Iterator<Item = Value> + Send + Sync>),
RevIter(Box<dyn DoubleEndedIterator<Item = Value> + Send + Sync>),
Seq(usize),
Values(Vec<Value>),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ObjectRepr {
Plain,
Map,
Seq,
Iterable,
}
type_erase! {
pub trait Object => DynObject {
fn repr(&self) -> ObjectRepr;
fn get_value(&self, key: &Value) -> Option<Value>;
fn get_value_by_str(&self, key: &str) -> Option<Value>;
fn enumerate(&self) -> Enumerator;
fn is_true(&self) -> bool;
fn enumerator_len(&self) -> Option<usize>;
fn call(
&self,
state: &State<'_, '_>,
args: &[Value]
) -> Result<Value, Error>;
fn call_method(
&self,
state: &State<'_, '_>,
method: &str,
args: &[Value]
) -> Result<Value, Error>;
fn custom_cmp(&self, other: &DynObject) -> Option<Ordering>;
fn render(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
impl fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
}
}
}
unsafe impl Send for DynObject {}
unsafe impl Sync for DynObject {}
impl DynObject {
impl_object_helpers!(pub &Self);
pub(crate) fn is_same_object(&self, other: &DynObject) -> bool {
self.ptr == other.ptr && self.vtable == other.vtable
}
pub(crate) fn is_same_object_type(&self, other: &DynObject) -> bool {
self.type_id() == other.type_id()
}
}
impl Hash for DynObject {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
if let Some(iter) = self.try_iter_pairs() {
for (key, value) in iter {
key.hash(state);
value.hash(state);
}
}
}
}
impl fmt::Display for DynObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.render(f)
}
}
impl Enumerator {
fn query_len(&self) -> Option<usize> {
Some(match self {
Enumerator::Empty => 0,
Enumerator::Values(v) => v.len(),
Enumerator::Str(v) => v.len(),
Enumerator::Iter(i) => match i.size_hint() {
(a, Some(b)) if a == b => a,
_ => return None,
},
Enumerator::RevIter(i) => match i.size_hint() {
(a, Some(b)) if a == b => a,
_ => return None,
},
Enumerator::Seq(v) => *v,
Enumerator::NonEnumerable => return None,
})
}
}
macro_rules! impl_value_vec {
($vec_type:ident) => {
impl<T> Object for $vec_type<T>
where
T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
fn repr(self: &Arc<Self>) -> ObjectRepr {
ObjectRepr::Seq
}
#[inline(always)]
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
self.get(some!(key.as_usize())).cloned().map(|v| v.into())
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
Enumerator::Seq(self.len())
}
}
impl<T> From<$vec_type<T>> for Value
where
T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
fn from(val: $vec_type<T>) -> Self {
Value::from_object(val)
}
}
};
}
#[allow(unused)]
macro_rules! impl_value_iterable {
($iterable_type:ident, $enumerator:ident) => {
impl<T> Object for $iterable_type<T>
where
T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
fn repr(self: &Arc<Self>) -> ObjectRepr {
ObjectRepr::Iterable
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
self.clone()
.$enumerator(|this| Box::new(this.iter().map(|x| x.clone().into())))
}
}
impl<T> From<$iterable_type<T>> for Value
where
T: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
fn from(val: $iterable_type<T>) -> Self {
Value::from_object(val)
}
}
};
}
macro_rules! impl_str_map_helper {
($map_type:ident, $key_type:ty, $enumerator:ident) => {
impl<V> Object for $map_type<$key_type, V>
where
V: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
#[inline(always)]
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
self.get(some!(key.as_str())).cloned().map(|v| v.into())
}
#[inline(always)]
fn get_value_by_str(self: &Arc<Self>, key: &str) -> Option<Value> {
self.get(key).cloned().map(|v| v.into())
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
self.$enumerator(|this| Box::new(this.keys().map(|x| Value::from(x as &str))))
}
fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
Some(self.len())
}
}
};
}
macro_rules! impl_static_str_map_helper {
($map_type:ident, $enumerator:ident) => {
impl<V> Object for $map_type<&'static str, V>
where
V: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
#[inline(always)]
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
self.get(some!(key.as_str())).cloned().map(|v| v.into())
}
#[inline(always)]
fn get_value_by_str(self: &Arc<Self>, key: &str) -> Option<Value> {
if self.len() <= 8 {
self.iter().find_map(|(map_key, value)| {
(*map_key == key).then(|| value.clone().into())
})
} else {
self.get(key).cloned().map(|v| v.into())
}
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
self.$enumerator(|this| Box::new(this.keys().map(|x| Value::from(*x))))
}
fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
Some(self.len())
}
}
};
}
macro_rules! impl_str_map {
($map_type:ident, $enumerator:ident) => {
impl_str_map_helper!($map_type, String, $enumerator);
impl_str_map_helper!($map_type, Arc<str>, $enumerator);
impl_static_str_map_helper!($map_type, $enumerator);
impl<V> From<$map_type<String, V>> for Value
where
V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
{
fn from(val: $map_type<String, V>) -> Self {
Value::from_object(val)
}
}
impl<V> From<$map_type<Arc<str>, V>> for Value
where
V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
{
fn from(val: $map_type<Arc<str>, V>) -> Self {
Value::from_object(val)
}
}
impl<'a, V> From<$map_type<&'a str, V>> for Value
where
V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
{
fn from(val: $map_type<&'a str, V>) -> Self {
Value::from(
val.into_iter()
.map(|(k, v)| (Arc::from(k), v))
.collect::<$map_type<Arc<str>, V>>(),
)
}
}
impl<'a, V> From<$map_type<Cow<'a, str>, V>> for Value
where
V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
{
fn from(val: $map_type<Cow<'a, str>, V>) -> Self {
Value::from(
val.into_iter()
.map(|(k, v)| (Arc::from(k), v))
.collect::<$map_type<Arc<str>, V>>(),
)
}
}
};
}
macro_rules! impl_value_map {
($map_type:ident, $enumerator:ident) => {
impl<V> Object for $map_type<Value, V>
where
V: Into<Value> + Clone + Send + Sync + fmt::Debug + 'static,
{
#[inline(always)]
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
self.get(key).cloned().map(|v| v.into())
}
#[inline(always)]
fn get_value_by_str(self: &Arc<Self>, key: &str) -> Option<Value> {
if self.len() <= 12 {
self.iter().find_map(|(k, v)| match &k.0 {
ValueRepr::String(s, _) if &**s == key => Some(v.clone().into()),
ValueRepr::SmallStr(s) if s.as_str() == key => Some(v.clone().into()),
_ => None,
})
} else {
self.get(&Value::from(key)).cloned().map(|v| v.into())
}
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
self.$enumerator(|this| Box::new(this.keys().cloned()))
}
fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
Some(self.len())
}
}
impl<V> From<$map_type<Value, V>> for Value
where
V: Into<Value> + Send + Sync + Clone + fmt::Debug + 'static,
{
fn from(val: $map_type<Value, V>) -> Self {
Value::from_object(val)
}
}
};
}
impl_value_vec!(Vec);
impl_value_map!(BTreeMap, mapped_rev_enumerator);
impl_str_map!(BTreeMap, mapped_rev_enumerator);
#[cfg(feature = "std_collections")]
mod std_collections_impls {
use super::*;
use std::collections::{BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
impl_value_iterable!(LinkedList, mapped_rev_enumerator);
impl_value_iterable!(HashSet, mapped_enumerator);
impl_value_iterable!(BTreeSet, mapped_rev_enumerator);
impl_str_map!(HashMap, mapped_enumerator);
impl_value_map!(HashMap, mapped_enumerator);
impl_value_vec!(VecDeque);
}
#[cfg(feature = "preserve_order")]
mod preserve_order_impls {
use super::*;
use indexmap::IndexMap;
impl_value_map!(IndexMap, mapped_rev_enumerator);
}