1use crate::datum::{Array, FromDatum, PgVarlena, VariadicArray};
2use crate::PgBox;
3use core::any::TypeId;
4use once_cell::sync::Lazy;
5use pgrx_sql_entity_graph::RustSqlMapping;
6
7#[inline]
9#[doc(hidden)]
10pub fn nonstatic_typeid<T: ?Sized>() -> core::any::TypeId {
11 trait NonStaticAny {
12 fn type_id(&self) -> core::any::TypeId
13 where
14 Self: 'static;
15 }
16 impl<T: ?Sized> NonStaticAny for core::marker::PhantomData<T> {
17 #[inline]
18 fn type_id(&self) -> core::any::TypeId
19 where
20 Self: 'static,
21 {
22 core::any::TypeId::of::<T>()
23 }
24 }
25 let it = core::marker::PhantomData::<T>;
26 unsafe { core::mem::transmute::<&dyn NonStaticAny, &'static dyn NonStaticAny>(&it).type_id() }
28}
29
30pub trait WithTypeIds {
51 const ITEM_ID: Lazy<TypeId>;
52 const OPTION_ID: Lazy<Option<TypeId>>;
53 const VEC_ID: Lazy<Option<TypeId>>;
54 const VEC_OPTION_ID: Lazy<Option<TypeId>>;
55 const OPTION_VEC_ID: Lazy<Option<TypeId>>;
56 const OPTION_VEC_OPTION_ID: Lazy<Option<TypeId>>;
57 const ARRAY_ID: Lazy<Option<TypeId>>;
58 const OPTION_ARRAY_ID: Lazy<Option<TypeId>>;
59 const VARIADICARRAY_ID: Lazy<Option<TypeId>>;
60 const OPTION_VARIADICARRAY_ID: Lazy<Option<TypeId>>;
61 const VARLENA_ID: Lazy<Option<TypeId>>;
62 const OPTION_VARLENA_ID: Lazy<Option<TypeId>>;
63
64 fn register_with_refs(map: &mut std::collections::HashSet<RustSqlMapping>, single_sql: String) {
65 Self::register(map, single_sql.clone());
66 <&Self as WithTypeIds>::register(map, single_sql.clone());
67 <&mut Self as WithTypeIds>::register(map, single_sql);
68 }
69
70 fn register_sized_with_refs(
71 _map: &mut std::collections::HashSet<RustSqlMapping>,
72 _single_sql: String,
73 ) {
74 ()
75 }
76
77 fn register_sized(_map: &mut std::collections::HashSet<RustSqlMapping>, _single_sql: String) {
78 ()
79 }
80
81 fn register_varlena_with_refs(
82 _map: &mut std::collections::HashSet<RustSqlMapping>,
83 _single_sql: String,
84 ) {
85 ()
86 }
87
88 fn register_varlena(_map: &mut std::collections::HashSet<RustSqlMapping>, _single_sql: String) {
89 ()
90 }
91
92 fn register_array_with_refs(
93 _map: &mut std::collections::HashSet<RustSqlMapping>,
94 _single_sql: String,
95 ) {
96 ()
97 }
98
99 fn register_array(_map: &mut std::collections::HashSet<RustSqlMapping>, _single_sql: String) {
100 ()
101 }
102
103 fn register(set: &mut std::collections::HashSet<RustSqlMapping>, single_sql: String) {
104 let rust = core::any::type_name::<Self>();
105 assert!(
106 set.insert(RustSqlMapping {
107 sql: single_sql.clone(),
108 rust: rust.to_string(),
109 id: *Self::ITEM_ID,
110 }),
111 "Cannot set mapping of `{rust}` twice, was already `{single_sql}`.",
112 );
113 }
114}
115
116impl<T: ?Sized> WithTypeIds for T {
117 const ITEM_ID: Lazy<TypeId> = Lazy::new(|| nonstatic_typeid::<T>());
118 const OPTION_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
119 const VEC_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
120 const VEC_OPTION_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
121 const OPTION_VEC_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
122 const OPTION_VEC_OPTION_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
123 const ARRAY_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
124 const OPTION_ARRAY_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
125 const VARIADICARRAY_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
126 const OPTION_VARIADICARRAY_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
127 const VARLENA_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
128 const OPTION_VARLENA_ID: Lazy<Option<TypeId>> = Lazy::new(|| None);
129}
130
131pub struct WithSizedTypeIds<T>(pub core::marker::PhantomData<T>);
156
157impl<T> WithSizedTypeIds<T> {
158 pub const PG_BOX_ID: Lazy<Option<TypeId>> = Lazy::new(|| Some(nonstatic_typeid::<PgBox<T>>()));
159 pub const PG_BOX_OPTION_ID: Lazy<Option<TypeId>> =
160 Lazy::new(|| Some(nonstatic_typeid::<PgBox<Option<T>>>()));
161 pub const PG_BOX_VEC_ID: Lazy<Option<TypeId>> =
162 Lazy::new(|| Some(nonstatic_typeid::<PgBox<Vec<T>>>()));
163 pub const OPTION_ID: Lazy<Option<TypeId>> = Lazy::new(|| Some(nonstatic_typeid::<Option<T>>()));
164 pub const VEC_ID: Lazy<Option<TypeId>> = Lazy::new(|| Some(nonstatic_typeid::<Vec<T>>()));
165 pub const VEC_OPTION_ID: Lazy<Option<TypeId>> =
166 Lazy::new(|| Some(nonstatic_typeid::<Vec<Option<T>>>()));
167 pub const OPTION_VEC_ID: Lazy<Option<TypeId>> =
168 Lazy::new(|| Some(nonstatic_typeid::<Option<Vec<T>>>()));
169 pub const OPTION_VEC_OPTION_ID: Lazy<Option<TypeId>> =
170 Lazy::new(|| Some(nonstatic_typeid::<Option<Vec<Option<T>>>>()));
171
172 pub fn register_sized_with_refs(
173 map: &mut std::collections::HashSet<RustSqlMapping>,
174 single_sql: String,
175 ) where
176 Self: 'static,
177 {
178 WithSizedTypeIds::<T>::register_sized(map, single_sql.clone());
179 WithSizedTypeIds::<&T>::register_sized(map, single_sql.clone());
180 WithSizedTypeIds::<&mut T>::register_sized(map, single_sql);
181 }
182
183 pub fn register_sized(map: &mut std::collections::HashSet<RustSqlMapping>, single_sql: String) {
184 let set_sql = format!("{single_sql}[]");
185
186 if let Some(id) = *WithSizedTypeIds::<T>::PG_BOX_ID {
187 let rust = core::any::type_name::<crate::PgBox<T>>().to_string();
188 assert!(
189 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
190 "Cannot map `{rust}` twice.",
191 );
192 }
193
194 if let Some(id) = *WithSizedTypeIds::<T>::PG_BOX_OPTION_ID {
195 let rust = core::any::type_name::<crate::PgBox<Option<T>>>().to_string();
196 assert!(
197 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
198 "Cannot map `{rust}` twice.",
199 );
200 }
201
202 if let Some(id) = *WithSizedTypeIds::<T>::PG_BOX_VEC_ID {
203 let rust = core::any::type_name::<crate::PgBox<Vec<T>>>().to_string();
204 assert!(
205 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
206 "Cannot map `{rust}` twice.",
207 );
208 }
209
210 if let Some(id) = *WithSizedTypeIds::<T>::OPTION_ID {
211 let rust = core::any::type_name::<Option<T>>().to_string();
212 assert!(
213 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
214 "Cannot map `{rust}` twice.",
215 );
216 }
217
218 if let Some(id) = *WithSizedTypeIds::<T>::VEC_ID {
219 let rust = core::any::type_name::<T>().to_string();
220 assert!(
221 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
222 "Cannot map `{rust}` twice.",
223 );
224 }
225 if let Some(id) = *WithSizedTypeIds::<T>::VEC_OPTION_ID {
226 let rust = core::any::type_name::<Vec<Option<T>>>();
227 assert!(
228 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
229 "Cannot map `{rust}` twice.",
230 );
231 }
232 if let Some(id) = *WithSizedTypeIds::<T>::OPTION_VEC_ID {
233 let rust = core::any::type_name::<Option<Vec<T>>>();
234 assert!(
235 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
236 "Cannot map `{rust}` twice.",
237 );
238 }
239 if let Some(id) = *WithSizedTypeIds::<T>::OPTION_VEC_OPTION_ID {
240 let rust = core::any::type_name::<Option<Vec<Option<T>>>>();
241 assert!(
242 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
243 "Cannot map `{rust}` twice.",
244 );
245 }
246 }
247}
248
249pub struct WithArrayTypeIds<T>(pub core::marker::PhantomData<T>);
274
275impl<T: FromDatum + 'static> WithArrayTypeIds<T> {
276 pub const ARRAY_ID: Lazy<Option<TypeId>> = Lazy::new(|| Some(nonstatic_typeid::<Array<T>>()));
277 pub const OPTION_ARRAY_ID: Lazy<Option<TypeId>> =
278 Lazy::new(|| Some(nonstatic_typeid::<Option<Array<T>>>()));
279 pub const VARIADICARRAY_ID: Lazy<Option<TypeId>> =
280 Lazy::new(|| Some(nonstatic_typeid::<VariadicArray<T>>()));
281 pub const OPTION_VARIADICARRAY_ID: Lazy<Option<TypeId>> =
282 Lazy::new(|| Some(nonstatic_typeid::<Option<VariadicArray<T>>>()));
283
284 pub fn register_array_with_refs(
285 map: &mut std::collections::HashSet<RustSqlMapping>,
286 single_sql: String,
287 ) where
288 Self: 'static,
289 {
290 WithArrayTypeIds::<T>::register_array(map, single_sql.clone());
291 WithArrayTypeIds::<&T>::register_array(map, single_sql.clone());
292 WithArrayTypeIds::<&mut T>::register_array(map, single_sql);
293 }
294
295 pub fn register_array(map: &mut std::collections::HashSet<RustSqlMapping>, single_sql: String) {
296 let set_sql = format!("{single_sql}[]");
297
298 if let Some(id) = *WithArrayTypeIds::<T>::ARRAY_ID {
299 let rust = core::any::type_name::<Array<T>>().to_string();
300 assert!(
301 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
302 "Cannot map `{rust}` twice.",
303 );
304 }
305 if let Some(id) = *WithArrayTypeIds::<T>::OPTION_ARRAY_ID {
306 let rust = core::any::type_name::<Option<Array<T>>>().to_string();
307 assert!(
308 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
309 "Cannot map `{rust}` twice.",
310 );
311 }
312
313 if let Some(id) = *WithArrayTypeIds::<T>::VARIADICARRAY_ID {
314 let rust = core::any::type_name::<VariadicArray<T>>().to_string();
315 assert!(
316 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
317 "Cannot map `{rust}` twice.",
318 );
319 }
320 if let Some(id) = *WithArrayTypeIds::<T>::OPTION_VARIADICARRAY_ID {
321 let rust = core::any::type_name::<Option<VariadicArray<T>>>().to_string();
322 assert!(
323 map.insert(RustSqlMapping { sql: set_sql.clone(), rust: rust.to_string(), id }),
324 "Cannot map `{rust}` twice.",
325 );
326 }
327 }
328}
329
330pub struct WithVarlenaTypeIds<T>(pub core::marker::PhantomData<T>);
355
356impl<T: Copy + 'static> WithVarlenaTypeIds<T> {
357 pub const VARLENA_ID: Lazy<Option<TypeId>> =
358 Lazy::new(|| Some(nonstatic_typeid::<PgVarlena<T>>()));
359 pub const PG_BOX_VARLENA_ID: Lazy<Option<TypeId>> =
360 Lazy::new(|| Some(nonstatic_typeid::<PgBox<PgVarlena<T>>>()));
361 pub const OPTION_VARLENA_ID: Lazy<Option<TypeId>> =
362 Lazy::new(|| Some(nonstatic_typeid::<Option<PgVarlena<T>>>()));
363
364 pub fn register_varlena_with_refs(
365 map: &mut std::collections::HashSet<RustSqlMapping>,
366 single_sql: String,
367 ) where
368 Self: 'static,
369 {
370 WithVarlenaTypeIds::<T>::register_varlena(map, single_sql.clone());
371 WithVarlenaTypeIds::<&T>::register_varlena(map, single_sql.clone());
372 WithVarlenaTypeIds::<&mut T>::register_varlena(map, single_sql);
373 }
374
375 pub fn register_varlena(
376 map: &mut std::collections::HashSet<RustSqlMapping>,
377 single_sql: String,
378 ) {
379 if let Some(id) = *WithVarlenaTypeIds::<T>::VARLENA_ID {
380 let rust = core::any::type_name::<PgVarlena<T>>();
381 assert!(
382 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
383 "Cannot map `{rust}` twice.",
384 );
385 }
386
387 if let Some(id) = *WithVarlenaTypeIds::<T>::PG_BOX_VARLENA_ID {
388 let rust = core::any::type_name::<PgBox<PgVarlena<T>>>().to_string();
389 assert!(
390 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
391 "Cannot map `{rust}` twice.",
392 );
393 }
394 if let Some(id) = *WithVarlenaTypeIds::<T>::OPTION_VARLENA_ID {
395 let rust = core::any::type_name::<Option<PgVarlena<T>>>().to_string();
396 assert!(
397 map.insert(RustSqlMapping { sql: single_sql.clone(), rust: rust.to_string(), id }),
398 "Cannot map `{rust}` twice.",
399 );
400 }
401 }
402}