1use super::{Enlist, List, ListCell, ListHead};
2use crate::memcx::MemCx;
3use crate::pg_sys;
4use crate::ptr::PointerExt;
5use crate::seal::Sealed;
6use core::cmp;
7use core::ffi;
8use core::marker::PhantomData;
9use core::mem;
10use core::ops::{Bound, Deref, DerefMut, RangeBounds};
11use core::ptr::{self, NonNull};
12use core::slice;
13
14impl<T: Enlist> Deref for ListCell<T> {
15 type Target = T;
16
17 fn deref(&self) -> &Self::Target {
18 unsafe { &*T::apoptosis(&self.cell as *const _ as *mut _) }
23 }
24}
25
26impl<T: Enlist> DerefMut for ListCell<T> {
27 fn deref_mut(&mut self) -> &mut Self::Target {
28 unsafe { &mut *T::apoptosis(&mut self.cell) }
31 }
32}
33
34impl Sealed for *mut ffi::c_void {}
35unsafe impl Enlist for *mut ffi::c_void {
36 const LIST_TAG: pg_sys::NodeTag = pg_sys::NodeTag::T_List;
37
38 unsafe fn apoptosis(cell: *mut pg_sys::ListCell) -> *mut *mut ffi::c_void {
39 unsafe { ptr::addr_of_mut!((*cell).ptr_value) }
40 }
41
42 fn endocytosis(cell: &mut pg_sys::ListCell, value: Self) {
43 cell.ptr_value = value;
44 }
45}
46
47impl Sealed for ffi::c_int {}
48unsafe impl Enlist for ffi::c_int {
49 const LIST_TAG: pg_sys::NodeTag = pg_sys::NodeTag::T_IntList;
50
51 unsafe fn apoptosis(cell: *mut pg_sys::ListCell) -> *mut ffi::c_int {
52 unsafe { ptr::addr_of_mut!((*cell).int_value) }
53 }
54
55 fn endocytosis(cell: &mut pg_sys::ListCell, value: Self) {
56 cell.int_value = value;
57 }
58}
59
60impl Sealed for pg_sys::Oid {}
61unsafe impl Enlist for pg_sys::Oid {
62 const LIST_TAG: pg_sys::NodeTag = pg_sys::NodeTag::T_OidList;
63
64 unsafe fn apoptosis(cell: *mut pg_sys::ListCell) -> *mut pg_sys::Oid {
65 unsafe { ptr::addr_of_mut!((*cell).oid_value) }
66 }
67
68 fn endocytosis(cell: &mut pg_sys::ListCell, value: Self) {
69 cell.oid_value = value;
70 }
71}
72
73#[cfg(any(feature = "pg16", feature = "pg17"))]
74impl Sealed for pg_sys::TransactionId {}
75#[cfg(any(feature = "pg16", feature = "pg17"))]
76unsafe impl Enlist for pg_sys::TransactionId {
77 const LIST_TAG: pg_sys::NodeTag = pg_sys::NodeTag::T_XidList;
78
79 unsafe fn apoptosis(cell: *mut pg_sys::ListCell) -> *mut pg_sys::TransactionId {
80 unsafe { ptr::addr_of_mut!((*cell).xid_value) }
81 }
82
83 fn endocytosis(cell: &mut pg_sys::ListCell, value: Self) {
84 cell.xid_value = value;
85 }
86}
87
88impl<'cx, T: Enlist> List<'cx, T> {
89 pub fn get(&self, index: usize) -> Option<&T> {
91 self.as_cells().get(index).map(Deref::deref)
92 }
93
94 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
96 self.as_cells_mut().get_mut(index).map(DerefMut::deref_mut)
97 }
98
99 pub fn unstable_push_in_context(
106 &mut self,
107 value: T,
108 mcx: &'cx MemCx<'_>,
109 ) -> &mut ListHead<'cx, T> {
110 match self {
111 List::Nil => {
112 let list_size = 128;
114 unsafe {
115 let list: *mut pg_sys::List = mcx.alloc_bytes(list_size).cast();
116 assert!(list.is_non_null());
117 (*list).type_ = T::LIST_TAG;
118 (*list).max_length = ((list_size - mem::size_of::<pg_sys::List>())
119 / mem::size_of::<pg_sys::ListCell>())
120 as _;
121 (*list).elements = ptr::addr_of_mut!((*list).initial_elements).cast();
122 T::endocytosis((*list).elements.as_mut().unwrap(), value);
123 (*list).length = 1;
124 *self = Self::downcast_ptr_in_memcx(list, mcx).unwrap();
125 assert_eq!(1, self.len());
126 match self {
127 List::Cons(head) => head,
128 _ => unreachable!(),
129 }
130 }
131 }
132 List::Cons(head) => head.push(value),
133 }
134 }
135
136 pub fn drain<R>(&mut self, range: R) -> Drain<'_, 'cx, T>
141 where
142 R: RangeBounds<usize>,
143 {
144 let len = self.len();
147 let drain_start = match range.start_bound() {
148 Bound::Unbounded | Bound::Included(0) => 0,
149 Bound::Included(first) => *first,
150 Bound::Excluded(point) => point + 1,
151 };
152 let tail_start = match range.end_bound() {
153 Bound::Unbounded => cmp::min(ffi::c_int::MAX as _, len),
154 Bound::Included(last) => last + 1,
155 Bound::Excluded(tail) => *tail,
156 };
157 let Some(tail_len) = len.checked_sub(tail_start) else {
158 panic!("index out of bounds of list!")
159 };
160 assert!(drain_start <= len);
162 assert!(tail_start <= len);
163
164 assert!(tail_start <= ffi::c_int::MAX as _);
166 assert!(drain_start + tail_len <= ffi::c_int::MAX as _);
167
168 let raw = if drain_start == 0 {
170 mem::take(self).into_ptr()
171 } else {
172 match self {
174 List::Nil => ptr::null_mut(),
175 List::Cons(head) => head.list.as_ptr().cast(),
176 }
177 };
178
179 if raw.is_non_null() {
181 unsafe { (*raw).length = drain_start as _ };
185 let cells_ptr = unsafe { (*raw).elements };
186 let iter = unsafe {
187 RawCellIter {
188 ptr: cells_ptr.add(drain_start).cast(),
189 end: cells_ptr.add(tail_start).cast(),
190 }
191 };
192 Drain { tail_len: tail_len as _, tail_start: tail_start as _, raw, origin: self, iter }
193 } else {
194 assert!(tail_len == 0 && tail_start == 0 && drain_start == 0);
197 Drain { tail_len: 0, tail_start: 0, raw, origin: self, iter: Default::default() }
198 }
199 }
200
201 pub fn iter(&self) -> impl Iterator<Item = &T> {
202 self.as_cells().into_iter().map(Deref::deref)
203 }
204
205 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
206 self.as_cells_mut().into_iter().map(DerefMut::deref_mut)
207 }
208}
209
210impl<T> List<'_, T> {
211 pub fn as_cells(&self) -> &[ListCell<T>] {
220 unsafe {
221 match self {
222 List::Nil => &[],
223 List::Cons(inner) => slice::from_raw_parts(inner.as_cells_ptr(), inner.len()),
224 }
225 }
226 }
227
228 pub fn as_cells_mut(&mut self) -> &mut [ListCell<T>] {
236 unsafe {
244 match self {
245 List::Nil => &mut [],
246 List::Cons(inner) => {
247 slice::from_raw_parts_mut(inner.as_mut_cells_ptr(), inner.len())
248 }
249 }
250 }
251 }
252}
253
254impl<T> ListHead<'_, T> {
255 #[inline]
256 pub fn capacity(&self) -> usize {
257 unsafe { self.list.as_ref().max_length as usize }
258 }
259
260 pub fn as_cells(&self) -> &[ListCell<T>] {
266 unsafe { slice::from_raw_parts(self.as_cells_ptr(), self.len()) }
267 }
268
269 pub fn as_cells_ptr(&self) -> *const ListCell<T> {
270 unsafe { (*self.list.as_ptr()).elements.cast() }
271 }
272
273 pub fn as_mut_cells_ptr(&mut self) -> *mut ListCell<T> {
274 unsafe { (*self.list.as_ptr()).elements.cast() }
275 }
276}
277
278impl<T: Enlist> ListHead<'_, T> {
279 pub fn push(&mut self, value: T) -> &mut Self {
280 let list = unsafe { self.list.as_mut() };
281 let pg_sys::List { length, max_length, elements, .. } = list;
282 assert!(*max_length > 0);
283 assert!(*length > 0);
284 assert!(*max_length >= *length);
285 if *max_length - *length < 1 {
286 self.reserve(*max_length as _);
287 }
288
289 let cell = unsafe { &mut *elements.add(*length as _) };
292 T::endocytosis(cell, value);
293 *length += 1;
294 self
295 }
296
297 pub fn reserve(&mut self, count: usize) -> &mut Self {
298 let list = unsafe { self.list.as_mut() };
299 assert!(list.length > 0);
300 assert!(list.max_length > 0);
301 if ((list.max_length - list.length) as usize) < count {
302 let size = i32::try_from(count).unwrap();
303 let size = list.length.checked_add(size).unwrap();
304 let size = usize::try_from(size).unwrap();
305 unsafe { grow_list(list, size) };
306 };
307 self
308 }
309}
310
311unsafe fn grow_list(list: &mut pg_sys::List, target: usize) {
312 assert!((i32::MAX as usize) >= target, "Cannot allocate more than c_int::MAX elements");
313 let alloc_size = target * mem::size_of::<pg_sys::ListCell>();
314 if list.elements == ptr::addr_of_mut!(list.initial_elements).cast() {
315 let context = pg_sys::GetMemoryChunkContext(list as *mut pg_sys::List as *mut _);
317 if context.is_null() {
318 panic!("Context free list?");
319 }
320 let buf = pg_sys::MemoryContextAlloc(context, alloc_size);
321 if buf.is_null() {
322 panic!("List allocation failure");
323 }
324 ptr::copy_nonoverlapping(list.elements, buf.cast(), list.length as _);
325 #[cfg(debug_assertions)]
327 ptr::write_bytes(list.elements, 0x7F, list.length as _);
328 list.elements = buf.cast();
329 } else {
330 list.elements = pg_sys::repalloc(list.elements.cast(), alloc_size).cast();
332 }
333
334 list.max_length = target as _;
335}
336
337unsafe fn destroy_list(list: *mut pg_sys::List) {
338 if (*list).elements != ptr::addr_of_mut!((*list).initial_elements).cast() {
340 pg_sys::pfree((*list).elements.cast());
341 }
342 pg_sys::pfree(list.cast());
343}
344
345#[derive(Debug)]
346pub struct ListIter<'a, T> {
347 list: List<'a, T>,
348 iter: RawCellIter<T>,
349}
350
351#[derive(Debug)]
353pub struct Drain<'a, 'cx, T> {
354 tail_start: u32,
356 tail_len: u32,
358 iter: RawCellIter<T>,
360 origin: &'a mut List<'cx, T>,
361 raw: *mut pg_sys::List,
362}
363
364impl<'a, 'cx, T> Drop for Drain<'a, 'cx, T> {
365 fn drop(&mut self) {
366 if self.raw.is_null() {
367 return;
368 }
369
370 unsafe {
372 let len = (*self.raw).length;
374 if len == 0 && self.tail_len == 0 {
375 destroy_list(self.raw)
377 } else {
378 let src = (*self.raw).elements.add(self.tail_start as _);
380 let dst = (*self.raw).elements.add(len as _);
381 ptr::copy(src, dst, self.tail_len as _); (*self.raw).length = len + (self.tail_len as ffi::c_int);
383
384 *self.origin = List::Cons(ListHead {
386 list: NonNull::new_unchecked(self.raw),
387 _type: PhantomData,
388 });
389 }
390 }
391 }
392}
393
394impl<T: Enlist> Iterator for Drain<'_, '_, T> {
395 type Item = T;
396
397 fn next(&mut self) -> Option<Self::Item> {
398 self.iter.next()
399 }
400}
401
402impl<T: Enlist> Iterator for ListIter<'_, T> {
403 type Item = T;
404
405 fn next(&mut self) -> Option<Self::Item> {
406 self.iter.next()
407 }
408}
409
410impl<'a, T: Enlist> IntoIterator for List<'a, T> {
411 type IntoIter = ListIter<'a, T>;
412 type Item = T;
413
414 fn into_iter(mut self) -> Self::IntoIter {
415 let len = self.len();
416 let iter = match &mut self {
417 List::Nil => Default::default(),
418 List::Cons(head) => {
419 let ptr = head.as_mut_cells_ptr();
420 let end = unsafe { ptr.add(len) };
421 RawCellIter { ptr, end }
422 }
423 };
424 ListIter { list: self, iter }
425 }
426}
427
428impl<'a, T> Drop for ListIter<'a, T> {
429 fn drop(&mut self) {
430 if let List::Cons(head) = &mut self.list {
431 unsafe { destroy_list(head.list.as_ptr()) }
432 }
433 }
434}
435
436#[derive(Debug, PartialEq)]
445struct RawCellIter<T> {
446 ptr: *mut ListCell<T>,
447 end: *mut ListCell<T>,
448}
449
450impl<T> Default for RawCellIter<T> {
451 fn default() -> Self {
452 RawCellIter { ptr: ptr::null_mut(), end: ptr::null_mut() }
453 }
454}
455
456impl<T: Enlist> Iterator for RawCellIter<T> {
457 type Item = T;
458
459 #[inline]
460 fn next(&mut self) -> Option<T> {
461 if self.ptr < self.end {
462 let ptr = self.ptr;
463 unsafe {
465 self.ptr = ptr.add(1);
466 Some(T::apoptosis(ptr.cast()).read())
467 }
468 } else {
469 None
470 }
471 }
472}