use crate::kbox::KBox;
use crate::type_traits::*;
use crate::{k::K, ConversionError};
use crate::{k_type::KTypeCode, kapi};
use std::slice;
use std::{marker::PhantomData, slice::SliceIndex};
use std::{mem, str};
use std::{ops, ptr::NonNull};
use std::{
iter::FromIterator,
slice::{Iter, IterMut},
};
unsafe fn as_slice_uninit<'a, T>(k: *mut K) -> &'a mut [mem::MaybeUninit<T>] {
let list = &(*k).union.list;
slice::from_raw_parts_mut(&list.g0 as *const _ as *mut _, list.n as usize)
}
unsafe fn as_slice_mut<'a, T>(k: *mut K) -> &'a mut [T] {
let list = &(*k).union.list;
slice::from_raw_parts_mut(&list.g0 as *const _ as *mut _, list.n as usize)
}
unsafe fn as_slice<'a, T>(k: *const K) -> &'a [T] {
let list = &(*k).union.list;
slice::from_raw_parts(&list.g0 as *const _ as *const _, list.n as usize)
}
#[repr(transparent)]
pub struct List<T> {
k: K,
_p: PhantomData<T>,
}
impl<T: KListable> List<T> {
#[inline]
pub fn as_slice(&self) -> &[T::ListItem] {
unsafe { as_slice(&self.k) }
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [T::ListItem] {
unsafe { as_slice_mut(&mut self.k) }
}
#[inline]
pub fn iter(&self) -> Iter<T::ListItem> {
self.as_slice().iter()
}
#[inline]
pub fn len(&self) -> usize {
self.as_slice().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T::ListItem> {
self.as_slice_mut().iter_mut()
}
#[inline]
pub fn get<I: SliceIndex<[T::ListItem]>>(&self, index: I) -> Option<&I::Output> {
self.as_slice().get(index)
}
#[inline]
pub fn get_mut<I: SliceIndex<[T::ListItem]>>(&mut self, index: I) -> Option<&mut I::Output> {
self.as_slice_mut().get_mut(index)
}
}
impl<T: KListable> KBox<List<T>> {
#[inline]
pub fn new_list() -> Self {
unsafe { mem::transmute(kapi::ktn(T::LIST_TYPE_CODE.into(), 0)) }
}
#[inline]
pub fn join(&mut self, list: KBox<List<T>>) {
unsafe {
self.k = NonNull::new_unchecked(
kapi::jv(&mut (self.k.as_ptr() as *mut K), list.into_raw() as *const K) as *mut K as *mut List<T>
)
}
}
#[inline]
pub fn push(&mut self, item: T::ListItem) {
unsafe {
self.k = NonNull::new_unchecked(T::join_to(item, self.k.as_ptr() as *mut K) as *mut List<T>);
}
}
}
impl<T: KListable> KTyped for List<T> {
const K_TYPE: KTypeCode = T::LIST_TYPE_CODE;
}
impl List<i8> {
pub fn try_as_str(&self) -> Result<&str, ConversionError> {
#[allow(clippy::transmute_ptr_to_ptr)]
let s: &[u8] = unsafe { mem::transmute(self.as_slice()) };
Ok(str::from_utf8(s)?)
}
pub unsafe fn as_str_unchecked(&self) -> &str {
#[allow(clippy::transmute_ptr_to_ptr)]
let s: &[u8] = mem::transmute(self.as_slice());
str::from_utf8_unchecked(s)
}
}
impl<T> KObject for List<T> {
fn k_ptr(&self) -> *const K {
&self.k
}
fn k_ptr_mut(&mut self) -> *mut K {
&mut self.k
}
}
impl<T> private::Sealed for List<T> {}
impl<T: KListable> ops::Index<ops::RangeFrom<usize>> for List<T> {
type Output = [T::ListItem];
fn index(&self, i: ops::RangeFrom<usize>) -> &Self::Output {
self.as_slice().index(i)
}
}
impl<T: KListable> ops::Index<ops::RangeTo<usize>> for List<T> {
type Output = [T::ListItem];
fn index(&self, i: ops::RangeTo<usize>) -> &Self::Output {
self.as_slice().index(i)
}
}
impl<T: KListable> ops::Index<ops::Range<usize>> for List<T> {
type Output = [T::ListItem];
fn index(&self, i: ops::Range<usize>) -> &Self::Output {
self.as_slice().index(i)
}
}
impl<T: KListable> ops::Index<usize> for List<T> {
type Output = T::ListItem;
fn index(&self, i: usize) -> &Self::Output {
self.as_slice().index(i)
}
}
impl<T: KListable> ops::Index<ops::RangeFull> for List<T> {
type Output = [T::ListItem];
fn index(&self, _: ops::RangeFull) -> &Self::Output {
self.as_slice()
}
}
impl<T: KListable> ops::IndexMut<ops::RangeFrom<usize>> for List<T> {
fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut Self::Output {
self.as_slice_mut().index_mut(i)
}
}
impl<T: KListable> ops::IndexMut<ops::RangeTo<usize>> for List<T> {
fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut Self::Output {
self.as_slice_mut().index_mut(i)
}
}
impl<T: KListable> ops::IndexMut<ops::Range<usize>> for List<T> {
fn index_mut(&mut self, i: ops::Range<usize>) -> &mut Self::Output {
self.as_slice_mut().index_mut(i)
}
}
impl<T: KListable> ops::IndexMut<usize> for List<T> {
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
self.as_slice_mut().index_mut(i)
}
}
impl<T: KListable> ops::IndexMut<ops::RangeFull> for List<T> {
fn index_mut(&mut self, _: ops::RangeFull) -> &mut Self::Output {
self.as_slice_mut()
}
}
impl<T: KListable> FromIterator<T::ListItem> for KBox<List<T>> {
fn from_iter<I: IntoIterator<Item = T::ListItem>>(iter: I) -> Self {
let iter = iter.into_iter();
match iter.size_hint() {
(x, Some(y)) if x == y => {
let k = unsafe { kapi::ktn(T::LIST_TYPE_CODE.into(), y as i64) };
let slice = unsafe { as_slice_uninit(k) };
slice
.iter_mut()
.zip(iter)
.for_each(|(dest, src)| *dest = mem::MaybeUninit::new(src));
unsafe { mem::transmute(k) }
}
_ => {
let mut list = Self::new_list();
list.extend(iter);
list
}
}
}
}
impl<T: KListable> Extend<T::ListItem> for KBox<List<T>> {
fn extend<I: IntoIterator<Item = T::ListItem>>(&mut self, iter: I) {
for item in iter {
self.push(item);
}
}
}
#[macro_export]
macro_rules! list{
($($expr:expr),+$(,)?) => {
list![_;$($expr,)+]
};
($t:ty; $($expr:expr),+$(,)?) => {
vec![$($expr.into(),)+].into_iter().collect::<$crate::KBox<$crate::List<$t>>>()
};
}
#[cfg(test)]
mod test {
#![allow(clippy::float_cmp)]
use crate::{symbol, Date, DateTime, Minute, Month, Second, Symbol, Time, Timespan, Timestamp};
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[test]
pub fn list_macro_creates_lists() {
assert_eq!(6u8, list![u8; 1, 2, 3 ].iter().copied().sum());
assert_eq!(6i8, list![i8; 1, 2, 3 ].iter().copied().sum());
assert_eq!(6i16, list![i16; 1i16, 2i16, 3i16].iter().copied().sum());
assert_eq!(6i32, list![i32; 1, 2, 3 ].iter().copied().sum());
assert_eq!(6i64, list![i64; 1, 2, 3 ].iter().copied().sum());
assert_eq!(6f32, list![f32; 1., 2., 3. ].iter().copied().sum());
assert_eq!(6f64, list![f64; 1., 2., 3. ].iter().copied().sum());
assert_eq!(
vec![true, false, true],
list![bool; true, false, true].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Second::from(1), Second::from(2), Second::from(3)],
list![Second; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Minute::from(1), Minute::from(2), Minute::from(3)],
list![Minute; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Month::from(1), Month::from(2), Month::from(3)],
list![Month; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Time::from(1), Time::from(2), Time::from(3)],
list![Time; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Date::new(2020, 1, 1), Date::new(2020, 1, 2), Date::new(2020, 1, 3)],
list![Date; Date::new(2020, 1, 1), Date::new(2020, 1, 2), Date::new(2020, 1, 3)]
.iter()
.copied()
.collect::<Vec<_>>()
);
assert_eq!(
vec![DateTime::from(1.), DateTime::from(2.), DateTime::from(3.)],
list![DateTime; 1., 2., 3.].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Timestamp::from(1), Timestamp::from(2), Timestamp::from(3)],
list![Timestamp; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![Timespan::from(1), Timespan::from(2), Timespan::from(3)],
list![Timespan; 1, 2, 3].iter().copied().collect::<Vec<_>>()
);
assert_eq!(
vec![symbol("Hello"), symbol("World")],
list![Symbol; symbol("Hello"), symbol("World")]
.iter()
.copied()
.collect::<Vec<_>>()
);
#[cfg(feature = "uuid")]
assert_eq!(
vec![Uuid::from_u128(1), Uuid::from_u128(2), Uuid::from_u128(3)],
list![Uuid;Uuid::from_u128(1), Uuid::from_u128(2), Uuid::from_u128(3)]
.iter()
.copied()
.collect::<Vec<_>>()
);
}
}