use crate::error::{SqlResult, convert_error};
use dbsp::NumEntries;
use feldera_macros::IsNone;
use feldera_types::serde_with_context::{
DeserializeWithContext, SerializeWithContext, SqlSerdeConfig, serde_config::UuidFormat,
};
use serde::{Deserializer, Serializer, de, de::Error as _};
use size_of::{Context, SizeOf};
use std::fmt::{self, Debug, Display};
#[derive(
Debug,
Default,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
IsNone,
)]
#[archive_attr(derive(Ord, Eq, PartialEq, PartialOrd))]
#[archive(compare(PartialEq, PartialOrd))]
pub struct Uuid {
value: uuid::Uuid,
}
impl From<uuid::Uuid> for Uuid {
fn from(uuid: uuid::Uuid) -> Self {
Uuid { value: uuid }
}
}
impl SizeOf for Uuid {
fn size_of_children(&self, _context: &mut Context) {}
}
impl SerializeWithContext<SqlSerdeConfig> for Uuid {
fn serialize_with_context<S>(
&self,
serializer: S,
context: &SqlSerdeConfig,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match context.uuid_format {
UuidFormat::String => serializer.serialize_str(&self.value.to_string()),
UuidFormat::Binary => serializer.serialize_bytes(self.value.as_bytes()),
}
}
}
#[doc(hidden)]
impl NumEntries for &Uuid {
const CONST_NUM_ENTRIES: Option<usize> = None;
#[doc(hidden)]
#[inline]
fn num_entries_shallow(&self) -> usize {
1
}
#[doc(hidden)]
#[inline]
fn num_entries_deep(&self) -> usize {
1
}
}
impl<'de, AUX> DeserializeWithContext<'de, SqlSerdeConfig, AUX> for Uuid {
fn deserialize_with_context<D>(
deserializer: D,
config: &'de SqlSerdeConfig,
) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
fn de_error<E: de::Error>(e: uuid::Error) -> E {
E::custom(format_args!("UUID parsing failed: {}", e))
}
struct UuidVisitor;
impl<'vi> de::Visitor<'vi> for UuidVisitor {
type Value = Uuid;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a UUID string or byte array")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
Ok(Uuid {
value: value.parse::<uuid::Uuid>().map_err(de_error)?,
})
}
fn visit_bytes<E: de::Error>(self, value: &[u8]) -> Result<Uuid, E> {
Ok(Uuid {
value: uuid::Uuid::from_slice(value).map_err(de_error)?,
})
}
fn visit_seq<A>(self, mut seq: A) -> Result<Uuid, A::Error>
where
A: de::SeqAccess<'vi>,
{
#[rustfmt::skip]
let bytes = [
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(0, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(1, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(2, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(3, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(4, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(5, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(6, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(7, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(8, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(9, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(10, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(11, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(12, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(13, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(14, &self)) },
match seq.next_element()? { Some(e) => e, None => return Err(A::Error::invalid_length(15, &self)) },
];
Ok(Uuid::from_bytes(bytes))
}
}
match config.uuid_format {
UuidFormat::String => deserializer.deserialize_str(UuidVisitor),
UuidFormat::Binary => deserializer.deserialize_bytes(UuidVisitor),
}
}
}
impl Uuid {
pub fn from_bytes(data: [u8; 16]) -> Self {
Self {
value: uuid::Uuid::from_bytes(data),
}
}
pub fn to_bytes(&self) -> &[u8; 16] {
self.value.as_bytes()
}
#[doc(hidden)]
pub fn try_from_ref(value: &str) -> SqlResult<Self> {
let uuid = convert_error(uuid::Uuid::parse_str(value))?;
Ok(Self { value: uuid })
}
}
impl Display for Uuid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.value, f)
}
}