1use crate::kbox::KBox;
2use crate::type_traits::*;
3use crate::{k::K, ConversionError};
4use crate::{k_type::KTypeCode, kapi};
5use std::slice;
6use std::{marker::PhantomData, slice::SliceIndex};
7use std::{mem, str};
8use std::{ops, ptr::NonNull};
9
10use std::{
11 iter::FromIterator,
12 slice::{Iter, IterMut},
13};
14
15unsafe fn as_slice_uninit<'a, T>(k: *mut K) -> &'a mut [mem::MaybeUninit<T>] {
16 let list = &(*k).union.list;
17 slice::from_raw_parts_mut(&list.g0 as *const _ as *mut _, list.n as usize)
18}
19
20unsafe fn as_slice_mut<'a, T>(k: *mut K) -> &'a mut [T] {
21 let list = &(*k).union.list;
22 slice::from_raw_parts_mut(&list.g0 as *const _ as *mut _, list.n as usize)
23}
24
25unsafe fn as_slice<'a, T>(k: *const K) -> &'a [T] {
26 let list = &(*k).union.list;
27 slice::from_raw_parts(&list.g0 as *const _ as *const _, list.n as usize)
28}
29
30#[repr(transparent)]
54pub struct List<T> {
55 k: K,
56 _p: PhantomData<T>,
57}
58
59impl<T: KListable> List<T> {
60 #[inline]
62 pub fn as_slice(&self) -> &[T::ListItem] {
63 unsafe { as_slice(&self.k) }
64 }
65
66 #[inline]
68 pub fn as_slice_mut(&mut self) -> &mut [T::ListItem] {
69 unsafe { as_slice_mut(&mut self.k) }
70 }
71
72 #[inline]
74 pub fn iter(&self) -> Iter<T::ListItem> {
75 self.as_slice().iter()
76 }
77
78 #[inline]
80 pub fn len(&self) -> usize {
81 self.as_slice().len()
82 }
83
84 #[inline]
86 pub fn is_empty(&self) -> bool {
87 self.len() == 0
88 }
89
90 #[inline]
92 pub fn iter_mut(&mut self) -> IterMut<T::ListItem> {
93 self.as_slice_mut().iter_mut()
94 }
95
96 #[inline]
98 pub fn get<I: SliceIndex<[T::ListItem]>>(&self, index: I) -> Option<&I::Output> {
99 self.as_slice().get(index)
100 }
101
102 #[inline]
104 pub fn get_mut<I: SliceIndex<[T::ListItem]>>(&mut self, index: I) -> Option<&mut I::Output> {
105 self.as_slice_mut().get_mut(index)
106 }
107}
108
109impl<T: KListable> KBox<List<T>> {
110 #[inline]
115 pub fn new_list() -> Self {
116 unsafe { mem::transmute(kapi::ktn(T::LIST_TYPE_CODE.into(), 0)) }
117 }
118
119 #[inline]
121 pub fn join(&mut self, list: KBox<List<T>>) {
122 unsafe {
123 self.k = NonNull::new_unchecked(
124 kapi::jv(&mut (self.k.as_ptr() as *mut K), list.into_raw() as *const K) as *mut K as *mut List<T>
125 )
126 }
127 }
128
129 #[inline]
131 pub fn push(&mut self, item: T::ListItem) {
132 unsafe {
133 self.k = NonNull::new_unchecked(T::join_to(item, self.k.as_ptr() as *mut K) as *mut List<T>);
134 }
135 }
136}
137
138impl<T: KListable> KTyped for List<T> {
139 const K_TYPE: KTypeCode = T::LIST_TYPE_CODE;
140}
141
142impl List<i8> {
143 pub fn try_as_str(&self) -> Result<&str, ConversionError> {
147 #[allow(clippy::transmute_ptr_to_ptr)]
148 let s: &[u8] = unsafe { mem::transmute(self.as_slice()) };
149 Ok(str::from_utf8(s)?)
150 }
151
152 pub unsafe fn as_str_unchecked(&self) -> &str {
159 #[allow(clippy::transmute_ptr_to_ptr)]
160 let s: &[u8] = mem::transmute(self.as_slice());
161 str::from_utf8_unchecked(s)
162 }
163}
164
165impl<T> KObject for List<T> {
166 fn k_ptr(&self) -> *const K {
167 &self.k
168 }
169
170 fn k_ptr_mut(&mut self) -> *mut K {
171 &mut self.k
172 }
173}
174
175impl<T> private::Sealed for List<T> {}
176
177impl<T: KListable> ops::Index<ops::RangeFrom<usize>> for List<T> {
178 type Output = [T::ListItem];
179 fn index(&self, i: ops::RangeFrom<usize>) -> &Self::Output {
180 self.as_slice().index(i)
181 }
182}
183
184impl<T: KListable> ops::Index<ops::RangeTo<usize>> for List<T> {
185 type Output = [T::ListItem];
186 fn index(&self, i: ops::RangeTo<usize>) -> &Self::Output {
187 self.as_slice().index(i)
188 }
189}
190
191impl<T: KListable> ops::Index<ops::Range<usize>> for List<T> {
192 type Output = [T::ListItem];
193 fn index(&self, i: ops::Range<usize>) -> &Self::Output {
194 self.as_slice().index(i)
195 }
196}
197
198impl<T: KListable> ops::Index<usize> for List<T> {
199 type Output = T::ListItem;
200 fn index(&self, i: usize) -> &Self::Output {
201 self.as_slice().index(i)
202 }
203}
204
205impl<T: KListable> ops::Index<ops::RangeFull> for List<T> {
206 type Output = [T::ListItem];
207 fn index(&self, _: ops::RangeFull) -> &Self::Output {
208 self.as_slice()
209 }
210}
211
212impl<T: KListable> ops::IndexMut<ops::RangeFrom<usize>> for List<T> {
213 fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut Self::Output {
214 self.as_slice_mut().index_mut(i)
215 }
216}
217
218impl<T: KListable> ops::IndexMut<ops::RangeTo<usize>> for List<T> {
219 fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut Self::Output {
220 self.as_slice_mut().index_mut(i)
221 }
222}
223
224impl<T: KListable> ops::IndexMut<ops::Range<usize>> for List<T> {
225 fn index_mut(&mut self, i: ops::Range<usize>) -> &mut Self::Output {
226 self.as_slice_mut().index_mut(i)
227 }
228}
229
230impl<T: KListable> ops::IndexMut<usize> for List<T> {
231 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
232 self.as_slice_mut().index_mut(i)
233 }
234}
235
236impl<T: KListable> ops::IndexMut<ops::RangeFull> for List<T> {
237 fn index_mut(&mut self, _: ops::RangeFull) -> &mut Self::Output {
238 self.as_slice_mut()
239 }
240}
241
242impl<T: KListable> FromIterator<T::ListItem> for KBox<List<T>> {
243 fn from_iter<I: IntoIterator<Item = T::ListItem>>(iter: I) -> Self {
244 let iter = iter.into_iter();
245 match iter.size_hint() {
248 (x, Some(y)) if x == y => {
249 let k = unsafe { kapi::ktn(T::LIST_TYPE_CODE.into(), y as i64) };
250 let slice = unsafe { as_slice_uninit(k) };
251 slice
252 .iter_mut()
253 .zip(iter)
254 .for_each(|(dest, src)| *dest = mem::MaybeUninit::new(src));
255 unsafe { mem::transmute(k) }
256 }
257 _ => {
258 let mut list = Self::new_list();
259 list.extend(iter);
260 list
261 }
262 }
263 }
264}
265
266impl<T: KListable> Extend<T::ListItem> for KBox<List<T>> {
267 fn extend<I: IntoIterator<Item = T::ListItem>>(&mut self, iter: I) {
268 for item in iter {
269 self.push(item);
270 }
271 }
272}
273
274#[macro_export]
291macro_rules! list{
292 ($($expr:expr),+$(,)?) => {
293 list![_;$($expr,)+]
294 };
295 ($t:ty; $($expr:expr),+$(,)?) => {
296 vec![$($expr.into(),)+].into_iter().collect::<$crate::KBox<$crate::List<$t>>>()
297 };
298}
299
300#[cfg(test)]
301mod test {
302 #![allow(clippy::float_cmp)]
303
304 use crate::{symbol, Date, DateTime, Minute, Month, Second, Symbol, Time, Timespan, Timestamp};
305
306 #[cfg(feature = "uuid")]
307 use uuid::Uuid;
308
309 #[test]
310 pub fn list_macro_creates_lists() {
311 assert_eq!(6u8, list![u8; 1, 2, 3 ].iter().copied().sum());
312 assert_eq!(6i8, list![i8; 1, 2, 3 ].iter().copied().sum());
313 assert_eq!(6i16, list![i16; 1i16, 2i16, 3i16].iter().copied().sum());
314 assert_eq!(6i32, list![i32; 1, 2, 3 ].iter().copied().sum());
315 assert_eq!(6i64, list![i64; 1, 2, 3 ].iter().copied().sum());
316
317 assert_eq!(6f32, list![f32; 1., 2., 3. ].iter().copied().sum());
318 assert_eq!(6f64, list![f64; 1., 2., 3. ].iter().copied().sum());
319 assert_eq!(
320 vec![true, false, true],
321 list![bool; true, false, true].iter().copied().collect::<Vec<_>>()
322 );
323
324 assert_eq!(
325 vec![Second::from(1), Second::from(2), Second::from(3)],
326 list![Second; 1, 2, 3].iter().copied().collect::<Vec<_>>()
327 );
328
329 assert_eq!(
330 vec![Minute::from(1), Minute::from(2), Minute::from(3)],
331 list![Minute; 1, 2, 3].iter().copied().collect::<Vec<_>>()
332 );
333
334 assert_eq!(
335 vec![Month::from(1), Month::from(2), Month::from(3)],
336 list![Month; 1, 2, 3].iter().copied().collect::<Vec<_>>()
337 );
338
339 assert_eq!(
340 vec![Time::from(1), Time::from(2), Time::from(3)],
341 list![Time; 1, 2, 3].iter().copied().collect::<Vec<_>>()
342 );
343 assert_eq!(
344 vec![Date::new(2020, 1, 1), Date::new(2020, 1, 2), Date::new(2020, 1, 3)],
345 list![Date; Date::new(2020, 1, 1), Date::new(2020, 1, 2), Date::new(2020, 1, 3)]
346 .iter()
347 .copied()
348 .collect::<Vec<_>>()
349 );
350 assert_eq!(
351 vec![DateTime::from(1.), DateTime::from(2.), DateTime::from(3.)],
352 list![DateTime; 1., 2., 3.].iter().copied().collect::<Vec<_>>()
353 );
354 assert_eq!(
355 vec![Timestamp::from(1), Timestamp::from(2), Timestamp::from(3)],
356 list![Timestamp; 1, 2, 3].iter().copied().collect::<Vec<_>>()
357 );
358 assert_eq!(
359 vec![Timespan::from(1), Timespan::from(2), Timespan::from(3)],
360 list![Timespan; 1, 2, 3].iter().copied().collect::<Vec<_>>()
361 );
362
363 assert_eq!(
364 vec![symbol("Hello"), symbol("World")],
365 list![Symbol; symbol("Hello"), symbol("World")]
366 .iter()
367 .copied()
368 .collect::<Vec<_>>()
369 );
370
371 #[cfg(feature = "uuid")]
372 assert_eq!(
373 vec![Uuid::from_u128(1), Uuid::from_u128(2), Uuid::from_u128(3)],
374 list![Uuid;Uuid::from_u128(1), Uuid::from_u128(2), Uuid::from_u128(3)]
375 .iter()
376 .copied()
377 .collect::<Vec<_>>()
378 );
379 }
380}