mirror of
https://github.com/noib3/nvim-oxi.git
synced 2025-08-04 19:08:31 +00:00
feat: add conversions from tuples of TryFrom<Object>
to Array
/Object
(#236)
This commit is contained in:
parent
80caa4cda4
commit
bac13dfcb1
3 changed files with 176 additions and 39 deletions
|
@ -11,6 +11,28 @@ use crate::Object;
|
|||
#[repr(transparent)]
|
||||
pub struct Array(pub(super) KVec<Object>);
|
||||
|
||||
/// An owning iterator over the `Object`s of a [`Array`].
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayIterator(kvec::IntoIter<Object>);
|
||||
|
||||
/// The error type returned when trying to convert an [`Array`] into a tuple.
|
||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||
pub enum ArrayFromTupleError<T> {
|
||||
/// Not enough elements in the array.
|
||||
#[error(
|
||||
"not enough elements in the array, expected {expected_len} but got \
|
||||
{actual_len}"
|
||||
)]
|
||||
NotEnoughElements { expected_len: usize, actual_len: usize },
|
||||
/// The tuple element at the given index couldn't be converted into the
|
||||
/// requested type.
|
||||
#[error(
|
||||
"couldn't convert tuple element at index {element_idx} into object: \
|
||||
{error:?}"
|
||||
)]
|
||||
ElementFromObject { element_idx: usize, error: T },
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Array {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
|
@ -120,10 +142,6 @@ impl IntoIterator for Array {
|
|||
}
|
||||
}
|
||||
|
||||
/// An owning iterator over the `Object`s of a [`Array`].
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayIterator(kvec::IntoIter<Object>);
|
||||
|
||||
impl Iterator for ArrayIterator {
|
||||
type Item = Object;
|
||||
|
||||
|
@ -207,7 +225,7 @@ impl lua::Pushable for Array {
|
|||
|
||||
/// Implements `From<(A, B, C, ..)>` for tuples `(A, B, C, ..)` where all the
|
||||
/// elements in the tuple are `Into<Object>`.
|
||||
macro_rules! from_tuple {
|
||||
macro_rules! array_from_tuple {
|
||||
($($ty:ident)*) => {
|
||||
impl <$($ty: Into<Object>),*> From<($($ty,)*)> for Array {
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -218,22 +236,84 @@ macro_rules! from_tuple {
|
|||
};
|
||||
}
|
||||
|
||||
from_tuple!(A);
|
||||
from_tuple!(A B);
|
||||
from_tuple!(A B C);
|
||||
from_tuple!(A B C D);
|
||||
from_tuple!(A B C D E);
|
||||
from_tuple!(A B C D E F);
|
||||
from_tuple!(A B C D E F G);
|
||||
from_tuple!(A B C D E F G H);
|
||||
from_tuple!(A B C D E F G H I);
|
||||
from_tuple!(A B C D E F G H I J);
|
||||
from_tuple!(A B C D E F G H I J K);
|
||||
from_tuple!(A B C D E F G H I J K L);
|
||||
from_tuple!(A B C D E F G H I J K L M);
|
||||
from_tuple!(A B C D E F G H I J K L M N);
|
||||
from_tuple!(A B C D E F G H I J K L M N O);
|
||||
from_tuple!(A B C D E F G H I J K L M N O P);
|
||||
array_from_tuple!(A);
|
||||
array_from_tuple!(A B);
|
||||
array_from_tuple!(A B C);
|
||||
array_from_tuple!(A B C D);
|
||||
array_from_tuple!(A B C D E);
|
||||
array_from_tuple!(A B C D E F);
|
||||
array_from_tuple!(A B C D E F G);
|
||||
array_from_tuple!(A B C D E F G H);
|
||||
array_from_tuple!(A B C D E F G H I);
|
||||
array_from_tuple!(A B C D E F G H I J);
|
||||
array_from_tuple!(A B C D E F G H I J K);
|
||||
array_from_tuple!(A B C D E F G H I J K L);
|
||||
array_from_tuple!(A B C D E F G H I J K L M);
|
||||
array_from_tuple!(A B C D E F G H I J K L M N);
|
||||
array_from_tuple!(A B C D E F G H I J K L M N O);
|
||||
array_from_tuple!(A B C D E F G H I J K L M N O P);
|
||||
|
||||
macro_rules! count {
|
||||
() => {0i32};
|
||||
($x:tt $($xs:tt)*) => {1i32 + count!($($xs)*)};
|
||||
}
|
||||
|
||||
/// Implements `TryFrom<Array>` for tuples `(A, B, C, ..)` where all the
|
||||
/// elements in the tuple are `TryFrom<Object>` with the same error.
|
||||
macro_rules! tuple_try_from_array {
|
||||
($($ty:ident)*) => {
|
||||
impl<Error, $($ty,)*> TryFrom<Array> for ($($ty,)*)
|
||||
where
|
||||
$($ty: TryFrom<Object, Error = Error>,)*
|
||||
{
|
||||
type Error = ArrayFromTupleError<Error>;
|
||||
|
||||
#[inline]
|
||||
#[allow(non_snake_case)]
|
||||
fn try_from(array: Array) -> Result<Self, Self::Error> {
|
||||
let actual_len = array.len();
|
||||
let expected_len = count!($($ty)*) as usize;
|
||||
|
||||
if actual_len < expected_len {
|
||||
return Err(ArrayFromTupleError::NotEnoughElements {
|
||||
expected_len,
|
||||
actual_len
|
||||
});
|
||||
}
|
||||
|
||||
let mut iter = array.into_iter();
|
||||
|
||||
$(
|
||||
let $ty = $ty::try_from(
|
||||
iter.next().expect("already checked len")
|
||||
).map_err(|error| ArrayFromTupleError::ElementFromObject {
|
||||
element_idx: actual_len - iter.len() - 1,
|
||||
error
|
||||
})?;
|
||||
)*
|
||||
|
||||
Ok(($($ty,)*))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tuple_try_from_array!(A);
|
||||
tuple_try_from_array!(A B);
|
||||
tuple_try_from_array!(A B C);
|
||||
tuple_try_from_array!(A B C D);
|
||||
tuple_try_from_array!(A B C D E);
|
||||
tuple_try_from_array!(A B C D E F);
|
||||
tuple_try_from_array!(A B C D E F G);
|
||||
tuple_try_from_array!(A B C D E F G H);
|
||||
tuple_try_from_array!(A B C D E F G H I);
|
||||
tuple_try_from_array!(A B C D E F G H I J);
|
||||
tuple_try_from_array!(A B C D E F G H I J K);
|
||||
tuple_try_from_array!(A B C D E F G H I J K L);
|
||||
tuple_try_from_array!(A B C D E F G H I J K L M);
|
||||
tuple_try_from_array!(A B C D E F G H I J K L M N);
|
||||
tuple_try_from_array!(A B C D E F G H I J K L M N O);
|
||||
tuple_try_from_array!(A B C D E F G H I J K L M N O P);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
|||
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
use crate::array::ArrayFromTupleError;
|
||||
use crate::{
|
||||
Array,
|
||||
Boolean,
|
||||
|
@ -33,6 +34,10 @@ pub enum Error {
|
|||
#[cfg(feature = "serde")]
|
||||
#[error(transparent)]
|
||||
Serialize(#[from] crate::serde::SerializeError),
|
||||
|
||||
#[doc(hidden)]
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Trait implemented for types can be obtained from an [`Object`].
|
||||
|
@ -77,8 +82,10 @@ impl FromObject for Boolean {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromObject for Integer {
|
||||
fn from_object(obj: Object) -> Result<Self, Error> {
|
||||
impl TryFrom<Object> for Integer {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(obj: Object) -> Result<Self, Self::Error> {
|
||||
match obj.kind() {
|
||||
ObjectKind::Integer
|
||||
| ObjectKind::Buffer
|
||||
|
@ -162,6 +169,13 @@ impl<A, R> FromObject for Function<A, R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: TryFrom<Object, Error = Error>> FromObject for T {
|
||||
#[inline]
|
||||
fn from_object(obj: Object) -> Result<Self, Error> {
|
||||
T::try_from(obj)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements `FromObject` for a type that implements `From<Integer>`.
|
||||
macro_rules! from_int {
|
||||
($integer:ty) => {
|
||||
|
@ -175,27 +189,30 @@ macro_rules! from_int {
|
|||
|
||||
from_int!(i128);
|
||||
|
||||
/// Implements `FromObject` for a type that implements `TryFrom<Integer>`.
|
||||
macro_rules! try_from_int {
|
||||
/// Implements `TryFrom<Object>` for a type that implements `TryFrom<Integer>`.
|
||||
macro_rules! int_try_from_obj {
|
||||
($integer:ty) => {
|
||||
impl FromObject for $integer {
|
||||
fn from_object(obj: Object) -> Result<Self, Error> {
|
||||
Integer::from_object(obj).and_then(|n| Ok(n.try_into()?))
|
||||
impl TryFrom<Object> for $integer {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(obj: Object) -> Result<Self, Self::Error> {
|
||||
Integer::try_from(obj)
|
||||
.and_then(|n| n.try_into().map_err(Into::into))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try_from_int!(i8);
|
||||
try_from_int!(u8);
|
||||
try_from_int!(i16);
|
||||
try_from_int!(u16);
|
||||
try_from_int!(i32);
|
||||
try_from_int!(u32);
|
||||
try_from_int!(u64);
|
||||
try_from_int!(u128);
|
||||
try_from_int!(isize);
|
||||
try_from_int!(usize);
|
||||
int_try_from_obj!(i8);
|
||||
int_try_from_obj!(u8);
|
||||
int_try_from_obj!(i16);
|
||||
int_try_from_obj!(u16);
|
||||
int_try_from_obj!(i32);
|
||||
int_try_from_obj!(u32);
|
||||
int_try_from_obj!(u64);
|
||||
int_try_from_obj!(u128);
|
||||
int_try_from_obj!(isize);
|
||||
int_try_from_obj!(usize);
|
||||
|
||||
impl FromObject for f32 {
|
||||
fn from_object(obj: Object) -> Result<Self, Error> {
|
||||
|
@ -231,6 +248,46 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Implements `FromObject` for tuples `(A, B, C, ..)` where all the
|
||||
/// elements in the tuple are `TryFrom<Object>` with the same error.
|
||||
macro_rules! tuple_from_object {
|
||||
($($ty:ident)*) => {
|
||||
impl<Err, $($ty,)*> FromObject for ($($ty,)*)
|
||||
where
|
||||
$($ty: TryFrom<Object, Error = Err>,)*
|
||||
Err: Into<self::Error> + core::error::Error,
|
||||
{
|
||||
#[inline]
|
||||
#[allow(non_snake_case)]
|
||||
fn from_object(obj: Object) -> Result<Self, Error> {
|
||||
Array::from_object(obj)?
|
||||
.try_into()
|
||||
.map_err(|err: ArrayFromTupleError<Err>| match err {
|
||||
ArrayFromTupleError::ElementFromObject { error, .. } => error.into(),
|
||||
err @ ArrayFromTupleError::NotEnoughElements { .. } => Error::Other(err.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tuple_from_object!(A);
|
||||
tuple_from_object!(A B);
|
||||
tuple_from_object!(A B C);
|
||||
tuple_from_object!(A B C D);
|
||||
tuple_from_object!(A B C D E);
|
||||
tuple_from_object!(A B C D E F);
|
||||
tuple_from_object!(A B C D E F G);
|
||||
tuple_from_object!(A B C D E F G H);
|
||||
tuple_from_object!(A B C D E F G H I);
|
||||
tuple_from_object!(A B C D E F G H I J);
|
||||
tuple_from_object!(A B C D E F G H I J K);
|
||||
tuple_from_object!(A B C D E F G H I J K L);
|
||||
tuple_from_object!(A B C D E F G H I J K L M);
|
||||
tuple_from_object!(A B C D E F G H I J K L M N);
|
||||
tuple_from_object!(A B C D E F G H I J K L M N O);
|
||||
tuple_from_object!(A B C D E F G H I J K L M N O P);
|
||||
|
||||
impl<T> ToObject for T
|
||||
where
|
||||
T: Into<Object>,
|
||||
|
|
|
@ -17,7 +17,7 @@ pub mod serde;
|
|||
mod string;
|
||||
|
||||
pub use arena::{arena, arena_init, Arena};
|
||||
pub use array::Array;
|
||||
pub use array::{Array, ArrayFromTupleError};
|
||||
pub use dictionary::{Dictionary, KeyValuePair};
|
||||
pub use error::Error;
|
||||
pub use function::Function;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue