1use crate::{
6 db::{
7 codec::{decode_cbor_bytes, encode_cbor_bytes},
8 data::{
9 decode_structural_field_by_kind_bytes, decode_structural_value_storage_bytes,
10 encode_structural_field_by_kind_bytes, encode_structural_value_storage_bytes,
11 },
12 },
13 error::InternalError,
14 model::field::{FieldKind, ScalarCodec},
15 traits::{DeserializeOwned, FieldValue, Serialize, field_value_vec_from_value},
16 types::{Blob, Date, Duration, Float32, Float64, Principal, Subaccount, Timestamp, Ulid, Unit},
17 value::Value,
18};
19use std::str;
20
21const SCALAR_SLOT_PREFIX: u8 = 0xFF;
22const SCALAR_SLOT_TAG_NULL: u8 = 0;
23const SCALAR_SLOT_TAG_VALUE: u8 = 1;
24const CBOR_NULL_PAYLOAD: [u8; 1] = [0xF6];
25
26const SCALAR_BOOL_PAYLOAD_LEN: usize = 1;
27const SCALAR_WORD32_PAYLOAD_LEN: usize = 4;
28const SCALAR_WORD64_PAYLOAD_LEN: usize = 8;
29const SCALAR_ULID_PAYLOAD_LEN: usize = 16;
30const SCALAR_SUBACCOUNT_PAYLOAD_LEN: usize = 32;
31
32const SCALAR_BOOL_FALSE_TAG: u8 = 0;
33const SCALAR_BOOL_TRUE_TAG: u8 = 1;
34
35#[derive(Clone, Copy, Debug)]
45pub enum ScalarValueRef<'a> {
46 Blob(&'a [u8]),
47 Bool(bool),
48 Date(Date),
49 Duration(Duration),
50 Float32(Float32),
51 Float64(Float64),
52 Int(i64),
53 Principal(Principal),
54 Subaccount(Subaccount),
55 Text(&'a str),
56 Timestamp(Timestamp),
57 Uint(u64),
58 Ulid(Ulid),
59 Unit,
60}
61
62impl ScalarValueRef<'_> {
63 #[must_use]
65 pub fn into_value(self) -> Value {
66 match self {
67 Self::Blob(value) => Value::Blob(value.to_vec()),
68 Self::Bool(value) => Value::Bool(value),
69 Self::Date(value) => Value::Date(value),
70 Self::Duration(value) => Value::Duration(value),
71 Self::Float32(value) => Value::Float32(value),
72 Self::Float64(value) => Value::Float64(value),
73 Self::Int(value) => Value::Int(value),
74 Self::Principal(value) => Value::Principal(value),
75 Self::Subaccount(value) => Value::Subaccount(value),
76 Self::Text(value) => Value::Text(value.to_owned()),
77 Self::Timestamp(value) => Value::Timestamp(value),
78 Self::Uint(value) => Value::Uint(value),
79 Self::Ulid(value) => Value::Ulid(value),
80 Self::Unit => Value::Unit,
81 }
82 }
83}
84
85#[derive(Clone, Copy, Debug)]
95pub enum ScalarSlotValueRef<'a> {
96 Null,
97 Value(ScalarValueRef<'a>),
98}
99
100pub trait PersistedScalar: Sized {
110 const CODEC: ScalarCodec;
112
113 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError>;
115
116 fn decode_scalar_payload(bytes: &[u8], field_name: &'static str)
118 -> Result<Self, InternalError>;
119}
120
121pub fn encode_persisted_slot_payload<T>(
124 value: &T,
125 field_name: &'static str,
126) -> Result<Vec<u8>, InternalError>
127where
128 T: Serialize,
129{
130 encode_cbor_bytes(value)
131 .map_err(|err| InternalError::persisted_row_field_encode_failed(field_name, err))
132}
133
134pub fn encode_persisted_slot_payload_by_kind<T>(
137 value: &T,
138 kind: FieldKind,
139 field_name: &'static str,
140) -> Result<Vec<u8>, InternalError>
141where
142 T: FieldValue,
143{
144 encode_structural_field_by_kind_bytes(kind, &value.to_value(), field_name)
145 .map_err(|err| InternalError::persisted_row_field_encode_failed(field_name, err))
146}
147
148pub fn encode_persisted_scalar_slot_payload<T>(
150 value: &T,
151 field_name: &'static str,
152) -> Result<Vec<u8>, InternalError>
153where
154 T: PersistedScalar,
155{
156 let payload = value.encode_scalar_payload()?;
157 let mut encoded = Vec::with_capacity(payload.len() + 2);
158 encoded.push(SCALAR_SLOT_PREFIX);
159 encoded.push(SCALAR_SLOT_TAG_VALUE);
160 encoded.extend_from_slice(&payload);
161
162 if encoded.len() < 2 {
163 return Err(InternalError::persisted_row_field_encode_failed(
164 field_name,
165 "scalar payload envelope underflow",
166 ));
167 }
168
169 Ok(encoded)
170}
171
172pub fn encode_persisted_option_scalar_slot_payload<T>(
174 value: &Option<T>,
175 field_name: &'static str,
176) -> Result<Vec<u8>, InternalError>
177where
178 T: PersistedScalar,
179{
180 match value {
181 Some(value) => encode_persisted_scalar_slot_payload(value, field_name),
182 None => Ok(vec![SCALAR_SLOT_PREFIX, SCALAR_SLOT_TAG_NULL]),
183 }
184}
185
186pub fn decode_persisted_slot_payload<T>(
189 bytes: &[u8],
190 field_name: &'static str,
191) -> Result<T, InternalError>
192where
193 T: DeserializeOwned,
194{
195 decode_cbor_bytes(bytes)
196 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))
197}
198
199fn decode_persisted_structural_slot_payload_by_kind<T>(
202 bytes: &[u8],
203 kind: FieldKind,
204 field_name: &'static str,
205) -> Result<Option<T>, InternalError>
206where
207 T: FieldValue,
208{
209 if persisted_slot_payload_is_null(bytes) {
210 return Ok(None);
211 }
212
213 decode_persisted_slot_payload_by_kind(bytes, kind, field_name).map(Some)
214}
215
216pub fn decode_persisted_slot_payload_by_kind<T>(
219 bytes: &[u8],
220 kind: FieldKind,
221 field_name: &'static str,
222) -> Result<T, InternalError>
223where
224 T: FieldValue,
225{
226 let value = decode_structural_field_by_kind_bytes(bytes, kind)
227 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))?;
228
229 T::from_value(&value).ok_or_else(|| {
230 InternalError::persisted_row_field_decode_failed(
231 field_name,
232 format!(
233 "value payload does not match {}",
234 std::any::type_name::<T>()
235 ),
236 )
237 })
238}
239
240pub fn decode_persisted_non_null_slot_payload_by_kind<T>(
243 bytes: &[u8],
244 kind: FieldKind,
245 field_name: &'static str,
246) -> Result<T, InternalError>
247where
248 T: FieldValue,
249{
250 decode_persisted_structural_slot_payload_by_kind(bytes, kind, field_name)?.ok_or_else(|| {
251 InternalError::persisted_row_field_decode_failed(
252 field_name,
253 "unexpected null for non-nullable field",
254 )
255 })
256}
257
258pub fn decode_persisted_option_slot_payload_by_kind<T>(
261 bytes: &[u8],
262 kind: FieldKind,
263 field_name: &'static str,
264) -> Result<Option<T>, InternalError>
265where
266 T: FieldValue,
267{
268 decode_persisted_structural_slot_payload_by_kind(bytes, kind, field_name)
269}
270
271fn decode_persisted_value_payload_as<T, F>(
274 bytes: &[u8],
275 field_name: &'static str,
276 mismatch: impl FnOnce() -> String,
277 decode: F,
278) -> Result<T, InternalError>
279where
280 F: FnOnce(&Value) -> Option<T>,
281{
282 let value = decode_structural_value_storage_bytes(bytes)
283 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))?;
284
285 decode(&value)
286 .ok_or_else(|| InternalError::persisted_row_field_decode_failed(field_name, mismatch()))
287}
288
289fn encode_persisted_value_payload(
292 value: Value,
293 field_name: &'static str,
294) -> Result<Vec<u8>, InternalError> {
295 encode_structural_value_storage_bytes(&value)
296 .map_err(|err| InternalError::persisted_row_field_encode_failed(field_name, err))
297}
298
299pub fn decode_persisted_custom_slot_payload<T>(
302 bytes: &[u8],
303 field_name: &'static str,
304) -> Result<T, InternalError>
305where
306 T: FieldValue,
307{
308 decode_persisted_value_payload_as(
309 bytes,
310 field_name,
311 || {
312 format!(
313 "value payload does not match {}",
314 std::any::type_name::<T>()
315 )
316 },
317 T::from_value,
318 )
319}
320
321pub fn decode_persisted_custom_many_slot_payload<T>(
324 bytes: &[u8],
325 field_name: &'static str,
326) -> Result<Vec<T>, InternalError>
327where
328 T: FieldValue,
329{
330 decode_persisted_value_payload_as(
331 bytes,
332 field_name,
333 || {
334 format!(
335 "value payload does not match Vec<{}>",
336 std::any::type_name::<T>()
337 )
338 },
339 field_value_vec_from_value::<T>,
340 )
341}
342
343pub fn encode_persisted_custom_slot_payload<T>(
346 value: &T,
347 field_name: &'static str,
348) -> Result<Vec<u8>, InternalError>
349where
350 T: FieldValue,
351{
352 encode_persisted_value_payload(value.to_value(), field_name)
353}
354
355pub fn encode_persisted_custom_many_slot_payload<T>(
357 values: &[T],
358 field_name: &'static str,
359) -> Result<Vec<u8>, InternalError>
360where
361 T: FieldValue,
362{
363 encode_persisted_value_payload(
364 Value::List(values.iter().map(FieldValue::to_value).collect()),
365 field_name,
366 )
367}
368
369pub fn decode_persisted_scalar_slot_payload<T>(
371 bytes: &[u8],
372 field_name: &'static str,
373) -> Result<T, InternalError>
374where
375 T: PersistedScalar,
376{
377 let payload = decode_scalar_slot_payload_body(bytes, field_name)?.ok_or_else(|| {
378 InternalError::persisted_row_field_decode_failed(
379 field_name,
380 "unexpected null for non-nullable scalar field",
381 )
382 })?;
383
384 T::decode_scalar_payload(payload, field_name)
385}
386
387pub fn decode_persisted_option_scalar_slot_payload<T>(
389 bytes: &[u8],
390 field_name: &'static str,
391) -> Result<Option<T>, InternalError>
392where
393 T: PersistedScalar,
394{
395 let Some(payload) = decode_scalar_slot_payload_body(bytes, field_name)? else {
396 return Ok(None);
397 };
398
399 T::decode_scalar_payload(payload, field_name).map(Some)
400}
401
402fn persisted_slot_payload_is_null(bytes: &[u8]) -> bool {
404 bytes == CBOR_NULL_PAYLOAD
405}
406
407pub(super) fn encode_scalar_slot_value(value: ScalarSlotValueRef<'_>) -> Vec<u8> {
409 match value {
410 ScalarSlotValueRef::Null => vec![SCALAR_SLOT_PREFIX, SCALAR_SLOT_TAG_NULL],
411 ScalarSlotValueRef::Value(value) => {
412 let mut encoded = Vec::new();
413 encoded.push(SCALAR_SLOT_PREFIX);
414 encoded.push(SCALAR_SLOT_TAG_VALUE);
415
416 match value {
417 ScalarValueRef::Blob(bytes) => encoded.extend_from_slice(bytes),
418 ScalarValueRef::Bool(value) => encoded.push(u8::from(value)),
419 ScalarValueRef::Date(value) => {
420 encoded.extend_from_slice(&value.as_days_since_epoch().to_le_bytes());
421 }
422 ScalarValueRef::Duration(value) => {
423 encoded.extend_from_slice(&value.as_millis().to_le_bytes());
424 }
425 ScalarValueRef::Float32(value) => {
426 encoded.extend_from_slice(&value.get().to_bits().to_le_bytes());
427 }
428 ScalarValueRef::Float64(value) => {
429 encoded.extend_from_slice(&value.get().to_bits().to_le_bytes());
430 }
431 ScalarValueRef::Int(value) => encoded.extend_from_slice(&value.to_le_bytes()),
432 ScalarValueRef::Principal(value) => encoded.extend_from_slice(value.as_slice()),
433 ScalarValueRef::Subaccount(value) => encoded.extend_from_slice(&value.to_bytes()),
434 ScalarValueRef::Text(value) => encoded.extend_from_slice(value.as_bytes()),
435 ScalarValueRef::Timestamp(value) => {
436 encoded.extend_from_slice(&value.as_millis().to_le_bytes());
437 }
438 ScalarValueRef::Uint(value) => encoded.extend_from_slice(&value.to_le_bytes()),
439 ScalarValueRef::Ulid(value) => encoded.extend_from_slice(&value.to_bytes()),
440 ScalarValueRef::Unit => {}
441 }
442
443 encoded
444 }
445 }
446}
447
448fn decode_scalar_slot_payload_body<'a>(
450 bytes: &'a [u8],
451 field_name: &'static str,
452) -> Result<Option<&'a [u8]>, InternalError> {
453 let Some((&prefix, rest)) = bytes.split_first() else {
454 return Err(InternalError::persisted_row_field_decode_failed(
455 field_name,
456 "empty scalar payload",
457 ));
458 };
459 if prefix != SCALAR_SLOT_PREFIX {
460 return Err(InternalError::persisted_row_field_decode_failed(
461 field_name,
462 format!(
463 "scalar payload prefix mismatch: expected slot envelope prefix byte 0x{SCALAR_SLOT_PREFIX:02X}, found 0x{prefix:02X}",
464 ),
465 ));
466 }
467 let Some((&tag, payload)) = rest.split_first() else {
468 return Err(InternalError::persisted_row_field_decode_failed(
469 field_name,
470 "truncated scalar payload tag",
471 ));
472 };
473
474 match tag {
475 SCALAR_SLOT_TAG_NULL => {
476 if !payload.is_empty() {
477 return Err(InternalError::persisted_row_field_decode_failed(
478 field_name,
479 "null scalar payload has trailing bytes",
480 ));
481 }
482
483 Ok(None)
484 }
485 SCALAR_SLOT_TAG_VALUE => Ok(Some(payload)),
486 _ => Err(InternalError::persisted_row_field_decode_failed(
487 field_name,
488 format!("invalid scalar payload tag {tag}"),
489 )),
490 }
491}
492
493#[expect(clippy::too_many_lines)]
495pub(super) fn decode_scalar_slot_value<'a>(
496 bytes: &'a [u8],
497 codec: ScalarCodec,
498 field_name: &'static str,
499) -> Result<ScalarSlotValueRef<'a>, InternalError> {
500 let Some(payload) = decode_scalar_slot_payload_body(bytes, field_name)? else {
501 return Ok(ScalarSlotValueRef::Null);
502 };
503
504 let value = match codec {
505 ScalarCodec::Blob => ScalarValueRef::Blob(payload),
506 ScalarCodec::Bool => {
507 let [value] = payload else {
508 return Err(
509 InternalError::persisted_row_field_payload_exact_len_required(
510 field_name,
511 "bool",
512 SCALAR_BOOL_PAYLOAD_LEN,
513 ),
514 );
515 };
516 match *value {
517 SCALAR_BOOL_FALSE_TAG => ScalarValueRef::Bool(false),
518 SCALAR_BOOL_TRUE_TAG => ScalarValueRef::Bool(true),
519 _ => {
520 return Err(InternalError::persisted_row_field_payload_invalid_byte(
521 field_name, "bool", *value,
522 ));
523 }
524 }
525 }
526 ScalarCodec::Date => {
527 let bytes: [u8; SCALAR_WORD32_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
528 InternalError::persisted_row_field_payload_exact_len_required(
529 field_name,
530 "date",
531 SCALAR_WORD32_PAYLOAD_LEN,
532 )
533 })?;
534 ScalarValueRef::Date(Date::from_days_since_epoch(i32::from_le_bytes(bytes)))
535 }
536 ScalarCodec::Duration => {
537 let bytes: [u8; SCALAR_WORD64_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
538 InternalError::persisted_row_field_payload_exact_len_required(
539 field_name,
540 "duration",
541 SCALAR_WORD64_PAYLOAD_LEN,
542 )
543 })?;
544 ScalarValueRef::Duration(Duration::from_millis(u64::from_le_bytes(bytes)))
545 }
546 ScalarCodec::Float32 => {
547 let bytes: [u8; SCALAR_WORD32_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
548 InternalError::persisted_row_field_payload_exact_len_required(
549 field_name,
550 "float32",
551 SCALAR_WORD32_PAYLOAD_LEN,
552 )
553 })?;
554 let value = f32::from_bits(u32::from_le_bytes(bytes));
555 let value = Float32::try_new(value).ok_or_else(|| {
556 InternalError::persisted_row_field_payload_non_finite(field_name, "float32")
557 })?;
558 ScalarValueRef::Float32(value)
559 }
560 ScalarCodec::Float64 => {
561 let bytes: [u8; SCALAR_WORD64_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
562 InternalError::persisted_row_field_payload_exact_len_required(
563 field_name,
564 "float64",
565 SCALAR_WORD64_PAYLOAD_LEN,
566 )
567 })?;
568 let value = f64::from_bits(u64::from_le_bytes(bytes));
569 let value = Float64::try_new(value).ok_or_else(|| {
570 InternalError::persisted_row_field_payload_non_finite(field_name, "float64")
571 })?;
572 ScalarValueRef::Float64(value)
573 }
574 ScalarCodec::Int64 => {
575 let bytes: [u8; SCALAR_WORD64_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
576 InternalError::persisted_row_field_payload_exact_len_required(
577 field_name,
578 "int",
579 SCALAR_WORD64_PAYLOAD_LEN,
580 )
581 })?;
582 ScalarValueRef::Int(i64::from_le_bytes(bytes))
583 }
584 ScalarCodec::Principal => ScalarValueRef::Principal(
585 Principal::try_from_bytes(payload)
586 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))?,
587 ),
588 ScalarCodec::Subaccount => {
589 let bytes: [u8; SCALAR_SUBACCOUNT_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
590 InternalError::persisted_row_field_payload_exact_len_required(
591 field_name,
592 "subaccount",
593 SCALAR_SUBACCOUNT_PAYLOAD_LEN,
594 )
595 })?;
596 ScalarValueRef::Subaccount(Subaccount::from_array(bytes))
597 }
598 ScalarCodec::Text => {
599 let value = str::from_utf8(payload).map_err(|err| {
600 InternalError::persisted_row_field_text_payload_invalid_utf8(field_name, err)
601 })?;
602 ScalarValueRef::Text(value)
603 }
604 ScalarCodec::Timestamp => {
605 let bytes: [u8; SCALAR_WORD64_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
606 InternalError::persisted_row_field_payload_exact_len_required(
607 field_name,
608 "timestamp",
609 SCALAR_WORD64_PAYLOAD_LEN,
610 )
611 })?;
612 ScalarValueRef::Timestamp(Timestamp::from_millis(i64::from_le_bytes(bytes)))
613 }
614 ScalarCodec::Uint64 => {
615 let bytes: [u8; SCALAR_WORD64_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
616 InternalError::persisted_row_field_payload_exact_len_required(
617 field_name,
618 "uint",
619 SCALAR_WORD64_PAYLOAD_LEN,
620 )
621 })?;
622 ScalarValueRef::Uint(u64::from_le_bytes(bytes))
623 }
624 ScalarCodec::Ulid => {
625 let bytes: [u8; SCALAR_ULID_PAYLOAD_LEN] = payload.try_into().map_err(|_| {
626 InternalError::persisted_row_field_payload_exact_len_required(
627 field_name,
628 "ulid",
629 SCALAR_ULID_PAYLOAD_LEN,
630 )
631 })?;
632 ScalarValueRef::Ulid(Ulid::from_bytes(bytes))
633 }
634 ScalarCodec::Unit => {
635 if !payload.is_empty() {
636 return Err(InternalError::persisted_row_field_payload_must_be_empty(
637 field_name, "unit",
638 ));
639 }
640 ScalarValueRef::Unit
641 }
642 };
643
644 Ok(ScalarSlotValueRef::Value(value))
645}
646
647macro_rules! impl_persisted_scalar_signed {
648 ($($ty:ty),* $(,)?) => {
649 $(
650 impl PersistedScalar for $ty {
651 const CODEC: ScalarCodec = ScalarCodec::Int64;
652
653 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
654 Ok(i64::from(*self).to_le_bytes().to_vec())
655 }
656
657 fn decode_scalar_payload(
658 bytes: &[u8],
659 field_name: &'static str,
660 ) -> Result<Self, InternalError> {
661 let raw: [u8; SCALAR_WORD64_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
662 InternalError::persisted_row_field_payload_exact_len_required(
663 field_name,
664 "int",
665 SCALAR_WORD64_PAYLOAD_LEN,
666 )
667 })?;
668 <$ty>::try_from(i64::from_le_bytes(raw)).map_err(|_| {
669 InternalError::persisted_row_field_payload_out_of_range(
670 field_name,
671 "integer",
672 )
673 })
674 }
675 }
676 )*
677 };
678}
679
680macro_rules! impl_persisted_scalar_unsigned {
681 ($($ty:ty),* $(,)?) => {
682 $(
683 impl PersistedScalar for $ty {
684 const CODEC: ScalarCodec = ScalarCodec::Uint64;
685
686 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
687 Ok(u64::from(*self).to_le_bytes().to_vec())
688 }
689
690 fn decode_scalar_payload(
691 bytes: &[u8],
692 field_name: &'static str,
693 ) -> Result<Self, InternalError> {
694 let raw: [u8; SCALAR_WORD64_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
695 InternalError::persisted_row_field_payload_exact_len_required(
696 field_name,
697 "uint",
698 SCALAR_WORD64_PAYLOAD_LEN,
699 )
700 })?;
701 <$ty>::try_from(u64::from_le_bytes(raw)).map_err(|_| {
702 InternalError::persisted_row_field_payload_out_of_range(
703 field_name,
704 "unsigned",
705 )
706 })
707 }
708 }
709 )*
710 };
711}
712
713impl_persisted_scalar_signed!(i8, i16, i32, i64);
714impl_persisted_scalar_unsigned!(u8, u16, u32, u64);
715
716impl PersistedScalar for bool {
717 const CODEC: ScalarCodec = ScalarCodec::Bool;
718
719 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
720 Ok(vec![u8::from(*self)])
721 }
722
723 fn decode_scalar_payload(
724 bytes: &[u8],
725 field_name: &'static str,
726 ) -> Result<Self, InternalError> {
727 let [value] = bytes else {
728 return Err(
729 InternalError::persisted_row_field_payload_exact_len_required(
730 field_name,
731 "bool",
732 SCALAR_BOOL_PAYLOAD_LEN,
733 ),
734 );
735 };
736
737 match *value {
738 SCALAR_BOOL_FALSE_TAG => Ok(false),
739 SCALAR_BOOL_TRUE_TAG => Ok(true),
740 _ => Err(InternalError::persisted_row_field_payload_invalid_byte(
741 field_name, "bool", *value,
742 )),
743 }
744 }
745}
746
747impl PersistedScalar for String {
748 const CODEC: ScalarCodec = ScalarCodec::Text;
749
750 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
751 Ok(self.as_bytes().to_vec())
752 }
753
754 fn decode_scalar_payload(
755 bytes: &[u8],
756 field_name: &'static str,
757 ) -> Result<Self, InternalError> {
758 str::from_utf8(bytes).map(str::to_owned).map_err(|err| {
759 InternalError::persisted_row_field_text_payload_invalid_utf8(field_name, err)
760 })
761 }
762}
763
764impl PersistedScalar for Vec<u8> {
765 const CODEC: ScalarCodec = ScalarCodec::Blob;
766
767 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
768 Ok(self.clone())
769 }
770
771 fn decode_scalar_payload(
772 bytes: &[u8],
773 _field_name: &'static str,
774 ) -> Result<Self, InternalError> {
775 Ok(bytes.to_vec())
776 }
777}
778
779impl PersistedScalar for Blob {
780 const CODEC: ScalarCodec = ScalarCodec::Blob;
781
782 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
783 Ok(self.to_vec())
784 }
785
786 fn decode_scalar_payload(
787 bytes: &[u8],
788 _field_name: &'static str,
789 ) -> Result<Self, InternalError> {
790 Ok(Self::from(bytes))
791 }
792}
793
794impl PersistedScalar for Ulid {
795 const CODEC: ScalarCodec = ScalarCodec::Ulid;
796
797 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
798 Ok(self.to_bytes().to_vec())
799 }
800
801 fn decode_scalar_payload(
802 bytes: &[u8],
803 field_name: &'static str,
804 ) -> Result<Self, InternalError> {
805 Self::try_from_bytes(bytes)
806 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))
807 }
808}
809
810impl PersistedScalar for Timestamp {
811 const CODEC: ScalarCodec = ScalarCodec::Timestamp;
812
813 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
814 Ok(self.as_millis().to_le_bytes().to_vec())
815 }
816
817 fn decode_scalar_payload(
818 bytes: &[u8],
819 field_name: &'static str,
820 ) -> Result<Self, InternalError> {
821 let raw: [u8; SCALAR_WORD64_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
822 InternalError::persisted_row_field_payload_exact_len_required(
823 field_name,
824 "timestamp",
825 SCALAR_WORD64_PAYLOAD_LEN,
826 )
827 })?;
828
829 Ok(Self::from_millis(i64::from_le_bytes(raw)))
830 }
831}
832
833impl PersistedScalar for Date {
834 const CODEC: ScalarCodec = ScalarCodec::Date;
835
836 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
837 Ok(self.as_days_since_epoch().to_le_bytes().to_vec())
838 }
839
840 fn decode_scalar_payload(
841 bytes: &[u8],
842 field_name: &'static str,
843 ) -> Result<Self, InternalError> {
844 let raw: [u8; SCALAR_WORD32_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
845 InternalError::persisted_row_field_payload_exact_len_required(
846 field_name,
847 "date",
848 SCALAR_WORD32_PAYLOAD_LEN,
849 )
850 })?;
851
852 Ok(Self::from_days_since_epoch(i32::from_le_bytes(raw)))
853 }
854}
855
856impl PersistedScalar for Duration {
857 const CODEC: ScalarCodec = ScalarCodec::Duration;
858
859 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
860 Ok(self.as_millis().to_le_bytes().to_vec())
861 }
862
863 fn decode_scalar_payload(
864 bytes: &[u8],
865 field_name: &'static str,
866 ) -> Result<Self, InternalError> {
867 let raw: [u8; SCALAR_WORD64_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
868 InternalError::persisted_row_field_payload_exact_len_required(
869 field_name,
870 "duration",
871 SCALAR_WORD64_PAYLOAD_LEN,
872 )
873 })?;
874
875 Ok(Self::from_millis(u64::from_le_bytes(raw)))
876 }
877}
878
879impl PersistedScalar for Float32 {
880 const CODEC: ScalarCodec = ScalarCodec::Float32;
881
882 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
883 Ok(self.get().to_bits().to_le_bytes().to_vec())
884 }
885
886 fn decode_scalar_payload(
887 bytes: &[u8],
888 field_name: &'static str,
889 ) -> Result<Self, InternalError> {
890 let raw: [u8; SCALAR_WORD32_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
891 InternalError::persisted_row_field_payload_exact_len_required(
892 field_name,
893 "float32",
894 SCALAR_WORD32_PAYLOAD_LEN,
895 )
896 })?;
897 let value = f32::from_bits(u32::from_le_bytes(raw));
898
899 Self::try_new(value).ok_or_else(|| {
900 InternalError::persisted_row_field_payload_non_finite(field_name, "float32")
901 })
902 }
903}
904
905impl PersistedScalar for Float64 {
906 const CODEC: ScalarCodec = ScalarCodec::Float64;
907
908 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
909 Ok(self.get().to_bits().to_le_bytes().to_vec())
910 }
911
912 fn decode_scalar_payload(
913 bytes: &[u8],
914 field_name: &'static str,
915 ) -> Result<Self, InternalError> {
916 let raw: [u8; SCALAR_WORD64_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
917 InternalError::persisted_row_field_payload_exact_len_required(
918 field_name,
919 "float64",
920 SCALAR_WORD64_PAYLOAD_LEN,
921 )
922 })?;
923 let value = f64::from_bits(u64::from_le_bytes(raw));
924
925 Self::try_new(value).ok_or_else(|| {
926 InternalError::persisted_row_field_payload_non_finite(field_name, "float64")
927 })
928 }
929}
930
931impl PersistedScalar for Principal {
932 const CODEC: ScalarCodec = ScalarCodec::Principal;
933
934 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
935 self.to_bytes()
936 .map_err(|err| InternalError::persisted_row_field_encode_failed("principal", err))
937 }
938
939 fn decode_scalar_payload(
940 bytes: &[u8],
941 field_name: &'static str,
942 ) -> Result<Self, InternalError> {
943 Self::try_from_bytes(bytes)
944 .map_err(|err| InternalError::persisted_row_field_decode_failed(field_name, err))
945 }
946}
947
948impl PersistedScalar for Subaccount {
949 const CODEC: ScalarCodec = ScalarCodec::Subaccount;
950
951 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
952 Ok(self.to_bytes().to_vec())
953 }
954
955 fn decode_scalar_payload(
956 bytes: &[u8],
957 field_name: &'static str,
958 ) -> Result<Self, InternalError> {
959 let raw: [u8; SCALAR_SUBACCOUNT_PAYLOAD_LEN] = bytes.try_into().map_err(|_| {
960 InternalError::persisted_row_field_payload_exact_len_required(
961 field_name,
962 "subaccount",
963 SCALAR_SUBACCOUNT_PAYLOAD_LEN,
964 )
965 })?;
966
967 Ok(Self::from_array(raw))
968 }
969}
970
971impl PersistedScalar for () {
972 const CODEC: ScalarCodec = ScalarCodec::Unit;
973
974 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
975 Ok(Vec::new())
976 }
977
978 fn decode_scalar_payload(
979 bytes: &[u8],
980 field_name: &'static str,
981 ) -> Result<Self, InternalError> {
982 if !bytes.is_empty() {
983 return Err(InternalError::persisted_row_field_payload_must_be_empty(
984 field_name, "unit",
985 ));
986 }
987
988 Ok(())
989 }
990}
991
992impl PersistedScalar for Unit {
993 const CODEC: ScalarCodec = ScalarCodec::Unit;
994
995 fn encode_scalar_payload(&self) -> Result<Vec<u8>, InternalError> {
996 Ok(Vec::new())
997 }
998
999 fn decode_scalar_payload(
1000 bytes: &[u8],
1001 field_name: &'static str,
1002 ) -> Result<Self, InternalError> {
1003 if !bytes.is_empty() {
1004 return Err(InternalError::persisted_row_field_payload_must_be_empty(
1005 field_name, "unit",
1006 ));
1007 }
1008
1009 Ok(Self)
1010 }
1011}