#![cfg(feature = "ulid")]
use alloc::string::String;
use ulid::Ulid;
use crate::{
Def, Facet, OxPtrConst, OxPtrUninit, ParseError, PtrConst, Shape, ShapeBuilder, TryFromOutcome,
Type, UserType, VTableIndirect,
};
unsafe fn try_from_ulid(
target: OxPtrUninit,
src_shape: &'static Shape,
src: PtrConst,
) -> TryFromOutcome {
unsafe {
if src_shape.id == <&str as Facet>::SHAPE.id {
let source_str: &str = src.get::<&str>();
match Ulid::from_string(source_str) {
Ok(val) => {
target.put(val);
TryFromOutcome::Converted
}
Err(_) => TryFromOutcome::Failed("ULID parsing failed".into()),
}
}
else if src_shape.id == <String as Facet>::SHAPE.id {
let source_str = src.read::<String>();
match Ulid::from_string(&source_str) {
Ok(val) => {
target.put(val);
TryFromOutcome::Converted
}
Err(_) => TryFromOutcome::Failed("ULID parsing failed".into()),
}
} else {
TryFromOutcome::Unsupported
}
}
}
unsafe fn parse_ulid(s: &str, target: OxPtrUninit) -> Option<Result<(), ParseError>> {
unsafe {
let parsed = Ulid::from_string(s).map_err(|_| ParseError::from_str("ULID parsing failed"));
Some(match parsed {
Ok(val) => {
target.put(val);
Ok(())
}
Err(e) => Err(e),
})
}
}
unsafe fn display_ulid(
source: OxPtrConst,
f: &mut core::fmt::Formatter<'_>,
) -> Option<core::fmt::Result> {
unsafe {
let ulid = source.get::<Ulid>();
Some(write!(f, "{ulid}"))
}
}
unsafe fn partial_eq_ulid(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
unsafe {
let a = a.get::<Ulid>();
let b = b.get::<Ulid>();
Some(a == b)
}
}
unsafe fn parse_bytes_ulid(bytes: &[u8], target: OxPtrUninit) -> Option<Result<(), ParseError>> {
unsafe {
if bytes.len() != 16 {
return Some(Err(ParseError::from_str("ULID must be exactly 16 bytes")));
}
let mut arr = [0u8; 16];
arr.copy_from_slice(bytes);
let val = u128::from_be_bytes(arr);
target.put(Ulid::from(val));
Some(Ok(()))
}
}
const ULID_VTABLE: VTableIndirect = VTableIndirect {
display: Some(display_ulid),
try_from: Some(try_from_ulid),
parse: Some(parse_ulid),
parse_bytes: Some(parse_bytes_ulid),
partial_eq: Some(partial_eq_ulid),
..VTableIndirect::EMPTY
};
unsafe impl Facet<'_> for Ulid {
const SHAPE: &'static Shape = &const {
ShapeBuilder::for_sized::<Ulid>("Ulid")
.module_path("ulid")
.ty(Type::User(UserType::Opaque))
.def(Def::Scalar)
.vtable_indirect(&ULID_VTABLE)
.inner(<alloc::string::String as Facet>::SHAPE)
.eq()
.build()
};
}