Skip to content

Commit

Permalink
Weaken bounds on Array impls (#1355)
Browse files Browse the repository at this point in the history
Weaken the bounds on various implementations for Array, to make things
easier to refactor. This weakening is mostly irrelevant because you still
can't construct a "useless" Array.
  • Loading branch information
workingjubilee authored Oct 27, 2023
1 parent dc0d88d commit a9e3b14
Showing 1 changed file with 37 additions and 34 deletions.
71 changes: 37 additions & 34 deletions pgrx/src/datum/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ fn with_vec(elems: Array<String>) {
}
```
*/
pub struct Array<'a, T: FromDatum> {
pub struct Array<'a, T> {
null_slice: NullKind<'a>,
slide_impl: ChaChaSlideImpl<T>,
// Rust drops in FIFO order, drop this last
Expand Down Expand Up @@ -154,22 +154,6 @@ impl<'a, T: FromDatum> Array<'a, T> {
Array { raw, slide_impl, null_slice }
}

/// Rips out the underlying `pg_sys::ArrayType` pointer.
/// Note that Array may have caused Postgres to allocate to unbox the datum,
/// and this can hypothetically cause a memory leak if so.
#[inline]
pub fn into_array_type(self) -> *const pg_sys::ArrayType {
// may be worth replacing this function when Toast<T> matures enough
// to be used as a public type with a fn(self) -> Toast<RawArray>

let Array { raw, .. } = self;
// Wrap the Toast<RawArray> to prevent it from deallocating itself
let mut raw = core::mem::ManuallyDrop::new(raw);
let ptr = raw.deref_mut().deref_mut() as *mut RawArray;
// SAFETY: Leaks are safe if they aren't use-after-frees!
unsafe { ptr.read() }.into_ptr().as_ptr() as _
}

/// Return an iterator of `Option<T>`.
#[inline]
pub fn iter(&self) -> ArrayIterator<'_, T> {
Expand All @@ -191,22 +175,6 @@ impl<'a, T: FromDatum> Array<'a, T> {
ArrayTypedIterator { array: self, curr: 0, ptr }
}

/// Returns `true` if this [`Array`] contains one or more SQL "NULL" values
#[inline]
pub fn contains_nulls(&self) -> bool {
self.null_slice.any()
}

#[inline]
pub fn len(&self) -> usize {
self.raw.len()
}

#[inline]
pub fn is_empty(&self) -> bool {
self.raw.len() == 0
}

#[allow(clippy::option_option)]
#[inline]
pub fn get(&self, index: usize) -> Option<Option<T>> {
Expand Down Expand Up @@ -275,6 +243,41 @@ impl<'a, T: FromDatum> Array<'a, T> {
}
}

#[deny(unsafe_op_in_unsafe_fn)]
impl<'a, T> Array<'a, T> {
/// Rips out the underlying `pg_sys::ArrayType` pointer.
/// Note that Array may have caused Postgres to allocate to unbox the datum,
/// and this can hypothetically cause a memory leak if so.
#[inline]
pub fn into_array_type(self) -> *const pg_sys::ArrayType {
// may be worth replacing this function when Toast<T> matures enough
// to be used as a public type with a fn(self) -> Toast<RawArray>

let Array { raw, .. } = self;
// Wrap the Toast<RawArray> to prevent it from deallocating itself
let mut raw = core::mem::ManuallyDrop::new(raw);
let ptr = raw.deref_mut().deref_mut() as *mut RawArray;
// SAFETY: Leaks are safe if they aren't use-after-frees!
unsafe { ptr.read() }.into_ptr().as_ptr() as _
}

/// Returns `true` if this [`Array`] contains one or more SQL "NULL" values
#[inline]
pub fn contains_nulls(&self) -> bool {
self.null_slice.any()
}

#[inline]
pub fn len(&self) -> usize {
self.raw.len()
}

#[inline]
pub fn is_empty(&self) -> bool {
self.raw.len() == 0
}
}

#[derive(thiserror::Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum ArraySliceError {
#[error("Cannot create a slice of an Array that contains nulls")]
Expand Down Expand Up @@ -362,7 +365,7 @@ impl<'a> Array<'a, i8> {
}

#[inline(always)]
fn as_slice<'a, T: Sized + FromDatum>(array: &'a Array<'_, T>) -> Result<&'a [T], ArraySliceError> {
fn as_slice<'a, T: Sized>(array: &'a Array<'_, T>) -> Result<&'a [T], ArraySliceError> {
if array.contains_nulls() {
return Err(ArraySliceError::ContainsNulls);
}
Expand Down

0 comments on commit a9e3b14

Please sign in to comment.