Skip to content

Commit

Permalink
Add Arguments iterator
Browse files Browse the repository at this point in the history
- Add `Argument<...>` type
- Add `Arguments<...>` iterator
- Add `ArgAbi::unbox_argument` that uses them

This simplifies the internal logic of ArgAbi impls
  • Loading branch information
workingjubilee committed Jun 14, 2024
1 parent 8ac225d commit 9c274b5
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 12 deletions.
4 changes: 4 additions & 0 deletions pgrx-examples/custom_types/src/hexint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ where
value
}
}

unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, 'fcx>) -> Option<Self> {
args.next().and_then(|arg| arg.unbox_arg_using_from_datum())
}
}

unsafe impl BoxRet for HexInt {
Expand Down
8 changes: 8 additions & 0 deletions pgrx-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,11 @@ fn impl_postgres_enum(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream>
.unwrap_or_else(|| panic!("argument {index} must not be null"))
}
}

unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, #fcx_lt>) -> Option<Self> {
args.next().and_then(|arg| arg.unbox_arg_using_from_datum())
}

}

unsafe impl #generics ::pgrx::datum::UnboxDatum for #enum_ident #generics {
Expand Down Expand Up @@ -923,6 +928,9 @@ fn impl_postgres_type(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream>
.unwrap_or_else(|| panic!("argument {index} must not be null"))
}
}
unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, #fcx_lt>) -> Option<Self> {
args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() })
}
}
}
)
Expand Down
14 changes: 10 additions & 4 deletions pgrx-sql-entity-graph/src/pg_extern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,12 +400,13 @@ impl PgExtern {
// false
true
};
let args_ident = proc_macro2::Ident::new("_args", Span::call_site());
let arg_fetches = args.iter().enumerate().map(|(idx, arg)| {
if new_unboxing {
let pat = &arg_pats[idx];
let resolved_ty = &arg.used_ty.resolved_ty;
quote_spanned!{ pat.span() =>
let #pat = <#resolved_ty as ::pgrx::callconv::ArgAbi>::unbox_from_fcinfo_index(#fcinfo_ident, &mut #idx);
let #pat = <#resolved_ty as ::pgrx::callconv::ArgAbi>::unbox_argument(#args_ident).unwrap();
}
} else {
let pat = &arg_pats[idx];
Expand Down Expand Up @@ -448,13 +449,18 @@ impl PgExtern {
#[allow(unused_unsafe)]
unsafe {
let #fcinfo_ident = fcinfo;
let result = match <#ret_ty as ::pgrx::callconv::RetAbi>::check_and_prepare(#fcinfo_ident) {
let call_flow = <#ret_ty as ::pgrx::callconv::RetAbi>::check_and_prepare(#fcinfo_ident);
let result = match call_flow {
::pgrx::callconv::CallCx::WrappedFn(mcx) => {
let mut mcx = ::pgrx::PgMemoryContexts::For(mcx);
::pgrx::callconv::RetAbi::to_ret(mcx.switch_to(|_| {
let fcinfo = &*#fcinfo_ident;
let mut args = fcinfo.arguments();
let #args_ident= &mut args;
let call_result = mcx.switch_to(|_| {
#(#arg_fetches)*
#func_name( #(#arg_pats),* )
}))
});
::pgrx::callconv::RetAbi::to_ret(call_result)
}
::pgrx::callconv::CallCx::RestoreCx => <#ret_ty as ::pgrx::callconv::RetAbi>::ret_from_fcx(#fcinfo_ident),
};
Expand Down
102 changes: 94 additions & 8 deletions pgrx/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use crate::{
Timestamp, TimestampWithTimeZone, UnboxDatum, Uuid,
};
use core::marker::PhantomData;
use core::mem;
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::{iter, mem, slice};
use std::ffi::{CStr, CString};
use std::ptr::NonNull;

Expand Down Expand Up @@ -51,7 +51,7 @@ pub unsafe trait ArgAbi<'fcx>: Sized {
// FIXME: use an iterator or something?
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self;

unsafe fn uhh() -> () {}
unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self>;
}

pub fn wrap_fn<'fcx, A, F: FunctionMetadata<A>>(fcinfo: &mut FcInfo<'fcx>, f: F) -> Datum<'fcx> {
Expand All @@ -65,6 +65,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
todo!()
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::datum::VariadicArray<'fcx, T>
Expand All @@ -74,13 +78,21 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
todo!()
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

// not sure how this is gonna work
unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::PgBox<T> {
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
todo!()
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, W> ArgAbi<'fcx> for PgHeapTuple<'fcx, W>
Expand All @@ -90,6 +102,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
todo!()
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, T> ArgAbi<'fcx> for Option<T>
Expand All @@ -105,6 +121,10 @@ where
Some(unsafe { <T as ArgAbi>::unbox_from_fcinfo_index(fcinfo, index) })
}
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::Range<T>
Expand All @@ -121,6 +141,10 @@ where
.unwrap_or_else(|| panic!("argument {index} must not be null"))
}
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() })
}
}

