use crate as rune;
use crate::alloc::fmt::TryWrite;
use crate::alloc::prelude::*;
use crate::hashbrown::{IterRef, KeysRef, Table, ValuesRef};
use crate::runtime::{
EnvProtocolCaller, Formatter, FromValue, Iterator, ProtocolCaller, Ref, Value, VmErrorKind,
VmResult,
};
use crate::{Any, ContextError, Module};
#[rune::module(::std::collections::hash_map)]
pub fn module() -> Result<Module, ContextError> {
let mut m = Module::from_meta(self::module_meta)?;
m.ty::<HashMap>()?;
m.function_meta(HashMap::new__meta)?;
m.function_meta(HashMap::with_capacity__meta)?;
m.function_meta(HashMap::len__meta)?;
m.function_meta(HashMap::capacity__meta)?;
m.function_meta(HashMap::insert__meta)?;
m.function_meta(HashMap::get__meta)?;
m.function_meta(HashMap::contains_key__meta)?;
m.function_meta(HashMap::remove__meta)?;
m.function_meta(HashMap::clear__meta)?;
m.function_meta(HashMap::is_empty__meta)?;
m.function_meta(HashMap::iter__meta)?;
m.function_meta(HashMap::into_iter__meta)?;
m.function_meta(HashMap::from_iter__meta)?;
m.function_meta(HashMap::keys__meta)?;
m.function_meta(HashMap::values__meta)?;
m.function_meta(HashMap::extend__meta)?;
m.function_meta(HashMap::index_set__meta)?;
m.function_meta(HashMap::index_get__meta)?;
m.function_meta(HashMap::debug_fmt__meta)?;
m.function_meta(HashMap::clone__meta)?;
m.implement_trait::<HashMap>(rune::item!(::std::clone::Clone))?;
m.function_meta(HashMap::partial_eq__meta)?;
m.implement_trait::<HashMap>(rune::item!(::std::cmp::PartialEq))?;
m.function_meta(HashMap::eq__meta)?;
m.implement_trait::<HashMap>(rune::item!(::std::cmp::Eq))?;
m.ty::<Iter>()?;
m.function_meta(Iter::next)?;
m.function_meta(Iter::size_hint)?;
m.implement_trait::<Iter>(rune::item!(::std::iter::Iterator))?;
m.ty::<Keys>()?;
m.function_meta(Keys::next)?;
m.function_meta(Keys::size_hint)?;
m.implement_trait::<Keys>(rune::item!(::std::iter::Iterator))?;
m.ty::<Values>()?;
m.function_meta(Values::next)?;
m.function_meta(Values::size_hint)?;
m.implement_trait::<Values>(rune::item!(::std::iter::Iterator))?;
Ok(m)
}
#[derive(Any)]
#[rune(item = ::std::collections::hash_map)]
pub(crate) struct HashMap {
table: Table<Value>,
}
impl HashMap {
#[rune::function(keep, path = Self::new)]
fn new() -> Self {
Self {
table: Table::new(),
}
}
#[rune::function(keep, path = Self::with_capacity)]
pub(crate) fn with_capacity(capacity: usize) -> VmResult<Self> {
VmResult::Ok(Self {
table: vm_try!(Table::try_with_capacity(capacity)),
})
}
#[rune::function(keep)]
fn len(&self) -> usize {
self.table.len()
}
#[rune::function(keep)]
fn capacity(&self) -> usize {
self.table.capacity()
}
#[rune::function(keep)]
fn is_empty(&self) -> bool {
self.table.is_empty()
}
#[rune::function(keep)]
pub(crate) fn insert(&mut self, key: Value, value: Value) -> VmResult<Option<Value>> {
let mut caller = EnvProtocolCaller;
self.table.insert_with(key, value, &mut caller)
}
#[rune::function(keep)]
fn get(&self, key: Value) -> VmResult<Option<Value>> {
let mut caller = EnvProtocolCaller;
VmResult::Ok(vm_try!(self.table.get(&key, &mut caller)).map(|(_, v)| v.clone()))
}
#[rune::function(keep)]
fn contains_key(&self, key: Value) -> VmResult<bool> {
let mut caller = EnvProtocolCaller;
VmResult::Ok(vm_try!(self.table.get(&key, &mut caller)).is_some())
}
#[rune::function(keep)]
fn remove(&mut self, key: Value) -> VmResult<Option<Value>> {
let mut caller = EnvProtocolCaller;
self.table.remove_with(&key, &mut caller)
}
#[rune::function(keep)]
fn clear(&mut self) {
self.table.clear()
}
#[rune::function(keep, instance, path = Self::iter)]
fn iter(this: Ref<Self>) -> Iter {
let iter = Table::iter_ref(Ref::map(this, |this| &this.table));
Iter { iter }
}
#[rune::function(keep, instance, path = Self::keys)]
fn keys(this: Ref<Self>) -> Keys {
let iter = Table::keys_ref(Ref::map(this, |this| &this.table));
Keys { iter }
}
#[rune::function(keep, instance, path = Self::values)]
fn values(this: Ref<Self>) -> Values {
let iter = Table::values_ref(Ref::map(this, |this| &this.table));
Values { iter }
}
#[rune::function(keep)]
fn extend(&mut self, value: Value) -> VmResult<()> {
let mut it = vm_try!(value.into_iter());
while let Some(value) = vm_try!(it.next()) {
let (key, value) = vm_try!(<(Value, Value)>::from_value(value));
vm_try!(self.insert(key, value));
}
VmResult::Ok(())
}
#[rune::function(keep, instance, path = Self::clone, protocol = CLONE)]
fn clone(this: &HashMap) -> VmResult<HashMap> {
VmResult::Ok(Self {
table: vm_try!(this.table.try_clone()),
})
}
#[rune::function(keep, path = Self::from_iter)]
fn from_iter(it: Iterator) -> VmResult<HashMap> {
let mut caller = EnvProtocolCaller;
Self::from_iter_with(it, &mut caller)
}
pub(crate) fn from_iter_with(
mut it: Iterator,
caller: &mut dyn ProtocolCaller,
) -> VmResult<Self> {
let mut map = Self::new();
while let Some(value) = vm_try!(it.next()) {
let (key, value) = vm_try!(<(Value, Value)>::from_value(value));
vm_try!(map.table.insert_with(key, value, caller));
}
VmResult::Ok(map)
}
#[rune::function(keep, protocol = INDEX_SET)]
fn index_set(&mut self, key: Value, value: Value) -> VmResult<()> {
let _ = vm_try!(self.insert(key, value));
VmResult::Ok(())
}
#[rune::function(keep, protocol = INDEX_GET)]
fn index_get(&self, key: Value) -> VmResult<Value> {
use crate::runtime::TypeOf;
let mut caller = EnvProtocolCaller;
let Some((_, value)) = vm_try!(self.table.get(&key, &mut caller)) else {
return VmResult::err(VmErrorKind::MissingIndexKey {
target: Self::type_info(),
});
};
VmResult::Ok(value.clone())
}
#[rune::function(keep, protocol = DEBUG_FMT)]
fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> {
self.debug_fmt_with(f, &mut EnvProtocolCaller)
}
pub(crate) fn debug_fmt_with(
&self,
f: &mut Formatter,
caller: &mut dyn ProtocolCaller,
) -> VmResult<()> {
vm_try!(vm_write!(f, "{{"));
let mut it = self.table.iter().peekable();
while let Some((key, value)) = it.next() {
vm_try!(key.debug_fmt_with(f, caller));
vm_try!(vm_write!(f, ": "));
vm_try!(value.debug_fmt_with(f, caller));
if it.peek().is_some() {
vm_try!(vm_write!(f, ", "));
}
}
vm_try!(vm_write!(f, "}}"));
VmResult::Ok(())
}
#[rune::function(keep, protocol = PARTIAL_EQ)]
fn partial_eq(&self, other: &Self) -> VmResult<bool> {
self.partial_eq_with(other, &mut EnvProtocolCaller)
}
fn partial_eq_with(&self, other: &Self, caller: &mut dyn ProtocolCaller) -> VmResult<bool> {
if self.table.len() != other.table.len() {
return VmResult::Ok(false);
}
for (k, v1) in self.table.iter() {
let Some((_, v2)) = vm_try!(other.table.get(k, caller)) else {
return VmResult::Ok(false);
};
if !vm_try!(Value::partial_eq_with(v1, v2, caller)) {
return VmResult::Ok(false);
}
}
VmResult::Ok(true)
}
#[rune::function(keep, protocol = EQ)]
fn eq(&self, other: &Self) -> VmResult<bool> {
self.eq_with(other, &mut EnvProtocolCaller)
}
fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> VmResult<bool> {
if self.table.len() != other.table.len() {
return VmResult::Ok(false);
}
for (k, v1) in self.table.iter() {
let Some((_, v2)) = vm_try!(other.table.get(k, caller)) else {
return VmResult::Ok(false);
};
if !vm_try!(Value::eq_with(v1, v2, caller)) {
return VmResult::Ok(false);
}
}
VmResult::Ok(true)
}
#[rune::function(keep, instance, protocol = INTO_ITER, path = Self)]
fn into_iter(this: Ref<Self>) -> Iter {
Self::iter(this)
}
}
#[derive(Any)]
#[rune(item = ::std::collections::hash_map)]
pub(crate) struct Iter {
iter: IterRef<Value>,
}
impl Iter {
#[rune::function(instance, protocol = NEXT)]
fn next(&mut self) -> Option<(Value, Value)> {
self.iter.next()
}
#[rune::function(instance, protocol = SIZE_HINT)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[derive(Any)]
#[rune(item = ::std::collections::hash_map)]
pub(crate) struct Keys {
iter: KeysRef<Value>,
}
impl Keys {
#[rune::function(instance, protocol = NEXT)]
fn next(&mut self) -> Option<Value> {
self.iter.next()
}
#[rune::function(instance, protocol = SIZE_HINT)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[derive(Any)]
#[rune(item = ::std::collections::hash_map)]
pub(crate) struct Values {
iter: ValuesRef<Value>,
}
impl Values {
#[rune::function(instance, protocol = NEXT)]
fn next(&mut self) -> Option<Value> {
self.iter.next()
}
#[rune::function(instance, protocol = SIZE_HINT)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}