1use serde::{Deserialize, Serialize};
5use smallvec::SmallVec;
6use std::fmt;
7
8pub type RecordKind = u8;
12pub type SysId = u64;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct RecordKey {
18 pub kind: RecordKind,
20 pub sys_id: SysId,
22}
23pub type TxSeq = u64;
25pub type PkBytes = SmallVec<[u8; 64]>;
27pub type PkEncodeFn = fn(&[u8]) -> PkBytes;
29
30pub const RECORD_HEADER_SIZE: usize = 16;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum FieldType {
40 Bool,
42 U8,
44 U16,
46 U32,
48 U64,
50 I32,
52 I64,
54 U128,
56 FixedBytes,
58 VarBytes,
60 EnumU8,
62}
63
64#[repr(C)]
66#[derive(
67 Debug, Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize,
68)]
69pub struct Version {
70 main: u8,
71 minor: u8,
72}
73
74const _: () = assert!(std::mem::size_of::<Version>() == 2);
75
76impl Version {
77 #[inline(always)]
79 pub const fn new(main: u8, minor: u8) -> Self {
80 Self { main, minor }
81 }
82
83 #[inline(always)]
85 pub const fn main(self) -> u8 {
86 self.main
87 }
88
89 #[inline(always)]
91 pub const fn minor(self) -> u8 {
92 self.minor
93 }
94
95 #[inline(always)]
97 pub const fn to_bytes(self) -> [u8; 2] {
98 [self.main, self.minor]
99 }
100
101 #[inline(always)]
103 pub const fn from_bytes(bytes: [u8; 2]) -> Self {
104 Self::new(bytes[0], bytes[1])
105 }
106}
107
108impl From<u16> for Version {
109 #[inline(always)]
110 fn from(value: u16) -> Self {
111 Self::from_bytes(value.to_le_bytes())
112 }
113}
114
115impl From<Version> for u16 {
116 #[inline(always)]
117 fn from(value: Version) -> Self {
118 u16::from_le_bytes(value.to_bytes())
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124pub struct FieldDefinition {
125 pub name: &'static str,
127 pub field_index: u32,
129 pub offset: u32,
131 pub ty: FieldType,
133 pub len: u32,
135 pub rust_type_name: &'static str,
137 pub enum_type_name: Option<&'static str>,
139 pub immutable: bool,
141}
142
143#[derive(Debug, Clone, Copy)]
145pub struct RecordDefinition {
146 pub kind: RecordKind,
148 pub name: &'static str,
150 pub is_pk_idx: bool,
152 pub support_range_scan: bool,
154 pub data_size: u32,
156 pub version: u16,
158 pub pk_encode: Option<PkEncodeFn>,
160 pub fields: &'static [FieldDefinition],
162 pub reserved_fields: &'static [FieldDefinition],
164 pub pk_fields: &'static [&'static str],
166}
167
168impl RecordDefinition {
169 #[inline]
171 pub fn field_by_name(&self, name: &str) -> Option<&FieldDefinition> {
172 self.fields.iter().find(|f| f.name == name)
173 }
174}
175
176pub trait RecordSchema {
178 const KIND: RecordKind;
180 const RECORD_LEN: usize;
182 const FIELD_COUNT: usize;
184
185 fn definition() -> &'static RecordDefinition;
187}
188
189pub trait PkCodec {
191 fn encode_pk_from_bytes(data: &[u8]) -> PkBytes;
193}
194
195pub trait GeneratedRecordAccess: RecordSchema {
197 const DATA_LEN: usize;
199 type Access<'a>;
201 type NewBuilder<'a>;
203 type UpdateBuilder<'a>;
205 fn wrap<'a>(buf: &'a [u8]) -> Self::Access<'a>;
207 fn wrap_new<'a>(buf: &'a mut [u8]) -> Self::NewBuilder<'a>;
209 fn wrap_update<'a>(buf: &'a mut [u8]) -> Self::UpdateBuilder<'a>;
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub struct EnumDecodeError {
216 pub type_name: &'static str,
218 pub raw: u8,
220}
221
222impl fmt::Display for EnumDecodeError {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 write!(f, "invalid {} discriminant: {}", self.type_name, self.raw)
225 }
226}
227
228impl std::error::Error for EnumDecodeError {}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232pub struct AccessError {
233 pub required: usize,
235 pub actual: usize,
237}
238
239impl fmt::Display for AccessError {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 write!(
242 f,
243 "buffer too small: required {} bytes, got {}",
244 self.required, self.actual
245 )
246 }
247}
248
249impl std::error::Error for AccessError {}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub struct EnumVariantDefinition {
254 pub name: &'static str,
256 pub discriminant: u8,
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq)]
262pub struct EnumDefinition {
263 pub name: &'static str,
265 pub variants: &'static [EnumVariantDefinition],
267}
268
269pub trait EnumU8: Copy + Eq + 'static {
271 fn to_u8(self) -> u8;
273 fn try_from_u8(v: u8) -> Result<Self, EnumDecodeError>;
275 fn type_name() -> &'static str;
277 fn definition() -> &'static EnumDefinition;
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283pub struct FixedBytes<const N: usize> {
284 len: u16,
285 buf: [u8; N],
286}
287
288impl<const N: usize> FixedBytes<N> {
289 pub fn new(bytes: &[u8]) -> Result<Self, AccessError> {
291 if bytes.len() > N {
292 return Err(AccessError {
293 required: N,
294 actual: bytes.len(),
295 });
296 }
297 let mut buf = [0u8; N];
298 buf[..bytes.len()].copy_from_slice(bytes);
299 Ok(Self {
300 len: bytes.len() as u16,
301 buf,
302 })
303 }
304
305 #[inline(always)]
307 pub fn len(&self) -> usize {
308 self.len as usize
309 }
310
311 #[inline(always)]
313 pub fn is_empty(&self) -> bool {
314 self.len == 0
315 }
316
317 #[inline(always)]
319 pub fn as_slice(&self) -> &[u8] {
320 &self.buf[..self.len()]
321 }
322
323 #[inline(always)]
325 pub fn padded_slice(&self) -> &[u8; N] {
326 &self.buf
327 }
328
329 #[inline]
331 pub fn pk_bytes(&self) -> PkBytes {
332 let mut pk = PkBytes::new();
333 pk.extend_from_slice(&self.buf);
334 pk
335 }
336}
337
338impl<const N: usize, const M: usize> From<&[u8; M]> for FixedBytes<N> {
339 #[inline]
340 fn from(bytes: &[u8; M]) -> Self {
341 const { assert!(M <= N, "FixedBytes: source length exceeds capacity") };
342 let mut buf = [0u8; N];
343 buf[..M].copy_from_slice(bytes);
344 Self { len: M as u16, buf }
345 }
346}
347
348pub struct PkBuilder {
350 buf: PkBytes,
351}
352
353impl PkBuilder {
354 #[inline]
356 pub fn new() -> Self {
357 Self {
358 buf: SmallVec::new(),
359 }
360 }
361
362 #[inline]
364 pub fn push_u8(&mut self, v: u8) {
365 self.buf.push(v);
366 }
367
368 #[inline]
370 pub fn push_u16(&mut self, v: u16) {
371 self.buf.extend_from_slice(&v.to_be_bytes());
372 }
373
374 #[inline]
376 pub fn push_u32(&mut self, v: u32) {
377 self.buf.extend_from_slice(&v.to_be_bytes());
378 }
379
380 #[inline]
382 pub fn push_u64(&mut self, v: u64) {
383 self.buf.extend_from_slice(&v.to_be_bytes());
384 }
385
386 #[inline]
388 pub fn push_i32(&mut self, v: i32) {
389 let encoded = ((v as u32) ^ 0x8000_0000).to_be_bytes();
390 self.buf.extend_from_slice(&encoded);
391 }
392
393 #[inline]
395 pub fn push_i64(&mut self, v: i64) {
396 let encoded = ((v as u64) ^ 0x8000_0000_0000_0000).to_be_bytes();
397 self.buf.extend_from_slice(&encoded);
398 }
399
400 #[inline]
402 pub fn push_bytes(&mut self, bytes: &[u8]) {
403 self.buf.extend_from_slice(bytes);
404 }
405
406 #[inline]
408 pub fn finish(self) -> PkBytes {
409 self.buf
410 }
411}
412
413impl Default for PkBuilder {
414 fn default() -> Self {
415 Self::new()
416 }
417}
418
419#[inline(always)]
421fn check_len(buf: &[u8], need: usize) -> Result<(), AccessError> {
422 if buf.len() >= need {
423 Ok(())
424 } else {
425 Err(AccessError {
426 required: need,
427 actual: buf.len(),
428 })
429 }
430}
431
432#[inline(always)]
433fn checked_need(offset: usize, len: usize, actual: usize) -> Result<usize, AccessError> {
434 offset.checked_add(len).ok_or(AccessError {
435 required: usize::MAX,
436 actual,
437 })
438}
439
440#[inline(always)]
443fn assert_len(buf: &[u8], need: usize) {
444 assert!(
445 buf.len() >= need,
446 "write buffer too small: {} < {}",
447 buf.len(),
448 need
449 );
450}
451
452#[inline(always)]
453pub fn read_u8(buf: &[u8], offset: usize) -> Result<u8, AccessError> {
455 check_len(buf, checked_need(offset, 1, buf.len())?)?;
456 Ok(buf[offset])
457}
458
459#[inline(always)]
460pub fn write_u8(buf: &mut [u8], offset: usize, v: u8) {
462 assert_len(buf, offset + 1);
463 buf[offset] = v;
464}
465
466#[inline(always)]
467pub fn read_bool(buf: &[u8], offset: usize) -> Result<bool, AccessError> {
469 Ok(read_u8(buf, offset)? != 0)
470}
471
472#[inline(always)]
473pub fn write_bool(buf: &mut [u8], offset: usize, v: bool) {
475 write_u8(buf, offset, if v { 1 } else { 0 });
476}
477
478#[inline(always)]
479pub fn read_u16_le(buf: &[u8], offset: usize) -> Result<u16, AccessError> {
481 let end = checked_need(offset, 2, buf.len())?;
482 check_len(buf, end)?;
483 let mut tmp = [0u8; 2];
484 tmp.copy_from_slice(&buf[offset..end]);
485 Ok(u16::from_le_bytes(tmp))
486}
487
488#[inline(always)]
489pub fn write_u16_le(buf: &mut [u8], offset: usize, v: u16) {
491 assert_len(buf, offset + 2);
492 buf[offset..offset + 2].copy_from_slice(&v.to_le_bytes());
493}
494
495#[inline(always)]
496pub fn read_u32_le(buf: &[u8], offset: usize) -> Result<u32, AccessError> {
498 let end = checked_need(offset, 4, buf.len())?;
499 check_len(buf, end)?;
500 let mut tmp = [0u8; 4];
501 tmp.copy_from_slice(&buf[offset..end]);
502 Ok(u32::from_le_bytes(tmp))
503}
504
505#[inline(always)]
506pub fn write_u32_le(buf: &mut [u8], offset: usize, v: u32) {
508 assert_len(buf, offset + 4);
509 buf[offset..offset + 4].copy_from_slice(&v.to_le_bytes());
510}
511
512#[inline(always)]
513pub fn read_u64_le(buf: &[u8], offset: usize) -> Result<u64, AccessError> {
515 let end = checked_need(offset, 8, buf.len())?;
516 check_len(buf, end)?;
517 let mut tmp = [0u8; 8];
518 tmp.copy_from_slice(&buf[offset..end]);
519 Ok(u64::from_le_bytes(tmp))
520}
521
522#[inline(always)]
523pub fn write_u64_le(buf: &mut [u8], offset: usize, v: u64) {
525 assert_len(buf, offset + 8);
526 buf[offset..offset + 8].copy_from_slice(&v.to_le_bytes());
527}
528
529#[inline(always)]
530pub fn read_i32_le(buf: &[u8], offset: usize) -> Result<i32, AccessError> {
532 Ok(read_u32_le(buf, offset)? as i32)
533}
534
535#[inline(always)]
536pub fn write_i32_le(buf: &mut [u8], offset: usize, v: i32) {
538 write_u32_le(buf, offset, v as u32);
539}
540
541#[inline(always)]
542pub fn read_i64_le(buf: &[u8], offset: usize) -> Result<i64, AccessError> {
544 Ok(read_u64_le(buf, offset)? as i64)
545}
546
547#[inline(always)]
548pub fn write_i64_le(buf: &mut [u8], offset: usize, v: i64) {
550 write_u64_le(buf, offset, v as u64);
551}
552
553#[inline(always)]
554pub fn read_u128_le(buf: &[u8], offset: usize) -> Result<u128, AccessError> {
556 let end = checked_need(offset, 16, buf.len())?;
557 check_len(buf, end)?;
558 let mut tmp = [0u8; 16];
559 tmp.copy_from_slice(&buf[offset..end]);
560 Ok(u128::from_le_bytes(tmp))
561}
562
563#[inline(always)]
564pub fn write_u128_le(buf: &mut [u8], offset: usize, v: u128) {
566 assert_len(buf, offset + 16);
567 buf[offset..offset + 16].copy_from_slice(&v.to_le_bytes());
568}
569
570#[inline(always)]
571pub fn read_fixed_bytes<const N: usize>(
573 buf: &[u8],
574 offset: usize,
575) -> Result<FixedBytes<N>, AccessError> {
576 let start = checked_need(offset, 2, buf.len())?;
577 let end = checked_need(start, N, buf.len())?;
578 check_len(buf, end)?;
579 let len = read_u16_le(buf, offset)? as usize;
580 if len > N {
581 return Err(AccessError {
582 required: len,
583 actual: N,
584 });
585 }
586 let mut tmp = [0u8; N];
587 tmp.copy_from_slice(&buf[start..end]);
588 Ok(FixedBytes {
589 len: len as u16,
590 buf: tmp,
591 })
592}
593
594#[inline(always)]
600pub fn write_fixed_bytes<const N: usize>(buf: &mut [u8], offset: usize, v: &FixedBytes<N>) {
601 assert_len(buf, offset + 2 + N);
602 write_u16_le(buf, offset, v.len);
603 buf[offset + 2..offset + 2 + N].fill(0);
604 buf[offset + 2..offset + 2 + v.len()].copy_from_slice(v.as_slice());
605}
606
607#[derive(Debug, Clone, PartialEq, Eq)]
611pub struct Command {
612 command_kind: u8,
613 ext_seq: u64,
614 ref_ext_time_us: u64,
615 payload: Vec<u8>,
616}
617
618impl Command {
619 #[inline]
621 pub fn new(command_kind: u8, ext_seq: u64, ref_ext_time_us: u64, payload: Vec<u8>) -> Self {
622 Self {
623 command_kind,
624 ext_seq,
625 ref_ext_time_us,
626 payload,
627 }
628 }
629
630 #[inline(always)]
632 pub fn command_kind(&self) -> u8 {
633 self.command_kind
634 }
635
636 #[inline(always)]
638 pub fn ext_seq(&self) -> u64 {
639 self.ext_seq
640 }
641
642 #[inline(always)]
644 pub fn ingress_dedupe_key(&self) -> u64 {
645 self.ext_seq
646 }
647
648 #[inline(always)]
650 pub fn ref_ext_time_us(&self) -> u64 {
651 self.ref_ext_time_us
652 }
653
654 #[inline(always)]
656 pub fn payload_len(&self) -> usize {
657 self.payload.len()
658 }
659
660 #[inline(always)]
662 pub fn payload(&self) -> &[u8] {
663 &self.payload
664 }
665
666 #[inline(always)]
668 pub fn into_payload(self) -> Vec<u8> {
669 self.payload
670 }
671}
672
673#[inline(always)]
676pub fn read_var_bytes(data: &[u8], offset: usize) -> Result<(&[u8], usize), AccessError> {
678 let len = read_u16_le(data, offset)? as usize;
679 let end = checked_need(checked_need(offset, 2, data.len())?, len, data.len())?;
680 if end > data.len() {
681 return Err(AccessError {
682 required: end,
683 actual: data.len(),
684 });
685 }
686 Ok((&data[offset + 2..end], end))
687}
688
689#[inline]
690pub fn write_var_bytes(buf: &mut Vec<u8>, content: &[u8]) -> Result<(), AccessError> {
692 let len = u16::try_from(content.len()).map_err(|_| AccessError {
693 required: content.len(),
694 actual: u16::MAX as usize,
695 })?;
696 buf.extend_from_slice(&len.to_le_bytes());
697 buf.extend_from_slice(content);
698 Ok(())
699}
700
701#[derive(Debug, Clone, Copy)]
705pub struct PayloadFieldDefinition {
706 pub name: &'static str,
708 pub field_index: u32,
710 pub ty: FieldType,
712 pub rust_type_name: &'static str,
714 pub enum_type_name: Option<&'static str>,
716 pub fixed_size: Option<u32>,
718}
719
720#[derive(Debug, Clone, Copy)]
722pub struct CommandDefinition {
723 pub kind: u8,
725 pub name: &'static str,
727 pub version: u16,
729 pub fields: &'static [PayloadFieldDefinition],
731}
732
733pub trait CommandSchema {
735 const KIND: u8;
737 fn definition() -> &'static CommandDefinition;
739}
740
741pub trait GeneratedCommandAccess: CommandSchema {
743 type Access<'a>;
745 type Builder;
747 fn wrap(data: &[u8]) -> Self::Access<'_>;
749 fn builder() -> Self::Builder;
751}
752
753#[derive(Debug, Clone, PartialEq, Eq)]
757pub struct Event {
758 event_kind: u8,
759 event_seq: u32,
760 payload: Vec<u8>,
761}
762
763impl Event {
764 #[inline]
766 pub fn new(event_kind: u8, event_seq: u32, payload: Vec<u8>) -> Self {
767 Self {
768 event_kind,
769 event_seq,
770 payload,
771 }
772 }
773
774 #[inline(always)]
776 pub fn event_kind(&self) -> u8 {
777 self.event_kind
778 }
779
780 #[inline(always)]
782 pub fn event_seq(&self) -> u32 {
783 self.event_seq
784 }
785
786 #[inline(always)]
788 pub fn payload(&self) -> &[u8] {
789 &self.payload
790 }
791
792 #[inline(always)]
794 pub fn into_payload(self) -> Vec<u8> {
795 self.payload
796 }
797
798 #[inline]
800 pub fn into_frame(self, tx_seq: TxSeq) -> EventFrame {
801 EventFrame::new(tx_seq, self.event_seq, self.event_kind, self.payload)
802 }
803}
804
805#[derive(Debug, Clone, PartialEq, Eq)]
807pub struct EventFrame {
808 tx_seq: TxSeq,
809 event_seq: u32,
810 event_kind: u8,
811 payload: Vec<u8>,
812}
813
814impl EventFrame {
815 #[inline]
817 pub fn new(tx_seq: u64, event_seq: u32, event_kind: u8, payload: Vec<u8>) -> Self {
818 Self {
819 tx_seq,
820 event_seq,
821 event_kind,
822 payload,
823 }
824 }
825
826 #[inline(always)]
828 pub fn tx_seq(&self) -> TxSeq {
829 self.tx_seq
830 }
831
832 #[inline(always)]
834 pub fn event_seq(&self) -> u32 {
835 self.event_seq
836 }
837
838 #[inline(always)]
840 pub fn event_kind(&self) -> u8 {
841 self.event_kind
842 }
843
844 #[inline(always)]
846 pub fn frame_len(&self) -> usize {
847 24 + self.payload.len()
848 }
849
850 #[inline(always)]
852 pub fn payload(&self) -> &[u8] {
853 &self.payload
854 }
855
856 #[inline(always)]
858 pub fn into_payload(self) -> Vec<u8> {
859 self.payload
860 }
861
862 #[inline]
864 pub fn into_parts(self) -> (TxSeq, Event) {
865 (
866 self.tx_seq,
867 Event {
868 event_kind: self.event_kind,
869 event_seq: self.event_seq,
870 payload: self.payload,
871 },
872 )
873 }
874}
875
876#[derive(Debug, Clone, Copy)]
878pub struct EventDefinition {
879 pub kind: u8,
881 pub name: &'static str,
883 pub version: u16,
885 pub fields: &'static [PayloadFieldDefinition],
887}
888
889pub trait EventSchema {
891 const KIND: u8;
893 fn definition() -> &'static EventDefinition;
895}
896
897pub trait GeneratedEventAccess: EventSchema {
899 type Access<'a>;
901 type Builder;
903 fn wrap(data: &[u8]) -> Self::Access<'_>;
905 fn builder() -> Self::Builder;
907}