Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weaken bounds on Array impls #1355

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you didn't add this, but lol.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙈

// 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