diff --git a/pgrx/src/lib.rs b/pgrx/src/lib.rs index bdd79bb3bd..e97f269e74 100644 --- a/pgrx/src/lib.rs +++ b/pgrx/src/lib.rs @@ -64,6 +64,7 @@ pub mod misc; pub mod namespace; pub mod nodes; pub mod nullable; +pub mod palloc; pub mod pg_catalog; pub mod pgbox; pub mod rel; diff --git a/pgrx/src/memcx.rs b/pgrx/src/memcx.rs index f3ad834c6e..9e6e8d845d 100644 --- a/pgrx/src/memcx.rs +++ b/pgrx/src/memcx.rs @@ -116,3 +116,8 @@ mod nightly { } } } +/// A type pallocated in a context. +pub struct InCx<'mcx, T>(T, PhantomData>); + +/// An "owning" palloc. +pub struct Palloc<'mcx, T>(T, &'mcx MemCx<'mcx>); diff --git a/pgrx/src/palloc.rs b/pgrx/src/palloc.rs new file mode 100644 index 0000000000..921e177b1e --- /dev/null +++ b/pgrx/src/palloc.rs @@ -0,0 +1,46 @@ +use crate::memcx::MemCx; +use core::ffi::{self, CStr}; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; + +/// A CStr in a palloc +/// +/// ABI-compatible with `*const ffi::c_char` +#[repr(transparent)] +pub struct PStr<'mcx>(NonNull, PhantomData<&'mcx MemCx<'mcx>>); + +impl<'mcx> PStr<'mcx> { + /// AKA [`mem::transmute`]. + /// + /// # Safety + /// + /// By invoking this, you assert + /// - The pointee is data allocated via a Postgres memory context. + /// - `'this` does not outlive that memory context. + /// - The constraints of [`CStr::from_ptr`] apply, with a `\0`-terminated pointee + /// + /// You are giving this a lifetime bounded by the called-with lifetime. There is no check to + /// validate your assertion, nor is there a check to validate the pointee is `\0`-terminated. + #[inline] + pub(crate) unsafe fn assume_ptr_lives_for<'this>(ptr: NonNull) -> PStr<'this> { + // SAFETY: The caller is allowed to assign a lifetime to this fn, making it a kind of + // "lifetime transmutation", regardless of whether we transmute or use struct init. + unsafe { mem::transmute(ptr) } + } + + /// Safely introduces a lifetime + /// + /// # Safety + /// + /// By calling this function, you assert: + /// - The pointee is data allocated via the referenced `MemCx<'mcx>`. + /// - The constraints of [`CStr::from_ptr`] apply, with a `\0`-terminated pointee + #[inline] + pub unsafe fn assume_ptr_in(ptr: NonNull, _memcx: &MemCx<'mcx>) -> PStr<'mcx> { + PStr::assume_ptr_lives_for::<'mcx>(ptr) + } +} + +/// A type allocated in a memory context. +pub struct Palloc<'mcx, T>(T, PhantomData<&'mcx MemCx<'mcx>>); diff --git a/spare_pstring_stuff.rs b/spare_pstring_stuff.rs new file mode 100644 index 0000000000..a086c80629 --- /dev/null +++ b/spare_pstring_stuff.rs @@ -0,0 +1,57 @@ +enum Encoding { + Bytes, + Utf8, +} +/// Pallocated, extensible string, that does not assume an encoding. +/// +/// Like StringInfo, but with less FFI. +/// Note that the 0-len str. +pub struct PString<'mcx> { + ptr: NonNull, + mcx: &'mcx MemCx<'mcx>, + len: u32, + cap: u32, +} + +impl<'mcx> PString<'mcx> { + pub fn new_in(mcx: &MemCx<'mcx>) -> PString<'mcx> { + todo!() + } + + /// Into a pallocated string. + pub fn into_pstr(self) -> PStr<'mcx> { + PStr(self.ptr, PhantomData) + } +} + + +struct CloneIn(); +struct IsRef(); +struct IsPalloc(); + +trait AllocAs {} +impl AllocAs for CloneIn { +} +impl AllocAs for IsRef { +} +impl AllocAs for IsPalloc { +} + +pub struct PStrBuilder { + memcx: M, + raw_ptr: Option<*mut ffi::c_char>, + alloc: Alloc, +} + +/// Instead of a proliferation of "create this from so-and-so" +pub fn build_from(builder: PStrBuilder>) -> PString<'mcx> { + todo!() +} + +impl PStrBuilder { + +} + +impl<'mcx> PStrBuilder> { + +} \ No newline at end of file