use core::{
cmp::Ordering,
fmt::{self, Debug, Write},
iter::FusedIterator,
marker::PhantomData,
ops::Index,
ptr::NonNull,
};
use evil_janet::{JanetKV, JanetTable as CJanetTable};
use super::{Janet, JanetExtend, JanetStruct};
use crate::cjvg;
#[repr(transparent)]
pub struct JanetTable<'data> {
pub(crate) raw: *mut CJanetTable,
phatom: PhantomData<&'data ()>,
}
impl<'data> JanetTable<'data> {
#[inline]
#[must_use = "function is a constructor associated function"]
pub fn new() -> Self {
Self {
raw: unsafe { evil_janet::janet_table(0) },
phatom: PhantomData,
}
}
#[inline]
#[must_use = "function is a constructor associated function"]
pub fn with_capacity(capacity: usize) -> Self {
let capacity = i32::try_from(capacity).unwrap_or(i32::MAX);
Self {
raw: unsafe { evil_janet::janet_table(capacity) },
phatom: PhantomData,
}
}
#[inline]
#[must_use = "function is a constructor associated function"]
pub fn with_prototype(proto: JanetTable<'data>) -> Self {
let mut t = Self::new();
t.set_prototype(&proto);
t
}
#[inline]
pub const unsafe fn from_raw(raw: *mut CJanetTable) -> Self {
Self {
raw,
phatom: PhantomData,
}
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn capacity(&self) -> usize {
unsafe { (*self.raw).capacity as usize }
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn removed(&self) -> usize {
unsafe { (*self.raw).deleted as usize }
}
#[cjvg("1.10.1")]
#[inline]
pub fn clear(&mut self) {
unsafe { evil_janet::janet_table_clear(self.raw) }
}
#[cjvg("1.0.0", "1.10.1")]
#[inline]
pub fn clear(&mut self) {
let capacity = self.capacity();
unsafe {
let data = (*self.raw).data;
for i in 0..capacity {
let kv = data.add(i);
(*kv).key = evil_janet::janet_wrap_nil();
(*kv).value = evil_janet::janet_wrap_nil();
}
(*self.raw).count = 0;
(*self.raw).deleted = 0;
}
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn len(&self) -> usize {
unsafe { (*self.raw).count as usize }
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn prototype(&self) -> Option<Self> {
let proto = unsafe { (*self.raw).proto };
if proto.is_null() {
None
} else {
let proto = unsafe { JanetTable::from_raw(proto) };
Some(proto)
}
}
#[inline]
pub fn set_prototype(&mut self, proto: &JanetTable) {
unsafe { (*self.raw).proto = proto.raw };
}
#[inline]
pub fn get(&self, key: impl Into<Janet>) -> Option<&Janet> {
self.get_key_value(key).map(|(_, v)| v)
}
#[inline]
pub fn get_key_value(&self, key: impl Into<Janet>) -> Option<(&Janet, &Janet)> {
let key = key.into();
if key.is_nil() {
None
} else {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(self.raw, key.inner) as *mut _ };
if kv.is_null() {
None
} else {
unsafe {
if (*kv).1.is_nil() {
None
} else {
Some((&(*kv).0, &(*kv).1))
}
}
}
}
}
#[inline]
pub fn get_mut(&mut self, key: impl Into<Janet>) -> Option<&'data mut Janet> {
self.get_key_value_mut(key).map(|(_, v)| v)
}
#[inline]
pub fn get_key_value_mut(
&mut self, key: impl Into<Janet>,
) -> Option<(&Janet, &'data mut Janet)> {
let key = key.into();
if key.is_nil() {
None
} else {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(self.raw, key.inner) as *mut _ };
if kv.is_null() {
None
} else {
unsafe {
if (*kv).1.is_nil() {
None
} else {
Some((&(*kv).0, &mut (*kv).1))
}
}
}
}
}
#[inline]
pub(crate) unsafe fn get_unchecked(&self, key: impl Into<Janet>) -> &'data Janet {
self.get_key_value_unchecked(key).1
}
#[inline]
pub(crate) unsafe fn get_mut_unchecked(&mut self, key: impl Into<Janet>) -> &'data mut Janet {
self.get_key_value_mut_unchecked(key).1
}
#[inline]
pub(crate) unsafe fn get_key_value_mut_unchecked(
&mut self, key: impl Into<Janet>,
) -> (&Janet, &'data mut Janet) {
let key = key.into();
let kv: *mut (Janet, Janet) = evil_janet::janet_table_find(self.raw, key.inner) as *mut _;
(&(*kv).0, &mut (*kv).1)
}
#[inline]
pub(crate) unsafe fn get_key_value_unchecked(
&self, key: impl Into<Janet>,
) -> (&Janet, &'data Janet) {
let key = key.into();
let kv: *mut (Janet, Janet) = evil_janet::janet_table_find(self.raw, key.inner) as *mut _;
(&(*kv).0, &(*kv).1)
}
#[inline]
pub fn get_proto(&self, key: impl Into<Janet>) -> Option<&Janet> {
self.get_key_value_proto(key).map(|(_, v)| v)
}
#[inline]
pub fn get_proto_mut(&mut self, key: impl Into<Janet>) -> Option<&mut Janet> {
self.get_key_value_proto_mut(key).map(|(_, v)| v)
}
#[inline]
pub fn get_key_value_proto_mut(
&mut self, key: impl Into<Janet>,
) -> Option<(&Janet, &mut Janet)> {
let key = key.into();
macro_rules! proto_lookup {
() => {
let mut proto = unsafe { (*self.raw).proto };
let mut depth = 0;
return loop {
if proto.is_null() {
break None;
} else {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(proto, key.inner) as *mut _ };
if kv.is_null() {
if depth < evil_janet::JANET_MAX_PROTO_DEPTH {
depth += 1;
proto = unsafe { (*proto).proto };
continue;
} else {
break None;
}
} else {
unsafe {
if (*kv).1.is_nil() {
if depth < evil_janet::JANET_MAX_PROTO_DEPTH {
depth += 1;
proto = (*proto).proto;
continue;
} else {
break None;
}
} else {
break Some((&(*kv).0, &mut (*kv).1));
}
}
}
}
}
};
}
if !key.is_nil() {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(self.raw, key.inner) as *mut _ };
if kv.is_null() {
proto_lookup!();
} else {
#[allow(unused_unsafe)]
unsafe {
if (*kv).1.is_nil() {
proto_lookup!();
} else {
return Some((&(*kv).0, &mut (*kv).1));
}
}
}
}
None
}
#[inline]
pub fn get_key_value_proto(&self, key: impl Into<Janet>) -> Option<(&Janet, &Janet)> {
let key = key.into();
match self.get_key_value(key) {
val @ Some(_) => val,
None => {
let mut proto = unsafe { (*self.raw).proto };
let mut depth = 0;
loop {
if proto.is_null() {
break None;
} else {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(proto, key.inner) as *mut _ };
if kv.is_null() {
if depth < evil_janet::JANET_MAX_PROTO_DEPTH {
depth += 1;
proto = unsafe { (*proto).proto };
continue;
} else {
break None;
}
} else {
unsafe {
if (*kv).1.is_nil() {
if depth < evil_janet::JANET_MAX_PROTO_DEPTH {
depth += 1;
proto = (*proto).proto;
continue;
} else {
break None;
}
} else {
break Some((&(*kv).0, &(*kv).1));
}
}
}
}
}
},
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn get_owned(&self, key: impl Into<Janet>) -> Option<Janet> {
let key = key.into();
if key.is_nil() {
None
} else {
let val: Janet = unsafe { evil_janet::janet_table_get(self.raw, key.inner).into() };
if val.is_nil() { None } else { Some(val) }
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn get_owned_key_value(&self, key: impl Into<Janet>) -> Option<(Janet, Janet)> {
let key = key.into();
self.get_owned(key).map(|v| (key, v))
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn raw_get_owned(&self, key: impl Into<Janet>) -> Option<Janet> {
let key = key.into();
if key.is_nil() {
None
} else {
let val: Janet = unsafe { evil_janet::janet_table_rawget(self.raw, key.inner).into() };
if val.is_nil() { None } else { Some(val) }
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn raw_get_owned_key_value(&self, key: impl Into<Janet>) -> Option<(Janet, Janet)> {
let key = key.into();
self.raw_get_owned(key).map(|v| (key, v))
}
#[allow(dead_code)]
#[cfg_attr(feature = "inline-more", inline)]
pub(crate) fn find(&mut self, key: impl Into<Janet>) -> Option<(&mut Janet, &mut Janet)> {
let key = key.into();
if key.is_nil() {
None
} else {
let kv: *mut (Janet, Janet) =
unsafe { evil_janet::janet_table_find(self.raw, key.inner) as *mut _ };
if kv.is_null() {
None
} else {
unsafe { Some((&mut (*kv).0, &mut (*kv).1)) }
}
}
}
#[cjvg("1.11.0")]
#[inline]
pub fn remove(&mut self, key: impl Into<Janet>) -> Option<Janet> {
let key = key.into();
if key.is_nil() {
None
} else {
let value: Janet =
unsafe { evil_janet::janet_table_remove(self.raw, key.inner).into() };
if value.is_nil() { None } else { Some(value) }
}
}
#[cjvg("1.0.0", "1.11.0")]
#[inline]
pub fn remove(&mut self, key: impl Into<Janet>) -> Option<Janet> {
let key = key.into();
if key.is_nil() {
None
} else {
let kv: *mut (Janet, Janet) =
unsafe { janet_table_find(self.raw, key.inner) as *mut _ };
if kv.is_null() {
None
} else {
unsafe {
let ret = (*kv).1;
if ret.is_nil() {
None
} else {
(*self.raw).count -= 1;
(*self.raw).deleted += 1;
(*kv).0 = Janet::nil();
(*kv).1 = Janet::boolean(false);
Some(ret)
}
}
}
}
}
#[inline]
pub fn insert(&mut self, key: impl Into<Janet>, value: impl Into<Janet>) -> Option<Janet> {
let (key, value) = (key.into(), value.into());
if key.is_nil() {
return None;
}
let old_value = self.get_owned(key);
unsafe { evil_janet::janet_table_put(self.raw, key.inner, value.inner) };
old_value
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn try_insert(
&mut self, key: impl Into<Janet>, value: impl Into<Janet>,
) -> Result<&mut Janet, OccupiedError<'_, 'data>> {
match self.entry(key) {
Entry::Occupied(entry) => Err(OccupiedError {
entry,
value: value.into(),
}),
Entry::Vacant(entry) => Ok(entry.insert(value)),
}
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn contains_key(&self, key: impl Into<Janet>) -> bool {
self.get(key).is_some()
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn contains(&self, value: impl Into<Janet>) -> bool {
let value = value.into();
self.values().any(|&v| v == value)
}
#[inline]
pub fn keys(&self) -> Keys<'_, '_> {
Keys { inner: self.iter() }
}
#[inline]
pub fn values(&self) -> Values<'_, '_> {
Values { inner: self.iter() }
}
#[inline]
pub fn values_mut(&mut self) -> ValuesMut<'_, '_> {
ValuesMut {
inner: self.iter_mut(),
}
}
#[inline]
pub fn iter(&self) -> Iter<'_, '_> {
Iter {
table: self,
kv: unsafe { (*self.raw).data },
end: unsafe { (*self.raw).data.add(self.capacity()) },
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, '_> {
let cap = self.capacity() as isize;
IterMut {
table: self,
kv: unsafe { (*self.raw).data },
end: unsafe { (*self.raw).data.offset(cap) },
}
}
#[inline]
#[must_use]
pub const fn as_raw(&self) -> *const CJanetTable {
self.raw
}
#[inline]
pub fn as_mut_raw(&mut self) -> *mut CJanetTable {
self.raw
}
}
impl<'data> JanetTable<'data> {
#[cfg_attr(feature = "inline-more", inline)]
pub fn entry(&mut self, key: impl Into<Janet>) -> Entry<'_, 'data> {
let key = key.into();
if self.get(key).is_some() {
let elem = unsafe {
NonNull::new_unchecked(evil_janet::janet_table_find(self.raw, key.inner) as *mut _)
};
Entry::Occupied(OccupiedEntry {
key: Some(key),
elem,
table: self,
})
} else {
Entry::Vacant(VacantEntry { key, table: self })
}
}
}
impl Debug for JanetTable<'_> {
#[cfg_attr(feature = "inline-more", inline)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('@')?;
f.debug_map().entries(self.iter()).finish()
}
}
impl Clone for JanetTable<'_> {
#[inline]
fn clone(&self) -> Self {
JanetTable {
raw: unsafe { evil_janet::janet_table_clone(self.raw) },
phatom: PhantomData,
}
}
}
impl PartialOrd for JanetTable<'_> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for JanetTable<'_> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.raw.cmp(&other.raw)
}
}
impl PartialEq for JanetTable<'_> {
#[inline]
#[allow(clippy::unconditional_recursion)] fn eq(&self, other: &Self) -> bool {
self.raw.eq(&other.raw)
}
}
impl Eq for JanetTable<'_> {}
impl super::DeepEq for JanetTable<'_> {
#[inline]
fn deep_eq(&self, other: &Self) -> bool {
if self.len() == other.len() {
return self.iter().all(|(s_key, s_val)| {
if let Some(o_val) = other.get(s_key) {
s_val.deep_eq(o_val)
} else {
false
}
});
}
false
}
}
impl super::DeepEq<JanetStruct<'_>> for JanetTable<'_> {
#[inline]
fn deep_eq(&self, other: &JanetStruct<'_>) -> bool {
if self.len() == other.len() {
return self.iter().all(|(s_key, s_val)| {
if let Some(o_val) = other.get(s_key) {
s_val.deep_eq(o_val)
} else {
false
}
});
}
false
}
}
impl Extend<(Janet, Janet)> for JanetTable<'_> {
#[cfg_attr(feature = "inline-more", inline)]
fn extend<T: IntoIterator<Item = (Janet, Janet)>>(&mut self, iter: T) {
iter.into_iter().for_each(|(k, v)| {
self.insert(k, v);
})
}
}
impl<'a> Extend<(&'a Janet, &'a Janet)> for JanetTable<'_> {
#[cfg_attr(feature = "inline-more", inline)]
fn extend<T: IntoIterator<Item = (&'a Janet, &'a Janet)>>(&mut self, iter: T) {
iter.into_iter().for_each(|(&k, &v)| {
self.insert(k, v);
})
}
}
impl JanetExtend<JanetTable<'_>> for JanetTable<'_> {
#[inline]
fn extend(&mut self, other: JanetTable<'_>) {
unsafe { evil_janet::janet_table_merge_table(self.raw, other.raw) }
}
}
impl Default for JanetTable<'_> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl From<JanetStruct<'_>> for JanetTable<'_> {
#[inline]
fn from(val: JanetStruct<'_>) -> Self {
val.into_iter().collect()
}
}
impl From<&JanetStruct<'_>> for JanetTable<'_> {
#[inline]
fn from(val: &JanetStruct<'_>) -> Self {
val.into_iter().collect()
}
}
impl<T: Into<Janet>> Index<T> for JanetTable<'_> {
type Output = Janet;
#[inline]
fn index(&self, key: T) -> &Self::Output {
self.get(key)
.unwrap_or_else(|| crate::jpanic!("no entry found for key"))
}
}
impl<'data> IntoIterator for JanetTable<'data> {
type IntoIter = IntoIter<'data>;
type Item = (Janet, Janet);
#[inline]
fn into_iter(self) -> Self::IntoIter {
let cap = self.capacity() as isize;
let kv = unsafe { (*self.raw).data };
let end = unsafe { (*self.raw).data.offset(cap) };
IntoIter {
table: self,
kv,
end,
}
}
}
impl<'a, 'data> IntoIterator for &'a JanetTable<'data> {
type IntoIter = Iter<'a, 'data>;
type Item = (&'a Janet, &'a Janet);
#[inline]
fn into_iter(self) -> Self::IntoIter {
let cap = self.capacity() as isize;
Iter {
table: self,
kv: unsafe { (*self.raw).data },
end: unsafe { (*self.raw).data.offset(cap) },
}
}
}
impl<'a, 'data> IntoIterator for &'a mut JanetTable<'data> {
type IntoIter = IterMut<'a, 'data>;
type Item = (&'a Janet, &'data mut Janet);
#[inline]
fn into_iter(self) -> Self::IntoIter {
let cap = self.capacity() as isize;
IterMut {
table: self,
kv: unsafe { (*self.raw).data },
end: unsafe { (*self.raw).data.offset(cap) },
}
}
}
impl<U, J> FromIterator<(U, J)> for JanetTable<'_>
where
U: Into<Janet>,
J: Into<Janet>,
{
#[cfg_attr(feature = "inline-more", inline)]
fn from_iter<T: IntoIterator<Item = (U, J)>>(iter: T) -> Self {
let iter = iter.into_iter();
let (lower, upper) = iter.size_hint();
let mut new = if let Some(upper) = upper {
Self::with_capacity(upper)
} else {
Self::with_capacity(lower)
};
for (k, v) in iter {
let _ = new.insert(k, v);
}
new
}
}
#[derive(Debug)]
pub enum Entry<'a, 'data> {
Occupied(OccupiedEntry<'a, 'data>),
Vacant(VacantEntry<'a, 'data>),
}
impl<'a, 'data> Entry<'a, 'data> {
#[inline]
#[must_use]
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut Janet),
{
match self {
Self::Occupied(mut entry) => {
f(entry.get_mut());
Self::Occupied(entry)
},
Self::Vacant(entry) => Self::Vacant(entry),
}
}
#[inline]
pub fn insert(self, value: impl Into<Janet>) -> OccupiedEntry<'a, 'data> {
match self {
Self::Occupied(mut entry) => {
entry.insert(value);
entry
},
Self::Vacant(entry) => entry.insert_entry(value),
}
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn key(&self) -> &Janet {
match self {
Self::Occupied(ref entry) => entry.key(),
Self::Vacant(ref entry) => entry.key(),
}
}
#[inline]
pub fn or_insert(self, default: impl Into<Janet>) -> &'a mut Janet {
match self {
Self::Occupied(entry) => entry.into_mut(),
Self::Vacant(entry) => entry.insert(default),
}
}
#[inline]
pub fn or_insert_with<F>(self, default: F) -> &'a mut Janet
where
F: FnOnce() -> Janet,
{
match self {
Self::Occupied(entry) => entry.into_mut(),
Self::Vacant(entry) => entry.insert(default()),
}
}
#[inline]
pub fn or_insert_with_key<F>(self, default: F) -> &'a mut Janet
where
F: FnOnce(&Janet) -> Janet,
{
match self {
Self::Occupied(entry) => entry.into_mut(),
Self::Vacant(entry) => {
let value = default(entry.key());
entry.insert(value)
},
}
}
}
#[derive(Debug)]
pub struct OccupiedEntry<'a, 'data> {
key: Option<Janet>,
elem: NonNull<(Janet, Janet)>,
table: &'a mut JanetTable<'data>,
}
impl<'a> OccupiedEntry<'a, '_> {
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn get(&self) -> &Janet {
unsafe { &(*self.elem.as_ptr()).1 }
}
#[inline]
pub fn get_mut(&mut self) -> &mut Janet {
unsafe { &mut (*self.elem.as_ptr()).1 }
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn insert(&mut self, value: impl Into<Janet>) -> Janet {
let mut value = value.into();
let old_value = self.get_mut();
core::mem::swap(&mut value, old_value);
value
}
#[inline]
pub fn into_mut(self) -> &'a mut Janet {
unsafe { &mut (*self.elem.as_ptr()).1 }
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn key(&self) -> &Janet {
unsafe { &(*self.elem.as_ptr()).0 }
}
#[inline]
pub fn remove(self) -> Janet {
self.remove_entry().1
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn remove_entry(self) -> (Janet, Janet) {
let copy = unsafe { *self.elem.as_ptr() };
self.table.remove(copy.0);
copy
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn replace_entry(self, value: impl Into<Janet>) -> (Janet, Janet) {
let value = value.into();
let mut entry = unsafe { *self.elem.as_ptr() };
let old_key = core::mem::replace(&mut entry.0, self.key.unwrap());
let old_value = core::mem::replace(&mut entry.1, value);
(old_key, old_value)
}
#[cfg_attr(feature = "inline-more", inline)]
pub fn replace_key(self) -> Janet {
let mut entry = unsafe { *self.elem.as_ptr() };
core::mem::replace(&mut entry.0, self.key.unwrap())
}
}
#[derive(Debug)]
pub struct VacantEntry<'a, 'data> {
key: Janet,
table: &'a mut JanetTable<'data>,
}
impl<'a, 'data> VacantEntry<'a, 'data> {
#[cfg_attr(feature = "inline-more", inline)]
pub fn insert(self, value: impl Into<Janet>) -> &'a mut Janet {
let value = value.into();
self.table.insert(self.key, value);
unsafe { self.table.get_mut_unchecked(self.key) }
}
#[cfg_attr(feature = "inline-more", inline)]
fn insert_entry(self, value: impl Into<Janet>) -> OccupiedEntry<'a, 'data> {
let value = value.into();
self.table.insert(self.key, value);
let elem = unsafe {
NonNull::new_unchecked(
evil_janet::janet_table_find(self.table.raw, self.key.inner) as *mut _
)
};
OccupiedEntry {
key: None,
elem,
table: self.table,
}
}
#[inline]
pub const fn into_key(self) -> Janet {
self.key
}
#[inline]
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn key(&self) -> &Janet {
&self.key
}
}
pub struct OccupiedError<'a, 'data> {
pub entry: OccupiedEntry<'a, 'data>,
pub value: Janet,
}
impl Debug for OccupiedError<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("key", self.entry.key())
.field("old_value", self.entry.get())
.field("new_value", &self.value)
.finish()
}
}
impl fmt::Display for OccupiedError<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!(
"failed to insert {:?}, key {:?} already exists with value {:?}",
self.value,
self.entry.key(),
self.entry.get()
))
}
}
impl core::error::Error for OccupiedError<'_, '_> {}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter<'a, 'data> {
table: &'a JanetTable<'data>,
kv: *const JanetKV,
end: *const JanetKV,
}
impl Debug for Iter<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.table.iter()).finish()
}
}
impl<'a> Iterator for Iter<'a, '_> {
type Item = (&'a Janet, &'a Janet);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.kv < self.end {
let ptr = self.kv as *const (Janet, Janet);
if !(*ptr).0.is_nil() {
self.kv = self.kv.add(1);
return Some((&(*ptr).0, &(*ptr).1));
}
self.kv = self.kv.add(1);
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.end as usize - self.kv as usize;
(exact, Some(exact))
}
}
impl ExactSizeIterator for Iter<'_, '_> {}
impl FusedIterator for Iter<'_, '_> {}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Keys<'a, 'data> {
inner: Iter<'a, 'data>,
}
impl Debug for Keys<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.inner.table.keys()).finish()
}
}
impl<'a> Iterator for Keys<'a, '_> {
type Item = &'a Janet;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, _)| k)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl ExactSizeIterator for Keys<'_, '_> {}
impl FusedIterator for Keys<'_, '_> {}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Values<'a, 'data> {
inner: Iter<'a, 'data>,
}
impl<'a> Iterator for Values<'a, '_> {
type Item = &'a Janet;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(_, v)| v)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl Debug for Values<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.inner.table.values()).finish()
}
}
impl ExactSizeIterator for Values<'_, '_> {}
impl FusedIterator for Values<'_, '_> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IterMut<'a, 'data> {
table: &'a JanetTable<'data>,
kv: *mut JanetKV,
end: *mut JanetKV,
}
impl Debug for IterMut<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.table.iter()).finish()
}
}
impl<'a, 'data> Iterator for IterMut<'a, 'data> {
type Item = (&'a Janet, &'data mut Janet);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.kv < self.end {
let ptr = self.kv as *mut (Janet, Janet);
if !(*ptr).0.is_nil() {
self.kv = self.kv.add(1);
return Some((&(*ptr).0, &mut (*ptr).1));
}
self.kv = self.kv.add(1);
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.end as usize - self.kv as usize;
(exact, Some(exact))
}
}
impl ExactSizeIterator for IterMut<'_, '_> {}
impl FusedIterator for IterMut<'_, '_> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ValuesMut<'a, 'data> {
inner: IterMut<'a, 'data>,
}
impl Debug for ValuesMut<'_, '_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.inner.table.clone()).finish()
}
}
impl<'data> Iterator for ValuesMut<'_, 'data> {
type Item = &'data mut Janet;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(_, v)| v)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl ExactSizeIterator for ValuesMut<'_, '_> {}
impl FusedIterator for ValuesMut<'_, '_> {}
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IntoIter<'data> {
table: JanetTable<'data>,
kv: *mut JanetKV,
end: *mut JanetKV,
}
impl Debug for IntoIter<'_> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.table.iter()).finish()
}
}
impl Iterator for IntoIter<'_> {
type Item = (Janet, Janet);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe {
while self.kv < self.end {
let ptr = self.kv as *mut (Janet, Janet);
if !(*ptr).0.is_nil() {
self.kv = self.kv.add(1);
return Some(((*ptr).0, (*ptr).1));
}
self.kv = self.kv.add(1);
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.end as usize - self.kv as usize;
(exact, Some(exact))
}
}
impl ExactSizeIterator for IntoIter<'_> {}
impl FusedIterator for IntoIter<'_> {}
#[cfg(all(test, any(feature = "amalgation", feature = "link-system")))]
mod tests {
use super::*;
use crate::{JanetString, client::JanetClient, table};
#[test]
fn index() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::new();
table.entry(10).or_insert("abc");
assert_eq!(&Janet::from("abc"), table[10]);
Ok(())
}
#[test]
fn creation() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let table = JanetTable::new();
assert_eq!(1, table.capacity());
let table = JanetTable::with_capacity(10);
assert_eq!(16, table.capacity());
Ok(())
}
#[test]
fn insert() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::new();
assert_eq!(None, table.insert(Janet::nil(), true));
assert_eq!(None, table.insert(0, true));
assert_eq!(Some(Janet::boolean(true)), table.insert(0, false));
Ok(())
}
#[test]
fn length() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::new();
assert_eq!(0, table.len());
assert_eq!(None, table.insert(0, true));
assert_eq!(1, table.len());
Ok(())
}
#[test]
fn get() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, 10.1);
assert_eq!(None, table.get(Janet::nil()));
assert_eq!(None, table.get(11));
assert_eq!(Some(&Janet::number(10.1)), table.get(10));
Ok(())
}
#[test]
fn get_mut() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, "ten");
let (k, v) = table.get_key_value_mut(10).unwrap();
assert_eq!(&Janet::integer(10), k);
assert_eq!(&mut Janet::from("ten"), v);
*v = Janet::string(JanetString::new("ten but modified"));
assert_eq!(
table.get_key_value_mut(10),
Some((&Janet::integer(10), &mut Janet::from("ten but modified")))
);
assert_eq!(table.get(11), None);
Ok(())
}
#[test]
fn get_owned() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, 10.1);
assert_eq!(None, table.get_owned(Janet::nil()));
assert_eq!(None, table.get_owned(11));
assert_eq!(Some(Janet::number(10.1)), table.get_owned(10));
Ok(())
}
#[test]
fn raw_get_owned() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, 10.1);
assert_eq!(None, table.raw_get_owned(Janet::nil()));
assert_eq!(None, table.raw_get_owned(11));
assert_eq!(Some(Janet::number(10.1)), table.raw_get_owned(10));
Ok(())
}
#[test]
fn find() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, 10.1);
assert_eq!(None, table.find(Janet::nil()));
assert_eq!(Some((&mut Janet::nil(), &mut Janet::nil())), table.find(11));
assert_eq!(
Some((&mut Janet::integer(10), &mut Janet::number(10.1))),
table.find(10)
);
Ok(())
}
#[test]
fn remove() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, 10.5);
table.insert(12, 1);
assert_eq!(2, table.len());
assert_eq!(None, table.remove(Janet::nil()));
assert_eq!(0, table.removed());
assert_eq!(2, table.len());
assert_eq!(None, table.remove(13));
assert_eq!(0, table.removed());
assert_eq!(2, table.len());
assert_eq!(Some(Janet::number(10.5)), table.remove(10));
assert_eq!(1, table.removed());
assert_eq!(1, table.len());
assert_eq!(Some(Janet::integer(1)), table.remove(12));
assert_eq!(2, table.removed());
assert!(table.is_empty());
Ok(())
}
#[test]
fn entry_api_vacant_or_insert() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
let val = table.entry(10).or_insert(78.9);
assert_eq!(&mut Janet::number(78.9), val);
assert_eq!(1, table.len());
let val = table.entry(20).or_insert("default");
assert_eq!(&mut Janet::from("default"), val);
assert_eq!(2, table.len());
Ok(())
}
#[test]
fn entry_api_occupied_or_insert() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, "dez");
table.insert(11, "onze");
assert_eq!(&mut Janet::from("dez"), table.entry(10).or_insert(10));
assert_eq!(&mut Janet::from("onze"), table.entry(11).or_insert(11));
Ok(())
}
#[test]
fn entry_api_and_modify() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, "dez");
{
let test_occupied = table
.entry(10)
.and_modify(|j| {
*j = Janet::boolean(true);
})
.or_insert(false);
assert_eq!(&mut Janet::boolean(true), test_occupied);
}
let test_vacant = table
.entry(11)
.and_modify(|j| {
*j = Janet::boolean(true);
})
.or_insert(false);
assert_eq!(&mut Janet::boolean(false), test_vacant);
Ok(())
}
#[test]
fn entry_api_key() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
table.insert(10, "dez");
{
let entry = table.entry(10);
let test_occupied = entry.key();
assert_eq!(&Janet::integer(10), test_occupied);
}
let entry = table.entry(11);
let test_vacant = entry.key();
assert_eq!(&Janet::integer(11), test_vacant);
Ok(())
}
#[test]
fn entry_api_insert() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = JanetTable::with_capacity(2);
let mut entry = table.entry(10).insert("dez");
assert_eq!(&Janet::integer(10), entry.key());
assert_eq!(&Janet::from("dez"), entry.get());
assert_eq!(&mut Janet::from("dez"), entry.get_mut());
assert_eq!(Janet::from("dez"), entry.insert("não dez"));
assert_eq!(&Janet::integer(10), entry.key());
assert_eq!(&Janet::from("não dez"), entry.get());
assert_eq!(&mut Janet::from("não dez"), entry.get_mut());
Ok(())
}
#[test]
fn iter() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let table = table! {10 => "dez", 11 => "onze"};
let mut iter = table.iter();
assert_eq!(
iter.next(),
Some((&Janet::integer(10), &Janet::from("dez")))
);
assert_eq!(
iter.next(),
Some((&Janet::integer(11), &Janet::from("onze")))
);
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
Ok(())
}
#[test]
fn itermut() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let mut table = table! {10 => "dez", 11 => "onze"};
let mut iter = table.iter_mut();
assert_eq!(
iter.next(),
Some((&Janet::integer(10), &mut Janet::from("dez")))
);
assert_eq!(
iter.next(),
Some((&Janet::integer(11), &mut Janet::from("onze")))
);
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
Ok(())
}
#[test]
fn intoiter() -> Result<(), crate::client::Error> {
let _client = JanetClient::init()?;
let table = table! {10 => "dez", 11 => "onze"};
let mut iter = table.into_iter();
assert_eq!(iter.next(), Some((Janet::integer(10), Janet::from("dez"))));
assert_eq!(iter.next(), Some((Janet::integer(11), Janet::from("onze"))));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
Ok(())
}
}