Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more methods on Array and Dictionary #212

Merged
merged 6 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions crates/types/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::ops::{Deref, DerefMut};

use luajit as lua;

use crate::kvec::{self, KVec};
Expand Down Expand Up @@ -56,6 +58,35 @@ impl Array {
{
self.0.push(value.into());
}

/// Removes an `Object` from the `Array` and returns it.
///
/// The removed object is replaced by the last element of the array.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
#[track_caller]
#[inline]
pub fn swap_remove(&mut self, index: usize) -> Object {
self.0.swap_remove(index)
}
}

impl Deref for Array {
type Target = [Object];

#[inline]
fn deref(&self) -> &Self::Target {
self.0.as_slice()
}
}

impl DerefMut for Array {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut_slice()
}
}

impl<T: Into<Object>> FromIterator<T> for Array {
Expand Down
119 changes: 108 additions & 11 deletions crates/types/src/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ use crate::Object;
#[repr(transparent)]
pub struct Dictionary(pub(super) KVec<KeyValuePair>);

/// A key-value pair mapping a Neovim [`String`] to a Neovim [`Object`].
/// A key-value pair mapping a [`String`] to an [`Object`].
//
// https://github.com/neovim/neovim/blob/v0.9.0/src/nvim/api/private/defs.h#L122-L125
#[derive(Clone, PartialEq)]
#[repr(C)]
pub(super) struct KeyValuePair {
pub struct KeyValuePair {
key: crate::String,
value: Object,
}
Expand All @@ -42,13 +42,36 @@ impl core::fmt::Debug for Dictionary {
}

impl Dictionary {
/// Returns a slice of all key-value pairs in the dictionary.
#[inline]
pub fn as_slice(&self) -> &[KeyValuePair] {
&self.0
}

/// Returns a mutable slice of all key-value pairs in the dictionary.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [KeyValuePair] {
&mut self.0
}

/// Returns a reference to the value corresponding to the key.
#[inline]
pub fn get<Q>(&self, query: &Q) -> Option<&Object>
where
Q: ?Sized + PartialEq<crate::String>,
{
self.iter().find_map(|(key, value)| (query == key).then_some(value))
self.get_index(query).map(|idx| self.as_slice()[idx].value())
}

/// Returns the index of the key-value pair corresponding to the key.
#[inline]
pub fn get_index<Q>(&self, query: &Q) -> Option<usize>
where
Q: ?Sized + PartialEq<crate::String>,
{
self.keys()
.enumerate()
.find_map(|(idx, key)| (query == key).then_some(idx))
}

/// Returns a mutable reference to the value corresponding to the key.
Expand All @@ -57,8 +80,7 @@ impl Dictionary {
where
Q: ?Sized + PartialEq<crate::String>,
{
self.iter_mut()
.find_map(|(key, value)| (query == key).then_some(value))
self.get_index(query).map(|idx| self.as_mut_slice()[idx].value_mut())
}

/// Inserts a key-value pair into the dictionary.
Expand Down Expand Up @@ -98,6 +120,12 @@ impl Dictionary {
self.0.len()
}

/// Returns an iterator over the keys of the dictionary.
#[inline]
pub fn keys(&self) -> impl Iterator<Item = &crate::String> + '_ {
self.iter().map(|(key, _)| key)
}

/// Creates a new, empty `Dictionary`.
#[inline]
pub fn new() -> Self {
Expand All @@ -110,6 +138,75 @@ impl Dictionary {
#[allow(clippy::unnecessary_struct_initialization)]
NonOwning::new(Self(KVec { ..self.0 }))
}

/// Removes a `KeyValuePair` from the `Dictionary` and returns it.
///
/// The removed pair is replaced by the last element of the dictionary.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
#[track_caller]
#[inline]
pub fn swap_remove(&mut self, index: usize) -> KeyValuePair {
self.0.swap_remove(index)
}
}

impl KeyValuePair {
/// Consumes the `KeyValuePair` and returns the key.
#[inline]
pub fn into_key(self) -> crate::String {
self.key
}

/// Consumes the `KeyValuePair` and returns a `(key, value)` tuple.
#[inline]
pub fn into_tuple(self) -> (crate::String, Object) {
(self.key, self.value)
}

/// Consumes the `KeyValuePair` and returns the value.
#[inline]
pub fn into_value(self) -> Object {
self.value
}

/// Returns a shared reference to the key of the `KeyValuePair`.
#[inline]
pub fn key(&self) -> &crate::String {
&self.key
}

/// Returns an exclusive reference to the key of the `KeyValuePair`.
#[inline]
pub fn key_mut(&mut self) -> &mut crate::String {
&mut self.key
}

/// Returns references to both the key and value as a tuple.
#[inline]
pub fn tuple(&self) -> (&crate::String, &Object) {
(&self.key, &self.value)
}

/// Returns exclusive references to both the key and value as a tuple.
#[inline]
pub fn tuple_mut(&mut self) -> (&mut crate::String, &mut Object) {
(&mut self.key, &mut self.value)
}

/// Returns a shared reference to the value of the `KeyValuePair`.
#[inline]
pub fn value(&self) -> &Object {
&self.value
}

/// Returns an exclusive reference to the value of the `KeyValuePair`.
#[inline]
pub fn value_mut(&mut self) -> &mut Object {
&mut self.value
}
}

impl<S> core::ops::Index<S> for Dictionary
Expand Down Expand Up @@ -173,7 +270,7 @@ impl Iterator for DictIterator {

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|pair| (pair.key, pair.value))
self.0.next().map(KeyValuePair::into_tuple)
}

#[inline]
Expand All @@ -192,7 +289,7 @@ impl ExactSizeIterator for DictIterator {
impl DoubleEndedIterator for DictIterator {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|pair| (pair.key, pair.value))
self.0.next_back().map(KeyValuePair::into_tuple)
}
}

