Skip to content

Commit cd26d68

Browse files
committed
Problem: pgx::datum::Serializer trait scope
It takes care of both serialization and deserialization. However, some types can potentially be only deserialized, or serialized. Besides, the naming of the trait itself showed that it is not a perfect match. Solution: split it into Serializer and Deserializer, respectively
1 parent 38120f1 commit cd26d68

File tree

3 files changed

+20
-40
lines changed

3 files changed

+20
-40
lines changed

pgx-macros/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,8 @@ fn impl_postgres_type(ast: DeriveInput) -> syn::Result<proc_macro2::TokenStream>
781781
de.bounds = bounds;
782782
lt_generics.params.insert(0, GenericParam::Lifetime(de));
783783
stream.extend(quote! {
784-
impl #lt_generics ::pgx::datum::Serializer<'de> for #name #generics { }
784+
impl #generics ::pgx::datum::Serializer for #name #generics { }
785+
impl #lt_generics ::pgx::datum::Deserializer<'de> for #name #generics { }
785786
});
786787
}
787788

pgx-tests/src/tests/postgres_type_tests.rs

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Use of this source code is governed by the MIT license that can be found in the
88
*/
99
use core::ffi::CStr;
1010
use pgx::prelude::*;
11-
use pgx::{InOutFuncs, PgVarlena, PgVarlenaInOutFuncs, Serializer, StringInfo};
11+
use pgx::{Deserializer, InOutFuncs, PgVarlena, PgVarlenaInOutFuncs, Serializer, StringInfo};
1212
use serde::{Deserialize, Serialize};
1313
use std::io::Write;
1414
use std::str::FromStr;
@@ -157,11 +157,13 @@ pub enum JsonEnumType {
157157
#[custom_serializer]
158158
pub struct CustomSerialized;
159159

160-
impl<'de> Serializer<'de> for CustomSerialized {
160+
impl Serializer for CustomSerialized {
161161
fn to_writer<W: Write>(&self, mut writer: W) {
162162
writer.write(&[1]).expect("can't write");
163163
}
164+
}
164165

166+
impl<'de> Deserializer<'de> for CustomSerialized {
165167
fn from_slice(slice: &'de [u8]) -> Self {
166168
if slice != &[1] {
167169
panic!("wrong type")
@@ -171,33 +173,15 @@ impl<'de> Serializer<'de> for CustomSerialized {
171173
}
172174
}
173175

174-
#[derive(Serialize, Deserialize, PostgresType)]
175-
#[custom_serializer]
176-
pub struct AnotherCustomSerialized;
177-
178-
impl<'de> Serializer<'de> for AnotherCustomSerialized {
179-
fn to_writer<W: Write>(&self, mut writer: W) {
180-
writer.write(&[0]).expect("can't write");
181-
}
182-
183-
fn from_slice(slice: &'de [u8]) -> Self {
184-
if slice != &[0] {
185-
panic!("wrong type")
186-
} else {
187-
AnotherCustomSerialized
188-
}
189-
}
190-
}
191-
192176
#[cfg(any(test, feature = "pg_test"))]
193177
#[pgx::pg_schema]
194178
mod tests {
195179
#[allow(unused_imports)]
196180
use crate as pgx_tests;
197181

198182
use crate::tests::postgres_type_tests::{
199-
AnotherCustomSerialized, CustomSerialized, CustomTextFormatSerializedEnumType,
200-
CustomTextFormatSerializedType, JsonEnumType, JsonType, VarlenaEnumType, VarlenaType,
183+
CustomSerialized, CustomTextFormatSerializedEnumType, CustomTextFormatSerializedType,
184+
JsonEnumType, JsonType, VarlenaEnumType, VarlenaType,
201185
};
202186
use pgx::prelude::*;
203187
use pgx::PgVarlena;
@@ -300,14 +284,4 @@ mod tests {
300284
)
301285
.unwrap();
302286
}
303-
304-
#[pg_test(error = "wrong type")]
305-
fn custom_serializer_wrong_type() {
306-
let s = CustomSerialized;
307-
let _ = Spi::get_one_with_args::<AnotherCustomSerialized>(
308-
r#"SELECT $1"#,
309-
vec![(PgOid::Custom(CustomSerialized::type_oid()), s.into_datum())],
310-
)
311-
.unwrap();
312-
}
313287
}

pgx/src/datum/mod.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ use pgx_sql_entity_graph::RustSqlMapping;
6565
/// Implemented automatically by `#[derive(PostgresType)]`
6666
pub trait PostgresType {}
6767

68-
/// Serializing to and from datum
68+
/// Serializing to datum
6969
///
7070
/// Default implementation uses CBOR and Varlena
71-
pub trait Serializer<'de>: Serialize + Deserialize<'de> {
71+
pub trait Serializer: Serialize {
7272
/// Serializes the value to Datum
7373
///
7474
/// Default implementation wraps the output of `Self::to_writer` into a Varlena
@@ -93,7 +93,12 @@ pub trait Serializer<'de>: Serialize + Deserialize<'de> {
9393
fn to_writer<W: std::io::Write>(&self, writer: W) {
9494
serde_cbor::to_writer(writer, &self).expect("failed to encode as CBOR");
9595
}
96+
}
9697

98+
/// Deserializing from datum
99+
///
100+
/// Default implementation uses CBOR and Varlena
101+
pub trait Deserializer<'de>: Deserialize<'de> {
97102
/// Deserializes datum into a value
98103
///
99104
/// Default implementation assumes datum to be a varlena and uses `Self::from_slice`
@@ -121,7 +126,7 @@ pub trait Serializer<'de>: Serialize + Deserialize<'de> {
121126
let input = datum.cast_mut_ptr();
122127
// this gets the varlena Datum copied into this memory context
123128
let varlena = pg_sys::pg_detoast_datum_copy(input as *mut pg_sys::varlena);
124-
<Self as Serializer<'de>>::deserialize(varlena.into())
129+
<Self as Deserializer<'de>>::deserialize(varlena.into())
125130
})
126131
}
127132
}
@@ -134,9 +139,9 @@ pub trait Serializer<'de>: Serialize + Deserialize<'de> {
134139
}
135140
}
136141

137-
impl<'de, T> IntoDatum for T
142+
impl<T> IntoDatum for T
138143
where
139-
T: PostgresType + Serializer<'de>,
144+
T: PostgresType + Serializer,
140145
{
141146
fn into_datum(self) -> Option<pg_sys::Datum> {
142147
Some(Serializer::serialize(&self))
@@ -149,7 +154,7 @@ where
149154

150155
impl<'de, T> FromDatum for T
151156
where
152-
T: PostgresType + Serializer<'de>,
157+
T: PostgresType + Deserializer<'de>,
153158
{
154159
unsafe fn from_polymorphic_datum(
155160
datum: pg_sys::Datum,
@@ -159,7 +164,7 @@ where
159164
if is_null {
160165
None
161166
} else {
162-
Some(<T as Serializer>::deserialize(datum))
167+
Some(<T as Deserializer>::deserialize(datum))
163168
}
164169
}
165170

0 commit comments

Comments
 (0)