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", feature = "pg18", feature = "pg19"))]
74impl Sealed for pg_sys::TransactionId {}
75#[cfg(any(feature = "pg16", feature = "pg17", feature = "pg18", feature = "pg19"))]
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 =
116 mcx.alloc_bytes(list_size).unwrap().cast().as_ptr();
117 assert!(list.is_non_null());
118 (*list).type_ = T::LIST_TAG;
119 (*list).max_length = ((list_size - mem::size_of::<pg_sys::List>())
120 / mem::size_of::<pg_sys::ListCell>())
121 as _;
122 (*list).elements = ptr::addr_of_mut!((*list).initial_elements).cast();
123 T::endocytosis((*list).elements.as_mut().unwrap(), value);
124 (*list).length = 1;
125 *self = Self::downcast_ptr_in_memcx(list, mcx).unwrap();
126 assert_eq!(1, self.len());
127 match self {
128 List::Cons(head) => head,
129 _ => unreachable!(),
130 }
131 }
132 }
133 List::Cons(head) => head.push(value),
134 }
135 }
136
137 pub fn drain<R>(&mut self, range: R) -> Drain<'_, 'cx, T>
142 where
143 R: RangeBounds<usize>,
144 {
145 let len = self.len();
148 let drain_start = match range.start_bound() {
149 Bound::Unbounded | Bound::Included(0) => 0,
150 Bound::Included(first) => *first,
151 Bound::Excluded(point) => point + 1,
152 };
153 let tail_start = match range.end_bound() {
154 Bound::Unbounded => cmp::min(ffi::c_int::MAX as _, len),
155 Bound::Included(last) => last + 1,
156 Bound::Excluded(tail) => *tail,
157 };
158 let Some(tail_len) = len.checked_sub(tail_start) else {
159 panic!("index out of bounds of list!")
160 };
161 assert!(drain_start <= len);
163 assert!(tail_start <= len);
164
165 assert!(tail_start <= ffi::c_int::MAX as _);
167 assert!(drain_start + tail_len <= ffi::c_int::MAX as _);
168
169 let raw = if drain_start == 0 {
171 mem::take(self).into_ptr()
172 } else {
173 match self {
175 List::Nil => ptr::null_mut(),
176 List::Cons(head) => head.list.as_ptr().cast(),
177 }
178 };
179
180 if raw.is_non_null() {
182 unsafe { (*raw).length = drain_start as _ };
186 let cells_ptr = unsafe { (*raw).elements };
187 let iter = unsafe {
188 RawCellIter {
189 ptr: cells_ptr.add(drain_start).cast(),
190 end: cells_ptr.add(tail_start).cast(),
191 }
192 };
193 Drain { tail_len: tail_len as _, tail_start: tail_start as _, raw, origin: self, iter }
194 } else {
195 assert!(tail_len == 0 && tail_start == 0 && drain_start == 0);
198 Drain { tail_len: 0, tail_start: 0, raw, origin: self, iter: Default::default() }
199 }
200 }
201
202 pub fn iter(&self) -> impl Iterator<Item = &T> {
203 self.as_cells().into_iter().map(Deref::deref)
204 }
205
206 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
207 self.as_cells_mut().into_iter().map(DerefMut::deref_mut)
208 }
209}
210
211impl<T> List<'_, T> {
212 pub fn as_cells(&self) -> &[ListCell<T>] {
221 unsafe {
222 match self {
223 List::Nil => &[],
224 List::Cons(inner) => slice::from_raw_parts(inner.as_cells_ptr(), inner.len()),
225 }
226 }
227 }
228
229 pub fn as_cells_mut(&mut self) -> &mut [ListCell<T>] {
237 unsafe {
245 match self {
246 List::Nil => &mut [],
247 List::Cons(inner) => {
248 slice::from_raw_parts_mut(inner.as_mut_cells_ptr(), inner.len())
249 }
250 }
251 }
252 }
253}
254
255impl<T> ListHead<'_, T> {
256 #[inline]
257 pub fn capacity(&self) -> usize {
258 unsafe { self.list.as_ref().max_length as usize }
259 }
260
261 pub fn as_cells(&self) -> &[ListCell<T>] {
267 unsafe { slice::from_raw_parts(self.as_cells_ptr(), self.len()) }
268 }
269
270 pub fn as_cells_ptr(&self) -> *const ListCell<T> {
271 unsafe { (*self.list.as_ptr()).elements.cast() }
272 }
273
274 pub fn as_mut_cells_ptr(&mut self) -> *mut ListCell<T> {
275 unsafe { (*self.list.as_ptr()).elements.cast() }
276 }
277}
278
279impl<T: Enlist> ListHead<'_, T> {
280 pub fn push(&mut self, value: T) -> &mut Self {
281 let list = unsafe { self.list.as_mut() };
282 let pg_sys::List { length, max_length, elements, .. } = list;
283 assert!(*max_length > 0);
284 assert!(*length > 0);
285 assert!(*max_length >= *length);
286 if *max_length - *length < 1 {
287 self.reserve(*max_length as _);
288 }
289
290 let cell = unsafe { &mut *elements.add(*length as _) };
293 T::endocytosis(cell, value);
294 *length += 1;
295 self
296 }
297
298 pub fn reserve(&mut self, count: usize) -> &mut Self {
299 let list = unsafe { self.list.as_mut() };
300 assert!(list.length > 0);
301 assert!(list.max_length > 0);
302 if ((list.max_length - list.length) as usize) < count {
303 let size = i32::try_from(count).unwrap();
304 let size = list.length.checked_add(size).unwrap();
305 let size = usize::try_from(size).unwrap();
306 unsafe { grow_list(list, size) };
307 };
308 self
309 }
310}
311
312unsafe fn grow_list(list: &mut pg_sys::List, target: usize) {
313 assert!((i32::MAX as usize) >= target, "Cannot allocate more than c_int::MAX elements");
314 let alloc_size = target * mem::size_of::<pg_sys::ListCell>();
315 if list.elements == ptr::addr_of_mut!(list.initial_elements).cast() {
316 let context = pg_sys::GetMemoryChunkContext(list as *mut pg_sys::List as *mut _);
318 if context.is_null() {
319 panic!("Context free list?");
320 }
321 let buf = pg_sys::MemoryContextAlloc(context, alloc_size);
322 if buf.is_null() {
323 panic!("List allocation failure");
324 }
325 ptr::copy_nonoverlapping(list.elements, buf.cast(), list.length as _);
326 #[cfg(debug_assertions)]
328 ptr::write_bytes(list.elements, 0x7F, list.length as _);
329 list.elements = buf.cast();
330 } else {
331 list.elements = pg_sys::repalloc(list.elements.cast(), alloc_size).cast();
333 }
334
335 list.max_length = target as _;
336}
337
338unsafe fn destroy_list(list: *mut pg_sys::List) {
339 if (*list).elements != ptr::addr_of_mut!((*list).initial_elements).cast() {
341 pg_sys::pfree((*list).elements.cast());
342 }
343 pg_sys::pfree(list.cast());
344}
345
346#[derive(Debug)]
347pub struct ListIter<'a, T> {
348 list: List<'a, T>,
349 iter: RawCellIter<T>,
350}
351
352#[derive(Debug)]
354pub struct Drain<'a, 'cx, T> {
355 tail_start: u32,
357 tail_len: u32,
359 iter: RawCellIter<T>,
361 origin: &'a mut List<'cx, T>,
362 raw: *mut pg_sys::List,
363}
364
365impl<'a, 'cx, T> Drop for Drain<'a, 'cx, T> {
366 fn drop(&mut self) {
367 if self.raw.is_null() {
368 return;
369 }
370
371 unsafe {
373 let len = (*self.raw).length;
375 if len == 0 && self.tail_len == 0 {
376 destroy_list(self.raw)
378 } else {
379 let src = (*self.raw).elements.add(self.tail_start as _);
381 let dst = (*self.raw).elements.add(len as _);
382 ptr::copy(src, dst, self.tail_len as _); (*self.raw).length = len + (self.tail_len as ffi::c_int);
384
385 *self.origin = List::Cons(ListHead {
387 list: NonNull::new_unchecked(self.raw),
388 _type: PhantomData,
389 });
390 }
391 }
392 }
393}
394
395impl<T: Enlist> Iterator for Drain<'_, '_, T> {
396 type Item = T;
397
398 fn next(&mut self) -> Option<Self::Item> {
399 self.iter.next()
400 }
401}
402
403impl<T: Enlist> Iterator for ListIter<'_, T> {
404 type Item = T;
405
406 fn next(&mut self) -> Option<Self::Item> {
407 self.iter.next()
408 }
409}
410
411impl<'a, T: Enlist> IntoIterator for List<'a, T> {
412 type IntoIter = ListIter<'a, T>;
413 type Item = T;
414
415 fn into_iter(mut self) -> Self::IntoIter {
416 let len = self.len();
417 let iter = match &mut self {
418 List::Nil => Default::default(),
419 List::Cons(head) => {
420 let ptr = head.as_mut_cells_ptr();
421 let end = unsafe { ptr.add(len) };
422 RawCellIter { ptr, end }
423 }
424 };
425 ListIter { list: self, iter }
426 }
427}
428
429impl<T> Drop for ListIter<'_, T> {
430 fn drop(&mut self) {
431 if let List::Cons(head) = &mut self.list {
432 unsafe { destroy_list(head.list.as_ptr()) }
433 }
434 }
435}
436
437#[derive(Debug, PartialEq)]
446struct RawCellIter<T> {
447 ptr: *mut ListCell<T>,
448 end: *mut ListCell<T>,
449}
450
451impl<T> Default for RawCellIter<T> {
452 fn default() -> Self {
453 RawCellIter { ptr: ptr::null_mut(), end: ptr::null_mut() }
454 }
455}
456
457impl<T: Enlist> Iterator for RawCellIter<T> {
458 type Item = T;
459
460 #[inline]
461 fn next(&mut self) -> Option<T> {
462 if self.ptr < self.end {
463 let ptr = self.ptr;
464 unsafe {
466 self.ptr = ptr.add(1);
467 Some(T::apoptosis(ptr.cast()).read())
468 }
469 } else {
470 None
471 }
472 }
473}