use crate::time_duration::TimeDuration;
use crate::timestamp::Timestamp;
use crate::uuid::Uuid;
use crate::{i256, u256, AlgebraicType, AlgebraicValue, ProductValue, Serialize, SumValue, ValueWithType};
use crate::{ser, ProductType, ProductTypeElement};
use core::fmt;
use core::fmt::Write as _;
use derive_more::{Display, From, Into};
use std::borrow::Cow;
use std::marker::PhantomData;
pub trait Satn: ser::Serialize {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Writer::with(f, |f| self.serialize(SatnFormatter { f }))?;
Ok(())
}
fn fmt_psql(&self, f: &mut fmt::Formatter, ty: &PsqlType<'_>) -> fmt::Result {
Writer::with(f, |f| {
self.serialize(TypedSerializer {
ty,
f: &mut SqlFormatter {
fmt: SatnFormatter { f },
ty,
},
})
})?;
Ok(())
}
fn to_satn(&self) -> String {
Wrapper::from_ref(self).to_string()
}
fn to_satn_pretty(&self) -> String {
format!("{:#}", Wrapper::from_ref(self))
}
}
impl<T: ser::Serialize + ?Sized> Satn for T {}
#[repr(transparent)]
pub struct Wrapper<T: ?Sized>(pub T);
impl<T: ?Sized> Wrapper<T> {
pub fn from_ref(t: &T) -> &Self {
unsafe { &*(t as *const T as *const Self) }
}
}
impl<T: Satn + ?Sized> fmt::Display for Wrapper<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: Satn + ?Sized> fmt::Debug for Wrapper<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
pub struct PsqlWrapper<'a, T: ?Sized> {
pub ty: PsqlType<'a>,
pub value: T,
}
impl<T: ?Sized> PsqlWrapper<'_, T> {
pub fn from_ref(t: &T) -> &Self {
unsafe { &*(t as *const T as *const Self) }
}
}
impl<T: Satn + ?Sized> fmt::Display for PsqlWrapper<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.value.fmt_psql(f, &self.ty)
}
}
impl<T: Satn + ?Sized> fmt::Debug for PsqlWrapper<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.value.fmt_psql(f, &self.ty)
}
}
struct EntryWrapper<'a, 'f, const SEP: char> {
fmt: Writer<'a, 'f>,
has_fields: bool,
}
impl<'a, 'f, const SEP: char> EntryWrapper<'a, 'f, SEP> {
fn new(fmt: Writer<'a, 'f>) -> Self {
Self { fmt, has_fields: false }
}
fn entry(&mut self, entry: impl FnOnce(Writer) -> fmt::Result) -> fmt::Result {
let res = (|| match &mut self.fmt {
Writer::Pretty(f) => {
if !self.has_fields {
f.write_char('\n')?;
}
f.state.indent += 1;
entry(Writer::Pretty(f.as_mut()))?;
f.write_char(SEP)?;
f.write_char('\n')?;
f.state.indent -= 1;
Ok(())
}
Writer::Normal(f) => {
if self.has_fields {
f.write_char(SEP)?;
f.write_char(' ')?;
}
entry(Writer::Normal(f))
}
})();
self.has_fields = true;
res
}
}
enum Writer<'a, 'f> {
Normal(&'a mut fmt::Formatter<'f>),
Pretty(IndentedWriter<'a, 'f>),
}
impl<'f> Writer<'_, 'f> {
fn with<R>(f: &mut fmt::Formatter<'_>, func: impl FnOnce(Writer<'_, '_>) -> R) -> R {
let mut state;
let f = if f.alternate() {
state = IndentState {
indent: 0,
on_newline: true,
};
Writer::Pretty(IndentedWriter { f, state: &mut state })
} else {
Writer::Normal(f)
};
func(f)
}
fn as_mut(&mut self) -> Writer<'_, 'f> {
match self {
Writer::Normal(f) => Writer::Normal(f),
Writer::Pretty(f) => Writer::Pretty(f.as_mut()),
}
}
}
struct IndentedWriter<'a, 'f> {
f: &'a mut fmt::Formatter<'f>,
state: &'a mut IndentState,
}
struct IndentState {
indent: u32,
on_newline: bool,
}
impl<'f> IndentedWriter<'_, 'f> {
fn as_mut(&mut self) -> IndentedWriter<'_, 'f> {
IndentedWriter {
f: self.f,
state: self.state,
}
}
}
impl fmt::Write for IndentedWriter<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for s in s.split_inclusive('\n') {
if self.state.on_newline {
for _ in 0..self.state.indent {
self.f.write_str(" ")?;
}
}
self.state.on_newline = s.ends_with('\n');
self.f.write_str(s)?;
}
Ok(())
}
}
impl fmt::Write for Writer<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self {
Writer::Normal(f) => f.write_str(s),
Writer::Pretty(f) => f.write_str(s),
}
}
}
struct SatnFormatter<'a, 'f> {
f: Writer<'a, 'f>,
}
impl SatnFormatter<'_, '_> {
fn ser_variant<T: ser::Serialize + ?Sized>(
&mut self,
_tag: u8,
name: Option<&str>,
value: &T,
) -> Result<(), SatnError> {
write!(self, "(")?;
EntryWrapper::<','>::new(self.f.as_mut()).entry(|mut f| {
if let Some(name) = name {
write!(f, "{name}")?;
}
write!(f, " = ")?;
value.serialize(SatnFormatter { f })?;
Ok(())
})?;
write!(self, ")")?;
Ok(())
}
}
#[derive(From, Into)]
pub struct SatnError(fmt::Error);
impl ser::Error for SatnError {
fn custom<T: fmt::Display>(_msg: T) -> Self {
Self(fmt::Error)
}
}
impl SatnFormatter<'_, '_> {
#[inline(always)]
fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), SatnError> {
self.f.write_fmt(args)?;
Ok(())
}
}
impl<'a, 'f> ser::Serializer for SatnFormatter<'a, 'f> {
type Ok = ();
type Error = SatnError;
type SerializeArray = ArrayFormatter<'a, 'f>;
type SerializeSeqProduct = SeqFormatter<'a, 'f>;
type SerializeNamedProduct = NamedFormatter<'a, 'f>;
fn serialize_bool(mut self, v: bool) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u8(mut self, v: u8) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u16(mut self, v: u16) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u32(mut self, v: u32) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u64(mut self, v: u64) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u128(mut self, v: u128) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_u256(mut self, v: u256) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i8(mut self, v: i8) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i16(mut self, v: i16) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i32(mut self, v: i32) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i64(mut self, v: i64) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i128(mut self, v: i128) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_i256(mut self, v: i256) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_f32(mut self, v: f32) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_f64(mut self, v: f64) -> Result<Self::Ok, Self::Error> {
write!(self, "{v}")
}
fn serialize_str(mut self, v: &str) -> Result<Self::Ok, Self::Error> {
write!(self, "\"{v}\"")
}
fn serialize_bytes(mut self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
write!(self, "0x{}", hex::encode(v))
}
fn serialize_array(mut self, _len: usize) -> Result<Self::SerializeArray, Self::Error> {
write!(self, "[")?; Ok(ArrayFormatter {
f: EntryWrapper::new(self.f),
})
}
fn serialize_seq_product(self, len: usize) -> Result<Self::SerializeSeqProduct, Self::Error> {
self.serialize_named_product(len).map(|inner| SeqFormatter { inner })
}
fn serialize_named_product(mut self, _len: usize) -> Result<Self::SerializeNamedProduct, Self::Error> {
write!(self, "(")?; Ok(NamedFormatter {
f: EntryWrapper::new(self.f),
idx: 0,
})
}
fn serialize_variant<T: ser::Serialize + ?Sized>(
mut self,
tag: u8,
name: Option<&str>,
value: &T,
) -> Result<Self::Ok, Self::Error> {
self.ser_variant(tag, name, value)
}
}
struct ArrayFormatter<'a, 'f> {
f: EntryWrapper<'a, 'f, ','>,
}
impl ser::SerializeArray for ArrayFormatter<'_, '_> {
type Ok = ();
type Error = SatnError;
fn serialize_element<T: ser::Serialize + ?Sized>(&mut self, elem: &T) -> Result<(), Self::Error> {
self.f.entry(|f| elem.serialize(SatnFormatter { f }).map_err(|e| e.0))?;
Ok(())
}
fn end(mut self) -> Result<Self::Ok, Self::Error> {
write!(self.f.fmt, "]")?;
Ok(())
}
}
struct SeqFormatter<'a, 'f> {
inner: NamedFormatter<'a, 'f>,
}
impl ser::SerializeSeqProduct for SeqFormatter<'_, '_> {
type Ok = ();
type Error = SatnError;
fn serialize_element<T: ser::Serialize + ?Sized>(&mut self, elem: &T) -> Result<(), Self::Error> {
ser::SerializeNamedProduct::serialize_element(&mut self.inner, None, elem)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
ser::SerializeNamedProduct::end(self.inner)
}
}
struct NamedFormatter<'a, 'f> {
f: EntryWrapper<'a, 'f, ','>,
idx: usize,
}
impl ser::SerializeNamedProduct for NamedFormatter<'_, '_> {
type Ok = ();
type Error = SatnError;
fn serialize_element<T: ser::Serialize + ?Sized>(
&mut self,
name: Option<&str>,
elem: &T,
) -> Result<(), Self::Error> {
let res = self.f.entry(|mut f| {
if let Some(name) = name {
write!(f, "{name}")?;
} else {
write!(f, "{}", self.idx)?;
}
write!(f, " = ")?;
elem.serialize(SatnFormatter { f })?;
Ok(())
});
self.idx += 1;
res?;
Ok(())
}
fn end(mut self) -> Result<Self::Ok, Self::Error> {
write!(self.f.fmt, ")")?;
Ok(())
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum PsqlClient {
SpacetimeDB,
Postgres,
}
pub struct PsqlChars {
pub start: char,
pub sep: &'static str,
pub end: char,
pub quote: &'static str,
}
impl PsqlClient {
pub fn format_chars(&self) -> PsqlChars {
match self {
PsqlClient::SpacetimeDB => PsqlChars {
start: '(',
sep: " =",
end: ')',
quote: "",
},
PsqlClient::Postgres => PsqlChars {
start: '{',
sep: ":",
end: '}',
quote: "\"",
},
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Display)]
pub enum PsqlPrintFmt {
Hex,
Timestamp,
Duration,
Uuid,
Satn,
}
impl PsqlPrintFmt {
pub fn is_special(&self) -> bool {
self != &PsqlPrintFmt::Satn
}
pub fn use_fmt(tuple: &ProductType, field: &ProductTypeElement, name: Option<&str>) -> PsqlPrintFmt {
if tuple.is_identity()
|| tuple.is_connection_id()
|| field.algebraic_type.is_identity()
|| field.algebraic_type.is_connection_id()
|| name.map(ProductType::is_identity_tag).unwrap_or_default()
|| name.map(ProductType::is_connection_id_tag).unwrap_or_default()
{
return PsqlPrintFmt::Hex;
};
if tuple.is_timestamp()
|| field.algebraic_type.is_timestamp()
|| name.map(ProductType::is_timestamp_tag).unwrap_or_default()
{
return PsqlPrintFmt::Timestamp;
};
if tuple.is_time_duration()
|| field.algebraic_type.is_time_duration()
|| name.map(ProductType::is_time_duration_tag).unwrap_or_default()
{
return PsqlPrintFmt::Duration;
};
if tuple.is_uuid() || field.algebraic_type.is_uuid() || name.map(ProductType::is_uuid_tag).unwrap_or_default() {
return PsqlPrintFmt::Uuid;
};
PsqlPrintFmt::Satn
}
}
#[derive(Debug, Clone)]
pub struct PsqlType<'a> {
pub client: PsqlClient,
pub tuple: &'a ProductType,
pub field: &'a ProductTypeElement,
pub idx: usize,
}
impl PsqlType<'_> {
pub fn use_fmt(&self) -> PsqlPrintFmt {
PsqlPrintFmt::use_fmt(self.tuple, self.field, None)
}
}
pub struct SqlFormatter<'a, 'f> {
fmt: SatnFormatter<'a, 'f>,
ty: &'a PsqlType<'a>,
}
pub trait TypedWriter {
type Error: ser::Error;
fn write<W: fmt::Display>(&mut self, value: W) -> Result<(), Self::Error>;
fn write_bool(&mut self, value: bool) -> Result<(), Self::Error>;
fn write_string(&mut self, value: &str) -> Result<(), Self::Error>;
fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error>;
fn write_hex(&mut self, value: &[u8]) -> Result<(), Self::Error>;
fn write_timestamp(&mut self, value: Timestamp) -> Result<(), Self::Error>;
fn write_duration(&mut self, value: TimeDuration) -> Result<(), Self::Error>;
fn write_uuid(&mut self, value: Uuid) -> Result<(), Self::Error>;
fn write_alt_record(
&mut self,
_ty: &PsqlType,
_value: &ValueWithType<'_, ProductValue>,
) -> Result<bool, Self::Error> {
Ok(false)
}
fn write_record(
&mut self,
fields: Vec<(Cow<str>, PsqlType, ValueWithType<AlgebraicValue>)>,
) -> Result<(), Self::Error>;
fn write_variant(
&mut self,
tag: u8,
ty: PsqlType,
name: Option<&str>,
value: ValueWithType<AlgebraicValue>,
) -> Result<(), Self::Error>;
}
pub struct TypedArrayFormatter<'a, 'f, F> {
ty: &'a PsqlType<'a>,
f: &'f mut F,
}
impl<F: TypedWriter> ser::SerializeArray for TypedArrayFormatter<'_, '_, F> {
type Ok = ();
type Error = F::Error;
fn serialize_element<T: ser::Serialize + ?Sized>(&mut self, elem: &T) -> Result<(), Self::Error> {
elem.serialize(TypedSerializer { ty: self.ty, f: self.f })?;
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
pub struct TypedSeqFormatter<'a, 'f, F> {
ty: &'a PsqlType<'a>,
f: &'f mut F,
}
impl<F: TypedWriter> ser::SerializeSeqProduct for TypedSeqFormatter<'_, '_, F> {
type Ok = ();
type Error = F::Error;
fn serialize_element<T: ser::Serialize + ?Sized>(&mut self, elem: &T) -> Result<(), Self::Error> {
elem.serialize(TypedSerializer { ty: self.ty, f: self.f })?;
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
pub struct TypedNamedProductFormatter<F> {
f: PhantomData<F>,
}
impl<F: TypedWriter> ser::SerializeNamedProduct for TypedNamedProductFormatter<F> {
type Ok = ();
type Error = F::Error;
fn serialize_element<T: ser::Serialize + ?Sized>(
&mut self,
_name: Option<&str>,
_elem: &T,
) -> Result<(), Self::Error> {
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
pub struct TypedSerializer<'a, 'f, F> {
pub ty: &'a PsqlType<'a>,
pub f: &'f mut F,
}
impl<'a, 'f, F: TypedWriter> ser::Serializer for TypedSerializer<'a, 'f, F> {
type Ok = ();
type Error = F::Error;
type SerializeArray = TypedArrayFormatter<'a, 'f, F>;
type SerializeSeqProduct = TypedSeqFormatter<'a, 'f, F>;
type SerializeNamedProduct = TypedNamedProductFormatter<F>;
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
self.f.write_bool(v)
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
match self.ty.use_fmt() {
PsqlPrintFmt::Hex => self.f.write_hex(&v.to_be_bytes()),
PsqlPrintFmt::Uuid => self.f.write_uuid(Uuid::from_u128(v)),
_ => self.f.write(v),
}
}
fn serialize_u256(self, v: u256) -> Result<Self::Ok, Self::Error> {
match self.ty.use_fmt() {
PsqlPrintFmt::Hex => self.f.write_hex(&v.to_be_bytes()),
_ => self.f.write(v),
}
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
match self.ty.use_fmt() {
PsqlPrintFmt::Duration => self.f.write_duration(TimeDuration::from_micros(v)),
PsqlPrintFmt::Timestamp => self.f.write_timestamp(Timestamp::from_micros_since_unix_epoch(v)),
_ => self.f.write(v),
}
}
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_i256(self, v: i256) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
self.f.write(v)
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
self.f.write_string(v)
}
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
if self.ty.use_fmt() == PsqlPrintFmt::Satn {
self.f.write_hex(v)
} else {
self.f.write_bytes(v)
}
}
fn serialize_array(self, _len: usize) -> Result<Self::SerializeArray, Self::Error> {
Ok(TypedArrayFormatter { ty: self.ty, f: self.f })
}
fn serialize_seq_product(self, _len: usize) -> Result<Self::SerializeSeqProduct, Self::Error> {
Ok(TypedSeqFormatter { ty: self.ty, f: self.f })
}
fn serialize_named_product(self, _len: usize) -> Result<Self::SerializeNamedProduct, Self::Error> {
unreachable!("This should never be called, use `serialize_named_product_raw` instead.");
}
fn serialize_named_product_raw(self, value: &ValueWithType<'_, ProductValue>) -> Result<Self::Ok, Self::Error> {
let val = &value.val.elements;
assert_eq!(val.len(), value.ty().elements.len());
if self.ty.use_fmt().is_special() {
let (tuple, field) = if let Some(product) = self.ty.field.algebraic_type.as_product() {
(product, &product.elements[0])
} else {
(self.ty.tuple, self.ty.field)
};
return value.val.serialize(TypedSerializer {
ty: &PsqlType {
client: self.ty.client,
tuple,
field,
idx: self.ty.idx,
},
f: self.f,
});
}
if self.f.write_alt_record(self.ty, value)? {
return Ok(());
}
let mut record = Vec::with_capacity(val.len());
for (idx, (val, field)) in val.iter().zip(&*value.ty().elements).enumerate() {
let ty = PsqlType {
client: self.ty.client,
tuple: value.ty(),
field,
idx,
};
record.push((
field
.name()
.map(|n| &**n)
.map(Cow::from)
.unwrap_or_else(|| Cow::from(format!("col_{idx}"))),
ty,
value.with(&field.algebraic_type, val),
));
}
self.f.write_record(record)
}
fn serialize_variant_raw(self, sum: &ValueWithType<'_, SumValue>) -> Result<Self::Ok, Self::Error> {
let sv = sum.value();
let (tag, val) = (sv.tag, &*sv.value);
let var_ty = &sum.ty().variants[tag as usize]; let product = ProductType::from([AlgebraicType::sum(sum.ty().clone())]);
let ty = PsqlType {
client: self.ty.client,
tuple: &product,
field: &product.elements[0],
idx: 0,
};
self.f.write_variant(
tag,
ty,
var_ty.name().map(|n| &**n),
sum.with(&var_ty.algebraic_type, val),
)
}
fn serialize_variant<T: Serialize + ?Sized>(
self,
_tag: u8,
_name: Option<&str>,
_value: &T,
) -> Result<Self::Ok, Self::Error> {
unreachable!("Use `serialize_variant_raw` instead.");
}
}
impl TypedWriter for SqlFormatter<'_, '_> {
type Error = SatnError;
fn write<W: fmt::Display>(&mut self, value: W) -> Result<(), Self::Error> {
write!(self.fmt, "{value}")
}
fn write_bool(&mut self, value: bool) -> Result<(), Self::Error> {
write!(self.fmt, "{value}")
}
fn write_string(&mut self, value: &str) -> Result<(), Self::Error> {
write!(self.fmt, "\"{value}\"")
}
fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error> {
self.write_hex(value)
}
fn write_hex(&mut self, value: &[u8]) -> Result<(), Self::Error> {
match self.ty.client {
PsqlClient::SpacetimeDB => write!(self.fmt, "0x{}", hex::encode(value)),
PsqlClient::Postgres => write!(self.fmt, "\"0x{}\"", hex::encode(value)),
}
}
fn write_timestamp(&mut self, value: Timestamp) -> Result<(), Self::Error> {
match self.ty.client {
PsqlClient::SpacetimeDB => write!(self.fmt, "{}", value.to_rfc3339().unwrap()),
PsqlClient::Postgres => write!(self.fmt, "\"{}\"", value.to_rfc3339().unwrap()),
}
}
fn write_duration(&mut self, value: TimeDuration) -> Result<(), Self::Error> {
match self.ty.client {
PsqlClient::SpacetimeDB => write!(self.fmt, "{value}"),
PsqlClient::Postgres => write!(self.fmt, "\"{}\"", value.to_iso8601()),
}
}
fn write_uuid(&mut self, value: Uuid) -> Result<(), Self::Error> {
write!(self.fmt, "\"{value}\"")
}
fn write_record(
&mut self,
fields: Vec<(Cow<str>, PsqlType<'_>, ValueWithType<AlgebraicValue>)>,
) -> Result<(), Self::Error> {
let PsqlChars { start, sep, end, quote } = self.ty.client.format_chars();
write!(self.fmt, "{start}")?;
for (idx, (name, ty, value)) in fields.into_iter().enumerate() {
if idx > 0 {
write!(self.fmt, ", ")?;
}
write!(self.fmt, "{quote}{name}{quote}{sep} ")?;
value.serialize(TypedSerializer { ty: &ty, f: self })?;
}
write!(self.fmt, "{end}")?;
Ok(())
}
fn write_variant(
&mut self,
tag: u8,
ty: PsqlType,
name: Option<&str>,
value: ValueWithType<AlgebraicValue>,
) -> Result<(), Self::Error> {
self.write_record(vec![(
name.map(Cow::from).unwrap_or_else(|| Cow::from(format!("col_{tag}"))),
ty,
value,
)])
}
}