pgrx_sql_entity_graph/pg_extern/
argument.rs

1//LICENSE Portions Copyright 2019-2021 ZomboDB, LLC.
2//LICENSE
3//LICENSE Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
4//LICENSE
5//LICENSE Portions Copyright 2023-2023 PgCentral Foundation, Inc. <contact@pgcentral.org>
6//LICENSE
7//LICENSE All rights reserved.
8//LICENSE
9//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10/*!
11
12`#[pg_extern]` related argument macro expansion for Rust to SQL translation
13
14> Like all of the [`sql_entity_graph`][crate] APIs, this is considered **internal**
15> to the `pgrx` framework and very subject to change between versions. While you may use this, please do it with caution.
16
17*/
18use crate::UsedType;
19use proc_macro2::TokenStream as TokenStream2;
20use quote::{quote, ToTokens, TokenStreamExt};
21use syn::{spanned::Spanned, FnArg, Pat};
22
23/// A parsed `#[pg_extern]` argument.
24///
25/// It is created during [`PgExtern`](crate::PgExtern) parsing.
26#[derive(Debug, Clone)]
27pub struct PgExternArgument {
28    pub fn_arg: syn::FnArg,
29    pub pat: syn::Ident,
30    pub used_ty: UsedType,
31}
32
33impl PgExternArgument {
34    pub fn build(fn_arg: FnArg) -> Result<Self, syn::Error> {
35        match &fn_arg {
36            syn::FnArg::Typed(pat) => Self::build_from_pat_type(fn_arg.clone(), pat.clone()),
37            syn::FnArg::Receiver(_) => {
38                // FIXME: Add a UI test for this
39                Err(syn::Error::new(fn_arg.span(), "Unable to parse FnArg that is Self"))
40            }
41        }
42    }
43
44    pub fn build_from_pat_type(
45        fn_arg: syn::FnArg,
46        value: syn::PatType,
47    ) -> Result<Self, syn::Error> {
48        let identifier = match *value.pat {
49            Pat::Ident(ref p) => p.ident.clone(),
50            Pat::Reference(ref p_ref) => match *p_ref.pat {
51                Pat::Ident(ref inner_ident) => inner_ident.ident.clone(),
52                // FIXME: add a UI test for this
53                _ => return Err(syn::Error::new(value.span(), "Unable to parse FnArg")),
54            },
55            // FIXME: add a UI test for this
56            _ => return Err(syn::Error::new(value.span(), "Unable to parse FnArg")),
57        };
58
59        let used_ty = UsedType::new(*value.ty)?;
60
61        Ok(PgExternArgument { fn_arg, pat: identifier, used_ty })
62    }
63
64    pub fn entity_tokens(&self) -> TokenStream2 {
65        let pat = &self.pat;
66        let used_ty_entity = self.used_ty.entity_tokens();
67
68        let quoted = quote! {
69            ::pgrx::pgrx_sql_entity_graph::PgExternArgumentEntity {
70                pattern: stringify!(#pat),
71                used_ty: #used_ty_entity,
72            }
73        };
74        quoted
75    }
76}
77
78impl ToTokens for PgExternArgument {
79    fn to_tokens(&self, tokens: &mut TokenStream2) {
80        let fn_arg = &self.fn_arg;
81        let quoted = quote! {
82            #fn_arg
83        };
84        tokens.append_all(quoted);
85    }
86}