unsafe impl<'fcx, T> ArgAbi<'fcx> for Vec<T>
Expand All @@ -130,6 +154,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
todo!()
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, T: Copy> ArgAbi<'fcx> for PgVarlena<T> {
Expand All @@ -141,6 +169,10 @@ unsafe impl<'fcx, T: Copy> ArgAbi<'fcx> for PgVarlena<T> {
assert_eq!(*isnull, false, "PgVarlena from argument {index} must not be null");
unsafe { Self::from_datum(*value) }
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

unsafe impl<'fcx, const P: u32, const S: u32> ArgAbi<'fcx> for crate::Numeric<P, S> {
Expand All @@ -154,12 +186,20 @@ unsafe impl<'fcx, const P: u32, const S: u32> ArgAbi<'fcx> for crate::Numeric<P,
.unwrap_or_else(|| panic!("argument {index} must not be null"))
}
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() })
}
}

unsafe impl<'fcx> ArgAbi<'fcx> for pg_sys::FunctionCallInfo {
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
unsafe { fcinfo.as_mut_ptr() }
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

macro_rules! argue_from_datum {
Expand All @@ -174,6 +214,10 @@ macro_rules! argue_from_datum {
value
}
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() })
}
})*
};
}
Expand Down Expand Up @@ -203,6 +247,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
Defaulted(unsafe { <T as ArgAbi>::unbox_from_fcinfo_index(fcinfo, index) })
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

// basically intended to be the new version of the `name!` macro
Expand All @@ -218,6 +266,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
Named(unsafe { <T as ArgAbi<'fcx>>::unbox_from_fcinfo_index(fcinfo, index) })
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

// basically intended to be the new version of the `composite_type!` macro
Expand All @@ -232,6 +284,10 @@ where
unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self {
CompositeType(unsafe { <T as ArgAbi>::unbox_from_fcinfo_index(fcinfo, index) })
}

unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option<Self> {
todo!()
}
}

/// How to return a value from Rust to Postgres
Expand Down Expand Up @@ -260,7 +316,7 @@ pub unsafe trait RetAbi: Sized {
CallCx::WrappedFn(unsafe { pg_sys::CurrentMemoryContext })
}

fn check_and_prepare<'fcx>(fcinfo: &mut FcInfo<'fcx>) -> CallCx {
fn check_and_prepare(fcinfo: &mut FcInfo<'_>) -> CallCx {
unsafe { Self::check_fcinfo_and_prepare(fcinfo.0) }
}

Expand Down Expand Up @@ -297,7 +353,7 @@ pub unsafe trait RetAbi: Sized {
unimplemented!()
}

fn ret_from_fcx<'fcx>(fcinfo: &mut FcInfo<'fcx>) -> Self::Ret {
fn ret_from_fcx(fcinfo: &mut FcInfo<'_>) -> Self::Ret {
let fcinfo = fcinfo.0;
unsafe { Self::ret_from_fcinfo_fcx(fcinfo) }
}
Expand Down Expand Up @@ -547,10 +603,7 @@ impl<'fcx> FcInfo<'fcx> {
}
/// Retrieve the arguments to this function call as a slice of [`pgrx_pg_sys::NullableDatum`]
#[inline]
pub fn raw_args<'a>(&'a self) -> &'fcx [pgrx_pg_sys::NullableDatum]
where
'a: 'fcx,
{
pub fn raw_args(&self) -> &[pgrx_pg_sys::NullableDatum] {
// Null pointer check already performed on immutable pointer
// at construction time.
unsafe {
Expand Down Expand Up @@ -710,6 +763,39 @@ impl<'fcx> FcInfo<'fcx> {
ReturnSetInfoWrapper::from_ptr((*self.0).resultinfo as *mut pg_sys::ReturnSetInfo)
}
}

#[inline]
pub fn arguments<'arg>(&'arg self) -> Arguments<'arg, 'fcx> {
Arguments { iter: self.raw_args().iter().enumerate(), fcinfo: self }
}
}

// TODO: rebadge this as AnyElement
pub struct Argument<'a, 'fcx>(&'a FcInfo<'fcx>, usize, &'a pg_sys::NullableDatum);

impl<'a, 'fcx> Argument<'a, 'fcx> {
pub fn raw_oid(&self) -> pg_sys::Oid {
// we can just unwrap here because we know we were created using a valid index
self.0.get_arg_type(self.1).unwrap()
}

pub unsafe fn unbox_arg_using_from_datum<T: FromDatum>(self) -> Option<T> {
let pg_sys::NullableDatum { isnull, value } = *self.2;
unsafe { FromDatum::from_datum(value, isnull) }
}
}

pub struct Arguments<'a, 'fcx> {
iter: iter::Enumerate<slice::Iter<'a, pg_sys::NullableDatum>>,
fcinfo: &'a FcInfo<'fcx>,
}

impl<'a, 'fcx> Iterator for Arguments<'a, 'fcx> {
type Item = Argument<'a, 'fcx>;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(i, dat)| Argument(self.fcinfo, i, dat))
}
}

#[derive(Clone)]
Expand Down

0 comments on commit 9c274b5

Please sign in to comment.