1use core::fmt;
32use core::str::FromStr;
33
34#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
36pub enum IdParseError {
37 #[error("invalid id length: expected 32 hex digits or UUID form, got {0} chars")]
39 InvalidLength(usize),
40 #[error("invalid hex character `{0}` in id")]
42 InvalidCharacter(char),
43}
44
45fn hex_encode(bytes: &[u8; 16]) -> String {
46 const HEX: &[u8; 16] = b"0123456789abcdef";
47 let mut out = String::with_capacity(32);
48 for b in bytes {
49 out.push(HEX[(b >> 4) as usize] as char);
50 out.push(HEX[(b & 0x0f) as usize] as char);
51 }
52 out
53}
54
55fn hex_decode(text: &str) -> Result<[u8; 16], IdParseError> {
56 let len = text.chars().count();
57 if len != 32 {
58 return Err(IdParseError::InvalidLength(len));
59 }
60 let mut out = [0u8; 16];
61 let mut chars = text.chars();
62 for byte in &mut out {
63 let hi = chars.next().expect("length checked above");
64 let lo = chars.next().expect("length checked above");
65 let hi = hi.to_digit(16).ok_or(IdParseError::InvalidCharacter(hi))?;
66 let lo = lo.to_digit(16).ok_or(IdParseError::InvalidCharacter(lo))?;
67 *byte = ((hi << 4) | lo) as u8;
68 }
69 Ok(out)
70}
71
72macro_rules! id128 {
73 ($(#[$meta:meta])* $name:ident) => {
74 $(#[$meta])*
75 #[doc = ""]
76 #[doc = "Random 128-bit identifier drawn from the operating-system CSPRNG by"]
77 #[doc = "[`new_random`](Self::new_random); never derived only from timestamps and"]
78 #[doc = "never reused within a database. The all-zero value is reserved."]
79 #[doc = ""]
80 #[doc = "Canonical text form: strict lowercase hexadecimal, 32 characters."]
81 #[doc = "Parsing is lenient and additionally accepts the hyphenated UUID form"]
82 #[doc = "(`8-4-4-4-12`) and uppercase hex digits."]
83 #[repr(transparent)]
84 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
85 pub struct $name(pub [u8; 16]);
86
87 impl $name {
88 pub const ZERO: Self = Self([0u8; 16]);
91
92 pub fn new_random() -> Self {
96 let mut bytes = [0u8; 16];
97 getrandom::getrandom(&mut bytes)
98 .expect("operating-system CSPRNG unavailable");
99 Self(bytes)
100 }
101
102 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
104 Self(bytes)
105 }
106
107 pub const fn as_bytes(&self) -> &[u8; 16] {
109 &self.0
110 }
111
112 pub fn to_hex(self) -> String {
114 hex_encode(&self.0)
115 }
116 }
117
118 impl serde::Serialize for $name {
119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 where
124 S: serde::Serializer,
125 {
126 if serializer.is_human_readable() {
127 serializer.serialize_str(&hex_encode(&self.0))
128 } else {
129 serializer.serialize_newtype_struct(stringify!($name), &self.0)
130 }
131 }
132 }
133
134 impl<'de> serde::Deserialize<'de> for $name {
135 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
139 where
140 D: serde::Deserializer<'de>,
141 {
142 struct HexVisitor;
143
144 impl serde::de::Visitor<'_> for HexVisitor {
145 type Value = $name;
146
147 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.write_str(concat!(
149 "a ",
150 stringify!($name),
151 " as 32 hex digits or hyphenated UUID form"
152 ))
153 }
154
155 fn visit_str<E>(self, text: &str) -> Result<Self::Value, E>
156 where
157 E: serde::de::Error,
158 {
159 text.parse().map_err(serde::de::Error::custom)
160 }
161 }
162
163 struct BytesVisitor;
164
165 impl<'de> serde::de::Visitor<'de> for BytesVisitor {
166 type Value = $name;
167
168 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 f.write_str(concat!("a ", stringify!($name), " as 16 raw bytes"))
170 }
171
172 fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
173 where
174 D: serde::Deserializer<'de>,
175 {
176 <[u8; 16] as serde::Deserialize>::deserialize(deserializer).map($name)
177 }
178
179 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
180 where
181 A: serde::de::SeqAccess<'de>,
182 {
183 let bytes: [u8; 16] = match seq.next_element()? {
184 Some(value) => value,
185 None => return Err(serde::de::Error::invalid_length(0, &self)),
186 };
187 Ok($name(bytes))
188 }
189 }
190
191 if deserializer.is_human_readable() {
192 deserializer.deserialize_str(HexVisitor)
193 } else {
194 deserializer.deserialize_newtype_struct(stringify!($name), BytesVisitor)
195 }
196 }
197 }
198
199 impl fmt::Display for $name {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.write_str(&hex_encode(&self.0))
202 }
203 }
204
205 impl fmt::Debug for $name {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 write!(f, concat!(stringify!($name), "({})"), hex_encode(&self.0))
208 }
209 }
210
211 impl FromStr for $name {
212 type Err = IdParseError;
213
214 fn from_str(text: &str) -> Result<Self, Self::Err> {
221 let compact: String = text.chars().filter(|c| *c != '-').collect();
222 hex_decode(&compact).map(Self)
223 }
224 }
225 };
226}
227
228id128!(
229 ClusterId
231);
232id128!(
233 NodeId
235);
236id128!(
237 DatabaseId
239);
240id128!(
241 TabletId
243);
244id128!(
245 RaftGroupId
247);
248id128!(
249 TransactionId
251);
252id128!(
253 QueryId
255);
256
257macro_rules! id64 {
258 ($(#[$meta:meta])* $name:ident) => {
259 $(#[$meta])*
260 #[doc = ""]
261 #[doc = "Numeric 64-bit identifier allocated through replicated catalog state;"]
262 #[doc = "never reused within a database. The zero value is reserved."]
263 #[repr(transparent)]
264 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
265 pub struct $name(pub u64);
266
267 impl $name {
268 pub const ZERO: Self = Self(0);
270
271 pub const fn new(value: u64) -> Self {
273 Self(value)
274 }
275
276 pub const fn get(self) -> u64 {
278 self.0
279 }
280 }
281
282 impl fmt::Display for $name {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 write!(f, "{}", self.0)
285 }
286 }
287
288 impl fmt::Debug for $name {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(f, concat!(stringify!($name), "({})"), self.0)
291 }
292 }
293
294 impl FromStr for $name {
295 type Err = core::num::ParseIntError;
296
297 fn from_str(text: &str) -> Result<Self, Self::Err> {
298 text.parse::<u64>().map(Self)
299 }
300 }
301 };
302}
303
304id64!(
305 TableId
307);
308id64!(
309 SchemaVersion
311);
312id64!(
313 MetadataVersion
315);
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320 use serde::{Deserialize, Serialize};
321 use std::collections::HashSet;
322
323 #[derive(Debug)]
332 struct HarnessError(String);
333
334 impl fmt::Display for HarnessError {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.write_str(&self.0)
337 }
338 }
339
340 impl std::error::Error for HarnessError {}
341
342 impl serde::ser::Error for HarnessError {
343 fn custom<T: fmt::Display>(msg: T) -> Self {
344 Self(msg.to_string())
345 }
346 }
347
348 impl serde::de::Error for HarnessError {
349 fn custom<T: fmt::Display>(msg: T) -> Self {
350 Self(msg.to_string())
351 }
352 }
353
354 struct StrSerializer;
357
358 impl serde::Serializer for StrSerializer {
359 type Ok = String;
360 type Error = HarnessError;
361 type SerializeSeq = serde::ser::Impossible<String, HarnessError>;
362 type SerializeTuple = serde::ser::Impossible<String, HarnessError>;
363 type SerializeTupleStruct = serde::ser::Impossible<String, HarnessError>;
364 type SerializeTupleVariant = serde::ser::Impossible<String, HarnessError>;
365 type SerializeMap = serde::ser::Impossible<String, HarnessError>;
366 type SerializeStruct = serde::ser::Impossible<String, HarnessError>;
367 type SerializeStructVariant = serde::ser::Impossible<String, HarnessError>;
368
369 fn is_human_readable(&self) -> bool {
370 true
371 }
372
373 fn serialize_str(self, v: &str) -> Result<String, HarnessError> {
374 Ok(v.to_owned())
375 }
376
377 fn serialize_bool(self, _v: bool) -> Result<String, HarnessError> {
378 Err(HarnessError("unsupported".into()))
379 }
380 fn serialize_i8(self, _v: i8) -> Result<String, HarnessError> {
381 Err(HarnessError("unsupported".into()))
382 }
383 fn serialize_i16(self, _v: i16) -> Result<String, HarnessError> {
384 Err(HarnessError("unsupported".into()))
385 }
386 fn serialize_i32(self, _v: i32) -> Result<String, HarnessError> {
387 Err(HarnessError("unsupported".into()))
388 }
389 fn serialize_i64(self, _v: i64) -> Result<String, HarnessError> {
390 Err(HarnessError("unsupported".into()))
391 }
392 fn serialize_u8(self, _v: u8) -> Result<String, HarnessError> {
393 Err(HarnessError("unsupported".into()))
394 }
395 fn serialize_u16(self, _v: u16) -> Result<String, HarnessError> {
396 Err(HarnessError("unsupported".into()))
397 }
398 fn serialize_u32(self, _v: u32) -> Result<String, HarnessError> {
399 Err(HarnessError("unsupported".into()))
400 }
401 fn serialize_u64(self, _v: u64) -> Result<String, HarnessError> {
402 Err(HarnessError("unsupported".into()))
403 }
404 fn serialize_f32(self, _v: f32) -> Result<String, HarnessError> {
405 Err(HarnessError("unsupported".into()))
406 }
407 fn serialize_f64(self, _v: f64) -> Result<String, HarnessError> {
408 Err(HarnessError("unsupported".into()))
409 }
410 fn serialize_char(self, _v: char) -> Result<String, HarnessError> {
411 Err(HarnessError("unsupported".into()))
412 }
413 fn serialize_bytes(self, _v: &[u8]) -> Result<String, HarnessError> {
414 Err(HarnessError("unsupported".into()))
415 }
416 fn serialize_none(self) -> Result<String, HarnessError> {
417 Err(HarnessError("unsupported".into()))
418 }
419 fn serialize_some<T: ?Sized + serde::Serialize>(
420 self,
421 _value: &T,
422 ) -> Result<String, HarnessError> {
423 Err(HarnessError("unsupported".into()))
424 }
425 fn serialize_unit(self) -> Result<String, HarnessError> {
426 Err(HarnessError("unsupported".into()))
427 }
428 fn serialize_unit_struct(self, _name: &'static str) -> Result<String, HarnessError> {
429 Err(HarnessError("unsupported".into()))
430 }
431 fn serialize_unit_variant(
432 self,
433 _name: &'static str,
434 _variant_index: u32,
435 _variant: &'static str,
436 ) -> Result<String, HarnessError> {
437 Err(HarnessError("unsupported".into()))
438 }
439 fn serialize_newtype_struct<T: ?Sized + serde::Serialize>(
440 self,
441 _name: &'static str,
442 _value: &T,
443 ) -> Result<String, HarnessError> {
444 Err(HarnessError("unsupported".into()))
445 }
446 fn serialize_newtype_variant<T: ?Sized + serde::Serialize>(
447 self,
448 _name: &'static str,
449 _variant_index: u32,
450 _variant: &'static str,
451 _value: &T,
452 ) -> Result<String, HarnessError> {
453 Err(HarnessError("unsupported".into()))
454 }
455 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, HarnessError> {
456 Err(HarnessError("unsupported".into()))
457 }
458 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, HarnessError> {
459 Err(HarnessError("unsupported".into()))
460 }
461 fn serialize_tuple_struct(
462 self,
463 _name: &'static str,
464 _len: usize,
465 ) -> Result<Self::SerializeTupleStruct, HarnessError> {
466 Err(HarnessError("unsupported".into()))
467 }
468 fn serialize_tuple_variant(
469 self,
470 _name: &'static str,
471 _variant_index: u32,
472 _variant: &'static str,
473 _len: usize,
474 ) -> Result<Self::SerializeTupleVariant, HarnessError> {
475 Err(HarnessError("unsupported".into()))
476 }
477 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, HarnessError> {
478 Err(HarnessError("unsupported".into()))
479 }
480 fn serialize_struct(
481 self,
482 _name: &'static str,
483 _len: usize,
484 ) -> Result<Self::SerializeStruct, HarnessError> {
485 Err(HarnessError("unsupported".into()))
486 }
487 fn serialize_struct_variant(
488 self,
489 _name: &'static str,
490 _variant_index: u32,
491 _variant: &'static str,
492 _len: usize,
493 ) -> Result<Self::SerializeStructVariant, HarnessError> {
494 Err(HarnessError("unsupported".into()))
495 }
496 }
497
498 struct BinSerializer;
501
502 struct ByteCollector {
503 buf: Vec<u8>,
504 }
505
506 impl ByteCollector {
507 fn push<T: ?Sized + serde::Serialize>(&mut self, value: &T) -> Result<(), HarnessError> {
508 let mut bytes = value.serialize(BinSerializer)?;
509 self.buf.append(&mut bytes);
510 Ok(())
511 }
512 }
513
514 impl serde::ser::SerializeSeq for ByteCollector {
515 type Ok = Vec<u8>;
516 type Error = HarnessError;
517
518 fn serialize_element<T: ?Sized + serde::Serialize>(
519 &mut self,
520 value: &T,
521 ) -> Result<(), HarnessError> {
522 self.push(value)
523 }
524
525 fn end(self) -> Result<Vec<u8>, HarnessError> {
526 Ok(self.buf)
527 }
528 }
529
530 impl serde::ser::SerializeTuple for ByteCollector {
531 type Ok = Vec<u8>;
532 type Error = HarnessError;
533
534 fn serialize_element<T: ?Sized + serde::Serialize>(
535 &mut self,
536 value: &T,
537 ) -> Result<(), HarnessError> {
538 self.push(value)
539 }
540
541 fn end(self) -> Result<Vec<u8>, HarnessError> {
542 Ok(self.buf)
543 }
544 }
545
546 impl serde::Serializer for BinSerializer {
547 type Ok = Vec<u8>;
548 type Error = HarnessError;
549 type SerializeSeq = ByteCollector;
550 type SerializeTuple = ByteCollector;
551 type SerializeTupleStruct = serde::ser::Impossible<Vec<u8>, HarnessError>;
552 type SerializeTupleVariant = serde::ser::Impossible<Vec<u8>, HarnessError>;
553 type SerializeMap = serde::ser::Impossible<Vec<u8>, HarnessError>;
554 type SerializeStruct = serde::ser::Impossible<Vec<u8>, HarnessError>;
555 type SerializeStructVariant = serde::ser::Impossible<Vec<u8>, HarnessError>;
556
557 fn is_human_readable(&self) -> bool {
558 false
559 }
560
561 fn serialize_u8(self, v: u8) -> Result<Vec<u8>, HarnessError> {
562 Ok(vec![v])
563 }
564
565 fn serialize_bytes(self, v: &[u8]) -> Result<Vec<u8>, HarnessError> {
566 Ok(v.to_vec())
567 }
568
569 fn serialize_newtype_struct<T: ?Sized + serde::Serialize>(
570 self,
571 _name: &'static str,
572 value: &T,
573 ) -> Result<Vec<u8>, HarnessError> {
574 value.serialize(self)
575 }
576
577 fn serialize_seq(self, len: Option<usize>) -> Result<ByteCollector, HarnessError> {
578 Ok(ByteCollector {
579 buf: Vec::with_capacity(len.unwrap_or(0)),
580 })
581 }
582
583 fn serialize_tuple(self, len: usize) -> Result<ByteCollector, HarnessError> {
584 Ok(ByteCollector {
585 buf: Vec::with_capacity(len),
586 })
587 }
588
589 fn serialize_bool(self, _v: bool) -> Result<Vec<u8>, HarnessError> {
590 Err(HarnessError("unsupported".into()))
591 }
592 fn serialize_i8(self, _v: i8) -> Result<Vec<u8>, HarnessError> {
593 Err(HarnessError("unsupported".into()))
594 }
595 fn serialize_i16(self, _v: i16) -> Result<Vec<u8>, HarnessError> {
596 Err(HarnessError("unsupported".into()))
597 }
598 fn serialize_i32(self, _v: i32) -> Result<Vec<u8>, HarnessError> {
599 Err(HarnessError("unsupported".into()))
600 }
601 fn serialize_i64(self, _v: i64) -> Result<Vec<u8>, HarnessError> {
602 Err(HarnessError("unsupported".into()))
603 }
604 fn serialize_u16(self, _v: u16) -> Result<Vec<u8>, HarnessError> {
605 Err(HarnessError("unsupported".into()))
606 }
607 fn serialize_u32(self, _v: u32) -> Result<Vec<u8>, HarnessError> {
608 Err(HarnessError("unsupported".into()))
609 }
610 fn serialize_u64(self, _v: u64) -> Result<Vec<u8>, HarnessError> {
611 Err(HarnessError("unsupported".into()))
612 }
613 fn serialize_f32(self, _v: f32) -> Result<Vec<u8>, HarnessError> {
614 Err(HarnessError("unsupported".into()))
615 }
616 fn serialize_f64(self, _v: f64) -> Result<Vec<u8>, HarnessError> {
617 Err(HarnessError("unsupported".into()))
618 }
619 fn serialize_char(self, _v: char) -> Result<Vec<u8>, HarnessError> {
620 Err(HarnessError("unsupported".into()))
621 }
622 fn serialize_str(self, _v: &str) -> Result<Vec<u8>, HarnessError> {
623 Err(HarnessError("unsupported".into()))
624 }
625 fn serialize_none(self) -> Result<Vec<u8>, HarnessError> {
626 Err(HarnessError("unsupported".into()))
627 }
628 fn serialize_some<T: ?Sized + serde::Serialize>(
629 self,
630 _value: &T,
631 ) -> Result<Vec<u8>, HarnessError> {
632 Err(HarnessError("unsupported".into()))
633 }
634 fn serialize_unit(self) -> Result<Vec<u8>, HarnessError> {
635 Err(HarnessError("unsupported".into()))
636 }
637 fn serialize_unit_struct(self, _name: &'static str) -> Result<Vec<u8>, HarnessError> {
638 Err(HarnessError("unsupported".into()))
639 }
640 fn serialize_unit_variant(
641 self,
642 _name: &'static str,
643 _variant_index: u32,
644 _variant: &'static str,
645 ) -> Result<Vec<u8>, HarnessError> {
646 Err(HarnessError("unsupported".into()))
647 }
648 fn serialize_newtype_variant<T: ?Sized + serde::Serialize>(
649 self,
650 _name: &'static str,
651 _variant_index: u32,
652 _variant: &'static str,
653 _value: &T,
654 ) -> Result<Vec<u8>, HarnessError> {
655 Err(HarnessError("unsupported".into()))
656 }
657 fn serialize_tuple_struct(
658 self,
659 _name: &'static str,
660 _len: usize,
661 ) -> Result<Self::SerializeTupleStruct, HarnessError> {
662 Err(HarnessError("unsupported".into()))
663 }
664 fn serialize_tuple_variant(
665 self,
666 _name: &'static str,
667 _variant_index: u32,
668 _variant: &'static str,
669 _len: usize,
670 ) -> Result<Self::SerializeTupleVariant, HarnessError> {
671 Err(HarnessError("unsupported".into()))
672 }
673 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, HarnessError> {
674 Err(HarnessError("unsupported".into()))
675 }
676 fn serialize_struct(
677 self,
678 _name: &'static str,
679 _len: usize,
680 ) -> Result<Self::SerializeStruct, HarnessError> {
681 Err(HarnessError("unsupported".into()))
682 }
683 fn serialize_struct_variant(
684 self,
685 _name: &'static str,
686 _variant_index: u32,
687 _variant: &'static str,
688 _len: usize,
689 ) -> Result<Self::SerializeStructVariant, HarnessError> {
690 Err(HarnessError("unsupported".into()))
691 }
692 }
693
694 struct BinDeserializer<'de> {
698 input: &'de [u8],
699 }
700
701 impl<'de> BinDeserializer<'de> {
702 fn new(input: &'de [u8]) -> Self {
703 Self { input }
704 }
705 }
706
707 impl<'de> serde::Deserializer<'de> for &mut BinDeserializer<'de> {
708 type Error = HarnessError;
709
710 fn is_human_readable(&self) -> bool {
711 false
712 }
713
714 fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, HarnessError>
715 where
716 V: serde::de::Visitor<'de>,
717 {
718 Err(HarnessError("unsupported".into()))
719 }
720
721 fn deserialize_newtype_struct<V>(
722 self,
723 _name: &'static str,
724 visitor: V,
725 ) -> Result<V::Value, HarnessError>
726 where
727 V: serde::de::Visitor<'de>,
728 {
729 visitor.visit_newtype_struct(self)
730 }
731
732 fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, HarnessError>
733 where
734 V: serde::de::Visitor<'de>,
735 {
736 visitor.visit_seq(ByteSeq { de: self })
737 }
738
739 fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, HarnessError>
740 where
741 V: serde::de::Visitor<'de>,
742 {
743 visitor.visit_seq(ByteSeq { de: self })
744 }
745
746 fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, HarnessError>
747 where
748 V: serde::de::Visitor<'de>,
749 {
750 let (&byte, rest) = self
751 .input
752 .split_first()
753 .ok_or_else(|| HarnessError("unexpected end of input".into()))?;
754 self.input = rest;
755 visitor.visit_u8(byte)
756 }
757
758 serde::forward_to_deserialize_any! {
759 bool i8 i16 i32 i64 u16 u32 u64 f32 f64 char str string
760 bytes byte_buf option unit unit_struct
761 tuple_struct map struct enum identifier ignored_any
762 }
763 }
764
765 struct ByteSeq<'a, 'de> {
766 de: &'a mut BinDeserializer<'de>,
767 }
768
769 impl<'de> serde::de::SeqAccess<'de> for ByteSeq<'_, 'de> {
770 type Error = HarnessError;
771
772 fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, HarnessError>
773 where
774 T: serde::de::DeserializeSeed<'de>,
775 {
776 seed.deserialize(&mut *self.de).map(Some)
777 }
778 }
779
780 fn check_text_forms<T>(id: T)
781 where
782 T: Copy + PartialEq + fmt::Debug + fmt::Display + FromStr<Err = IdParseError>,
783 {
784 let text = id.to_string();
785 assert_eq!(text.len(), 32, "canonical form is 32 chars");
786 assert!(
787 text.chars()
788 .all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()),
789 "canonical form is strict lowercase hex: {text}"
790 );
791 assert_eq!(text.parse::<T>().unwrap(), id, "hex round-trip");
792
793 let uuid = format!(
794 "{}-{}-{}-{}-{}",
795 &text[0..8],
796 &text[8..12],
797 &text[12..16],
798 &text[16..20],
799 &text[20..32]
800 );
801 assert_eq!(
802 uuid.parse::<T>().unwrap(),
803 id,
804 "hyphenated UUID form parses"
805 );
806
807 let upper = text.to_ascii_uppercase();
808 assert_eq!(upper.parse::<T>().unwrap(), id, "uppercase hex parses");
809
810 let upper_uuid = uuid.to_ascii_uppercase();
811 assert_eq!(
812 upper_uuid.parse::<T>().unwrap(),
813 id,
814 "uppercase UUID form parses"
815 );
816 }
817
818 #[test]
819 fn text_forms_round_trip_all_types() {
820 check_text_forms(ClusterId::new_random());
821 check_text_forms(NodeId::new_random());
822 check_text_forms(DatabaseId::new_random());
823 check_text_forms(TabletId::new_random());
824 check_text_forms(RaftGroupId::new_random());
825 check_text_forms(TransactionId::new_random());
826 check_text_forms(QueryId::new_random());
827 }
828
829 #[test]
830 fn text_form_exact_known_value() {
831 let bytes = [
832 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76,
833 0x54, 0x32,
834 ];
835 let id = ClusterId::from_bytes(bytes);
836 let expected = "000123456789abcdeffedcba98765432";
837 assert_eq!(id.to_hex(), expected);
838 assert_eq!(id.to_string(), expected);
839 assert_eq!(format!("{id:?}"), format!("ClusterId({expected})"));
840 assert_eq!(expected.parse::<ClusterId>().unwrap(), id);
841 assert_eq!(ClusterId::from_bytes(bytes).as_bytes(), &bytes);
842 }
843
844 #[test]
845 fn parse_rejects_bad_input() {
846 assert_eq!(
847 "".parse::<ClusterId>(),
848 Err(IdParseError::InvalidLength(0)),
849 "empty input"
850 );
851 assert_eq!(
852 "abcd".parse::<ClusterId>(),
853 Err(IdParseError::InvalidLength(4)),
854 "too short"
855 );
856 assert_eq!(
857 "a".repeat(33).parse::<ClusterId>(),
858 Err(IdParseError::InvalidLength(33)),
859 "too long"
860 );
861 assert_eq!(
862 "--------------------------------".parse::<ClusterId>(),
863 Err(IdParseError::InvalidLength(0)),
864 "hyphens only"
865 );
866 assert_eq!(
867 "g".repeat(32).parse::<ClusterId>(),
868 Err(IdParseError::InvalidCharacter('g')),
869 "non-hex character"
870 );
871 assert_eq!(
872 format!("{}é", "a".repeat(31)).parse::<ClusterId>(),
873 Err(IdParseError::InvalidCharacter('é')),
874 "non-ASCII character"
875 );
876 }
877
878 fn check_human_readable_serde<T>(id: T)
879 where
880 T: Copy + PartialEq + fmt::Debug + fmt::Display + FromStr<Err = IdParseError>,
881 T: Serialize + for<'de> Deserialize<'de>,
882 {
883 let json_like = id.serialize(StrSerializer).unwrap();
884 assert_eq!(
885 json_like,
886 id.to_string(),
887 "human-readable form is the hex string"
888 );
889
890 let back: T = T::deserialize(serde::de::value::StrDeserializer::<HarnessError>::new(
891 &json_like,
892 ))
893 .unwrap();
894 assert_eq!(back, id, "human-readable string round-trip");
895
896 let upper: T = T::deserialize(serde::de::value::StrDeserializer::<HarnessError>::new(
897 &json_like.to_ascii_uppercase(),
898 ))
899 .unwrap();
900 assert_eq!(upper, id, "human-readable form accepts uppercase");
901
902 let invalid = T::deserialize(serde::de::value::StrDeserializer::<HarnessError>::new(
903 "not-an-id",
904 ));
905 assert!(
906 invalid.is_err(),
907 "human-readable form rejects invalid strings"
908 );
909 }
910
911 #[test]
912 fn human_readable_serde_round_trip_all_types() {
913 check_human_readable_serde(ClusterId::new_random());
914 check_human_readable_serde(NodeId::new_random());
915 check_human_readable_serde(DatabaseId::new_random());
916 check_human_readable_serde(TabletId::new_random());
917 check_human_readable_serde(RaftGroupId::new_random());
918 check_human_readable_serde(TransactionId::new_random());
919 check_human_readable_serde(QueryId::new_random());
920 }
921
922 fn check_binary_serde<T>(id: T, raw: &[u8; 16])
923 where
924 T: Copy + PartialEq + fmt::Debug + Serialize + for<'de> Deserialize<'de>,
925 {
926 let bytes = id.serialize(BinSerializer).unwrap();
927 assert_eq!(bytes.len(), 16, "binary form stays 16 bytes");
928 assert_eq!(
929 bytes.as_slice(),
930 raw.as_slice(),
931 "binary form is the raw bytes"
932 );
933
934 let mut de = BinDeserializer::new(&bytes);
935 let back = T::deserialize(&mut de).unwrap();
936 assert_eq!(back, id, "binary round-trip");
937 assert!(de.input.is_empty(), "binary form consumed exactly");
938 }
939
940 #[test]
941 fn binary_serde_stays_sixteen_bytes_all_types() {
942 macro_rules! check {
943 ($($name:ident),*) => {$(
944 let id = $name::new_random();
945 check_binary_serde(id, id.as_bytes());
946 )*};
947 }
948 check!(
949 ClusterId,
950 NodeId,
951 DatabaseId,
952 TabletId,
953 RaftGroupId,
954 TransactionId,
955 QueryId
956 );
957 }
958
959 #[test]
960 fn zero_constant_is_all_zero() {
961 assert_eq!(ClusterId::ZERO.as_bytes(), &[0u8; 16]);
962 assert_eq!(ClusterId::ZERO.to_hex(), "0".repeat(32));
963 assert_eq!(
964 "0".repeat(32).parse::<ClusterId>().unwrap(),
965 ClusterId::ZERO
966 );
967 assert_eq!(TableId::ZERO.get(), 0);
968 assert_eq!(SchemaVersion::ZERO.get(), 0);
969 assert_eq!(MetadataVersion::ZERO.get(), 0);
970 }
971
972 #[test]
973 fn ordering_follows_byte_order() {
974 let low = ClusterId::from_bytes([0x00; 16]);
975 let mut high_bytes = [0x00; 16];
976 high_bytes[15] = 0x01;
977 let high = ClusterId::from_bytes(high_bytes);
978 assert!(low < high);
979 assert!(ClusterId::ZERO <= low);
980
981 let mut ids = vec![high, ClusterId::ZERO, low];
982 ids.sort();
983 assert_eq!(ids, vec![ClusterId::ZERO, low, high]);
984
985 assert!(TableId::new(1) < TableId::new(2));
986 }
987
988 #[test]
989 fn new_random_is_distinct_and_nonzero() {
990 let mut seen = HashSet::with_capacity(1000);
991 for _ in 0..1000 {
992 let id = ClusterId::new_random();
993 assert_ne!(
994 id,
995 ClusterId::ZERO,
996 "random ID must not be the reserved zero value"
997 );
998 assert!(seen.insert(id), "random IDs must not repeat");
999 }
1000 }
1001
1002 #[test]
1003 fn id64_round_trips() {
1004 let id = TableId::new(42);
1005 assert_eq!(id.get(), 42);
1006 assert_eq!(id.to_string(), "42");
1007 assert_eq!("42".parse::<TableId>().unwrap(), id);
1008 assert!("not-a-number".parse::<TableId>().is_err());
1009 assert_eq!(format!("{id:?}"), "TableId(42)");
1010 }
1011}