Expand All @@ -207,7 +304,7 @@ impl<'a> Iterator for DictIter<'a> {

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|pair| (&pair.key, &pair.value))
self.0.next().map(KeyValuePair::tuple)
}

#[inline]
Expand All @@ -226,7 +323,7 @@ impl ExactSizeIterator for DictIter<'_> {
impl DoubleEndedIterator for DictIter<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|pair| (&pair.key, &pair.value))
self.0.next_back().map(KeyValuePair::tuple)
}
}

Expand All @@ -240,7 +337,7 @@ impl<'a> Iterator for DictIterMut<'a> {

#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|pair| (&mut pair.key, &mut pair.value))
self.0.next().map(KeyValuePair::tuple_mut)
}

#[inline]
Expand All @@ -259,7 +356,7 @@ impl ExactSizeIterator for DictIterMut<'_> {
impl DoubleEndedIterator for DictIterMut<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back().map(|pair| (&mut pair.key, &mut pair.value))
self.0.next_back().map(KeyValuePair::tuple_mut)
}
}

Expand Down
64 changes: 64 additions & 0 deletions crates/types/src/kvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,28 @@ impl<T> KVec<T> {
self.size += 1;
}

/// Removes an element from the `KVec` and returns it.
///
/// The removed element is replaced by the last element of the vector.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
#[track_caller]
#[inline]
pub(crate) fn swap_remove(&mut self, index: usize) -> T {
let len = self.len();
if index >= len {
panic!("swap_remove index is {index}, but len is {len}");
}
unsafe {
let item = ptr::read(self.items.add(index));
ptr::copy(self.items.add(len - 1), self.items.add(index), 1);
self.size -= 1;
item
}
}

/// Creates a new, empty `KVec<T>` with the specified capacity.
#[inline]
pub(crate) fn with_capacity(capacity: usize) -> Self {
Expand Down Expand Up @@ -150,6 +172,34 @@ impl<T: PartialEq> PartialEq for KVec<T> {
}
}

impl<T: PartialEq> PartialEq<[T]> for KVec<T> {
#[inline]
fn eq(&self, other: &[T]) -> bool {
self.as_slice() == other
}
}

impl<T: PartialEq> PartialEq<&[T]> for KVec<T> {
#[inline]
fn eq(&self, other: &&[T]) -> bool {
self.as_slice() == *other
}
}

impl<const N: usize, T: PartialEq> PartialEq<[T; N]> for KVec<T> {
#[inline]
fn eq(&self, other: &[T; N]) -> bool {
self == other.as_slice()
}
}

impl<const N: usize, T: PartialEq> PartialEq<&[T; N]> for KVec<T> {
#[inline]
fn eq(&self, other: &&[T; N]) -> bool {
self == *other
}
}

impl<T> Deref for KVec<T> {
type Target = [T];

Expand Down Expand Up @@ -427,4 +477,18 @@ mod tests {
assert_eq!(Some("baz"), iter2.next().as_deref());
assert_eq!(None, iter2.next());
}

#[test]
fn swap_remove() {
let mut kvec = KVec::from_iter([1, 2, 3, 4]);
assert_eq!(kvec.swap_remove(1), 2);
assert_eq!(kvec, &[1, 4, 3]);
}

#[should_panic]
#[test]
fn swap_remove_oob() {
let mut kvec = KVec::from_iter([1, 2, 3, 4]);
kvec.swap_remove(kvec.len());
}
}
2 changes: 1 addition & 1 deletion crates/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod string;

pub use arena::{arena, arena_init, Arena};
pub use array::Array;
pub use dictionary::Dictionary;
pub use dictionary::{Dictionary, KeyValuePair};
pub use error::Error;
pub use function::Function;
pub use non_owning::NonOwning;
Expand Down
Loading