Skip to main content

fcb_core/static_btree/
key.rs

1use crate::static_btree::error::{Error, Result};
2use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3use chrono::{DateTime, TimeZone, Utc};
4use ordered_float::OrderedFloat; // Import OrderedFloat
5use std::fmt::Debug;
6use std::io::{Read, Write};
7use std::mem;
8
9/// Enum to hold different key types supported by the system
10#[derive(Debug, Clone)]
11pub enum KeyType {
12    /// Fixed-size string keys (with different sizes as type parameters)
13    StringKey20(FixedStringKey<20>),
14    StringKey50(FixedStringKey<50>),
15    StringKey100(FixedStringKey<100>),
16    /// Integer keys
17    Int32(i32),
18    Int64(i64),
19    UInt32(u32),
20    UInt64(u64),
21    Int8(i8),
22    UInt8(u8),
23    Int16(i16),
24    UInt16(u16),
25    /// Floating point keys (wrapped in OrderedFloat for total ordering)
26    Float32(OrderedFloat<f32>),
27    Float64(OrderedFloat<f64>),
28    /// Boolean keys
29    Bool(bool),
30    /// DateTime keys
31    DateTime(DateTime<Utc>),
32}
33
34/// Trait for types that have a maximum representable value.
35///
36/// This trait allows retrieval of the maximum value for a type,
37/// which is useful for B-tree operations like range queries and bounds checking.
38pub trait Max {
39    /// Returns the maximum representable value for this type.
40    fn max_value() -> Self;
41}
42
43pub trait Min {
44    /// Returns the minimum representable value for this type.
45    fn min_value() -> Self;
46}
47
48/// Trait defining requirements for keys used in the StaticBTree.
49///
50/// Keys must support ordering (`Ord`), cloning (`Clone`), debugging (`Debug`),
51/// and have a fixed serialized size (`SERIALIZED_SIZE`). Variable-length types
52/// like `String` must be adapted (e.g., using fixed-size prefixes) to conform.
53pub trait Key: Sized + Ord + Clone + Debug + Default + Max + Min {
54    /// The exact size of the key in bytes when serialized.
55    /// This is crucial for calculating node sizes and offsets.
56    const SERIALIZED_SIZE: usize;
57
58    /// Serializes the key into the provided writer.
59    ///
60    /// # Arguments
61    /// * `writer`: The `Write` target.
62    ///
63    /// # Returns
64    /// Returns the number of bytes written, which is always SERIALIZED_SIZE
65    /// `Err(Error)` if writing fails.
66    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize>;
67
68    /// Deserializes a key from the provided reader.
69    ///
70    /// # Arguments
71    /// * `reader`: The `Read` source.
72    ///
73    /// # Returns
74    /// `Ok(Self)` containing the deserialized key on success.
75    /// `Err(Error)` if reading fails or the implementation cannot read exactly `SERIALIZED_SIZE` bytes.
76    fn read_from<R: Read>(reader: &mut R) -> Result<Self>;
77
78    /// Deserializes a key from the provided bytes.
79    ///
80    /// # Arguments
81    /// * `bytes`: The bytes to deserialize the key from.
82    ///
83    /// # Returns
84    /// `Ok(Self)` containing the deserialized key on success.
85    /// `Err(Error)` if the bytes are not a valid key.
86    fn from_bytes(bytes: &[u8]) -> Result<Self>;
87}
88
89// Implement Max for primitive integer types
90impl Max for i8 {
91    fn max_value() -> Self {
92        i8::MAX
93    }
94}
95
96impl Max for u8 {
97    fn max_value() -> Self {
98        u8::MAX
99    }
100}
101
102impl Max for u16 {
103    fn max_value() -> Self {
104        u16::MAX
105    }
106}
107
108impl Max for i16 {
109    fn max_value() -> Self {
110        i16::MAX
111    }
112}
113
114impl Max for i32 {
115    fn max_value() -> Self {
116        i32::MAX
117    }
118}
119
120impl Max for u32 {
121    fn max_value() -> Self {
122        u32::MAX
123    }
124}
125
126impl Max for i64 {
127    fn max_value() -> Self {
128        i64::MAX
129    }
130}
131
132impl Max for u64 {
133    fn max_value() -> Self {
134        u64::MAX
135    }
136}
137
138// Implement Max for OrderedFloat
139impl Max for OrderedFloat<f32> {
140    fn max_value() -> Self {
141        OrderedFloat(f32::INFINITY)
142    }
143}
144
145impl Max for OrderedFloat<f64> {
146    fn max_value() -> Self {
147        OrderedFloat(f64::INFINITY)
148    }
149}
150
151// Implement Max for bool
152impl Max for bool {
153    fn max_value() -> Self {
154        true
155    }
156}
157
158// Implement Max for DateTime<Utc>
159impl Max for DateTime<Utc> {
160    fn max_value() -> Self {
161        // A date far in the future (year 9999)
162        Utc.timestamp_opt(253402300799, 999_999_999)
163            .single()
164            .unwrap()
165    }
166}
167
168// Implement Max for FixedStringKey
169impl<const N: usize> Max for FixedStringKey<N> {
170    fn max_value() -> Self {
171        // For strings, a byte array filled with 0xFF represents the maximum lexicographical value
172        Self([0xFF; N])
173    }
174}
175
176// Implement Min for primitive integer types
177impl Min for i8 {
178    fn min_value() -> Self {
179        i8::MIN
180    }
181}
182
183impl Min for u8 {
184    fn min_value() -> Self {
185        u8::MIN
186    }
187}
188impl Min for i16 {
189    fn min_value() -> Self {
190        i16::MIN
191    }
192}
193
194impl Min for u16 {
195    fn min_value() -> Self {
196        u16::MIN
197    }
198}
199
200impl Min for i32 {
201    fn min_value() -> Self {
202        i32::MIN
203    }
204}
205
206impl Min for u32 {
207    fn min_value() -> Self {
208        u32::MIN
209    }
210}
211
212impl Min for i64 {
213    fn min_value() -> Self {
214        i64::MIN
215    }
216}
217
218impl Min for u64 {
219    fn min_value() -> Self {
220        u64::MIN
221    }
222}
223
224impl Min for OrderedFloat<f32> {
225    fn min_value() -> Self {
226        OrderedFloat(f32::NEG_INFINITY)
227    }
228}
229
230impl Min for OrderedFloat<f64> {
231    fn min_value() -> Self {
232        OrderedFloat(f64::NEG_INFINITY)
233    }
234}
235
236impl Min for bool {
237    fn min_value() -> Self {
238        false
239    }
240}
241
242impl Min for DateTime<Utc> {
243    fn min_value() -> Self {
244        Utc.timestamp_opt(0, 0).single().unwrap()
245    }
246}
247
248impl<const N: usize> Min for FixedStringKey<N> {
249    fn min_value() -> Self {
250        FixedStringKey([0u8; N])
251    }
252}
253
254// Macro to implement Key for primitive integer types easily
255macro_rules! impl_key_for_int {
256    ($T:ty, $write_method:ident) => {
257        impl Key for $T {
258            const SERIALIZED_SIZE: usize = mem::size_of::<$T>();
259
260            #[inline]
261            fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
262                writer.$write_method::<LittleEndian>(*self)?;
263                Ok(Self::SERIALIZED_SIZE)
264            }
265
266            #[inline]
267            fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
268                let mut bytes = [0u8; Self::SERIALIZED_SIZE];
269                reader.read_exact(&mut bytes)?;
270                Ok(<$T>::from_le_bytes(bytes))
271            }
272
273            #[inline]
274            fn from_bytes(bytes: &[u8]) -> Result<Self> {
275                let mut array = [0u8; Self::SERIALIZED_SIZE];
276                array.copy_from_slice(&bytes[0..Self::SERIALIZED_SIZE]);
277                Ok(<$T>::from_le_bytes(array))
278            }
279        }
280    };
281}
282
283// Macro for single-byte types that don't need endianness specifiers
284macro_rules! impl_key_for_byte {
285    ($T:ty, $write_method:ident) => {
286        impl Key for $T {
287            const SERIALIZED_SIZE: usize = mem::size_of::<$T>();
288
289            #[inline]
290            fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
291                writer.$write_method(*self)?;
292                Ok(Self::SERIALIZED_SIZE)
293            }
294
295            #[inline]
296            fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
297                let mut bytes = [0u8; Self::SERIALIZED_SIZE];
298                reader.read_exact(&mut bytes)?;
299                Ok(<$T>::from_le_bytes(bytes))
300            }
301
302            #[inline]
303            fn from_bytes(bytes: &[u8]) -> Result<Self> {
304                let mut array = [0u8; Self::SERIALIZED_SIZE];
305                array.copy_from_slice(&bytes[0..Self::SERIALIZED_SIZE]);
306                Ok(<$T>::from_le_bytes(array))
307            }
308        }
309    };
310}
311
312// Implement Key for standard integer types with the correct write method
313impl_key_for_byte!(u8, write_u8);
314impl_key_for_byte!(i8, write_i8);
315impl_key_for_int!(i16, write_i16);
316impl_key_for_int!(u16, write_u16);
317impl_key_for_int!(i32, write_i32);
318impl_key_for_int!(u32, write_u32);
319impl_key_for_int!(i64, write_i64);
320impl_key_for_int!(u64, write_u64);
321
322// Implement Key for OrderedFloat<f32>
323impl Key for OrderedFloat<f32> {
324    const SERIALIZED_SIZE: usize = mem::size_of::<f32>();
325
326    #[inline]
327    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
328        writer.write_f32::<LittleEndian>(self.into_inner())?;
329        Ok(Self::SERIALIZED_SIZE)
330    }
331
332    #[inline]
333    fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
334        let mut bytes = [0u8; Self::SERIALIZED_SIZE];
335        reader.read_exact(&mut bytes)?;
336        Ok(OrderedFloat::from(f32::from_le_bytes(bytes)))
337    }
338
339    #[inline]
340    fn from_bytes(bytes: &[u8]) -> Result<Self> {
341        let mut array = [0u8; Self::SERIALIZED_SIZE];
342        array.copy_from_slice(&bytes[0..Self::SERIALIZED_SIZE]);
343        Ok(OrderedFloat::from(f32::from_le_bytes(array)))
344    }
345}
346
347// Implement Key for OrderedFloat<f64>
348impl Key for OrderedFloat<f64> {
349    const SERIALIZED_SIZE: usize = mem::size_of::<f64>();
350
351    #[inline]
352    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
353        writer.write_f64::<LittleEndian>(self.into_inner())?;
354        Ok(Self::SERIALIZED_SIZE)
355    }
356
357    #[inline]
358    fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
359        let mut bytes = [0u8; Self::SERIALIZED_SIZE];
360        reader.read_exact(&mut bytes)?;
361        Ok(OrderedFloat::from(f64::from_le_bytes(bytes)))
362    }
363
364    #[inline]
365    fn from_bytes(bytes: &[u8]) -> Result<Self> {
366        let mut array = [0u8; Self::SERIALIZED_SIZE];
367        array.copy_from_slice(&bytes[0..Self::SERIALIZED_SIZE]);
368        Ok(OrderedFloat::from(f64::from_le_bytes(array)))
369    }
370}
371
372// Implement Key for bool
373impl Key for bool {
374    const SERIALIZED_SIZE: usize = 1;
375
376    #[inline]
377    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
378        writer.write_all(&[*self as u8]).map_err(Error::from)?;
379        Ok(Self::SERIALIZED_SIZE)
380    }
381
382    #[inline]
383    fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
384        let mut byte = [0u8];
385        reader.read_exact(&mut byte)?;
386        Ok(byte[0] != 0)
387    }
388
389    #[inline]
390    fn from_bytes(bytes: &[u8]) -> Result<Self> {
391        Ok(bytes[0] != 0)
392    }
393}
394
395// Implement Key for DateTime<Utc>
396impl Key for DateTime<Utc> {
397    const SERIALIZED_SIZE: usize = 12; // 8 bytes for seconds + 4 bytes for nanoseconds
398
399    #[inline]
400    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
401        // Write timestamp seconds (i64)
402        writer.write_i64::<LittleEndian>(self.timestamp())?;
403        // Write nanoseconds (u32)
404        writer.write_u32::<LittleEndian>(self.timestamp_subsec_nanos())?;
405        Ok(Self::SERIALIZED_SIZE)
406    }
407
408    #[inline]
409    fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
410        let secs = reader.read_i64::<LittleEndian>()?;
411        let nanos = reader.read_u32::<LittleEndian>()?;
412        let dt = DateTime::<Utc>::from_timestamp(secs, nanos).expect("invalid datetime value");
413        Ok(dt)
414    }
415
416    #[inline]
417    fn from_bytes(bytes: &[u8]) -> Result<Self> {
418        let mut array = [0u8; Self::SERIALIZED_SIZE];
419        array.copy_from_slice(&bytes[0..Self::SERIALIZED_SIZE]);
420        let secs = i64::from_le_bytes(array[0..8].try_into().unwrap());
421        let nanos = u32::from_le_bytes(array[8..12].try_into().unwrap());
422        let dt = DateTime::<Utc>::from_timestamp(secs, nanos).expect("invalid datetime value");
423        Ok(dt)
424    }
425}
426
427/// A fixed-size key based on a string, suitable for use in the StaticBTree.
428///
429/// It stores the string's bytes in a fixed-size array `[u8; N]`.
430/// If the input string is shorter than `N`, it's padded with null bytes (`\0`).
431/// If the input string is longer than `N`, it's truncated.
432/// Comparison (`Ord`) is based on the byte array content.
433#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
434pub struct FixedStringKey<const N: usize>([u8; N]);
435
436impl<const N: usize> Default for FixedStringKey<N> {
437    fn default() -> Self {
438        Self([0u8; N])
439    }
440}
441
442impl<const N: usize> Key for FixedStringKey<N> {
443    const SERIALIZED_SIZE: usize = N;
444
445    #[inline]
446    fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize> {
447        writer.write_all(&self.0).map_err(Error::from)?;
448        Ok(Self::SERIALIZED_SIZE)
449    }
450
451    #[inline]
452    fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
453        let mut bytes = [0u8; N];
454        reader.read_exact(&mut bytes)?;
455        Ok(FixedStringKey(bytes))
456    }
457
458    #[inline]
459    fn from_bytes(bytes: &[u8]) -> Result<Self> {
460        let mut array = [0u8; N];
461        array.copy_from_slice(&bytes[0..N]);
462        Ok(FixedStringKey(array))
463    }
464}
465
466impl<const N: usize> FixedStringKey<N> {
467    /// Creates a key from a string slice, padding with 0 bytes
468    /// or truncating if necessary to fit exactly N bytes.
469    ///
470    /// # Examples
471    /// ```
472    /// # use fcb_core::static_btree::key::FixedStringKey;
473    /// let key_short = FixedStringKey::<10>::from_str("hello");
474    /// assert_eq!(key_short.to_string_lossy(), "hello");
475    ///
476    /// let key_long = FixedStringKey::<3>::from_str("world");
477    /// assert_eq!(key_long.to_string_lossy(), "wor");
478    ///
479    /// let key_exact = FixedStringKey::<5>::from_str("exact");
480    /// assert_eq!(key_exact.to_string_lossy(), "exact");
481    /// ```
482    pub fn from_str(s: &str) -> Self {
483        let mut bytes = [0u8; N];
484        let source_bytes = s.as_bytes();
485        let len_to_copy = std::cmp::min(source_bytes.len(), N);
486        bytes[..len_to_copy].copy_from_slice(&source_bytes[..len_to_copy]);
487        // Remaining bytes are already 0 due to initialization.
488        FixedStringKey(bytes)
489    }
490
491    /// Attempts to convert back to a String, stopping at the first null byte
492    /// or using all N bytes if no null byte is found.
493    ///
494    /// Note: This conversion is lossy if the original string contained null bytes
495    /// before the Nth byte, or if it was truncated.
496    ///
497    /// # Examples
498    /// ```
499    /// # use fcb_core::static_btree::key::FixedStringKey;
500    /// let key1 = FixedStringKey::<10>::from_str("test");
501    /// assert_eq!(key1.to_string_lossy(), "test");
502    ///
503    /// let key2 = FixedStringKey::<5>::from_str("example"); // truncated to "examp"
504    /// assert_eq!(key2.to_string_lossy(), "examp");
505    ///
506    /// let s_with_null = "null\0xy"; // String containing null byte
507    /// let key3 = FixedStringKey::<8>::from_str(s_with_null);
508    /// assert_eq!(key3.to_string_lossy(), "null"); // Stops at null byte
509    /// ```
510    pub fn to_string_lossy(&self) -> String {
511        // Find the first null byte, or take the whole array if none exists.
512        let first_null = self.0.iter().position(|&b| b == 0).unwrap_or(N);
513        // Convert the slice up to the null byte (or end) into a String.
514        String::from_utf8_lossy(&self.0[..first_null]).into_owned()
515    }
516}
517
518#[cfg(test)]
519mod tests {
520    use chrono::Datelike;
521
522    use super::*;
523    use std::cmp::Ordering;
524    use std::f32;
525    use std::f64;
526    use std::io::Cursor;
527
528    fn test_key_impl<T: Key + Eq + Debug>(key_val: T) {
529        let mut buffer = Vec::new();
530        key_val.write_to(&mut buffer).expect("write should succeed");
531        assert_eq!(buffer.len(), T::SERIALIZED_SIZE);
532
533        let mut cursor = Cursor::new(buffer);
534        let deserialized_key = T::read_from(&mut cursor).expect("read should succeed");
535        assert_eq!(key_val, deserialized_key);
536
537        // Test short read error
538        if T::SERIALIZED_SIZE > 0 {
539            // Avoid panic for zero-sized types if any
540            let short_buffer = vec![0u8; T::SERIALIZED_SIZE - 1];
541            let mut short_cursor = Cursor::new(short_buffer);
542            let result = T::read_from(&mut short_cursor);
543            assert!(result.is_err());
544            match result.err().unwrap() {
545                Error::IoError(e) => assert_eq!(e.kind(), std::io::ErrorKind::UnexpectedEof),
546                _ => panic!("expected io error for short read"),
547            }
548        }
549    }
550
551    #[test]
552    fn test_max_values() {
553        // Test Max implementation for integers
554        assert_eq!(i32::max_value(), i32::MAX);
555        assert_eq!(u32::max_value(), u32::MAX);
556        assert_eq!(i64::max_value(), i64::MAX);
557        assert_eq!(u64::max_value(), u64::MAX);
558
559        // Test Max implementation for floats
560        assert_eq!(
561            OrderedFloat::<f32>::max_value(),
562            OrderedFloat(f32::INFINITY)
563        );
564        assert_eq!(
565            OrderedFloat::<f64>::max_value(),
566            OrderedFloat(f64::INFINITY)
567        );
568
569        // Test Max implementation for bool
570        assert!(bool::max_value());
571
572        // Test Max implementation for DateTime
573        let max_date = DateTime::<Utc>::max_value();
574        assert!(max_date.year() >= 9999); // Should be far in the future
575
576        // Test Max implementation for FixedStringKey
577        let max_str_key = FixedStringKey::<5>::max_value();
578        assert_eq!(max_str_key.0, [0xFF; 5]);
579
580        // Verify max values are actually maximum
581        assert!(5_i32 < i32::max_value());
582        assert!(OrderedFloat(1000.0f64) < OrderedFloat::<f64>::max_value());
583        assert!(bool::max_value());
584        assert!(Utc::now() < DateTime::<Utc>::max_value());
585        assert!(FixedStringKey::<5>::from_str("zzzzz") < FixedStringKey::<5>::max_value());
586    }
587
588    #[test]
589    fn test_int_keys() {
590        test_key_impl(12345i32);
591        test_key_impl(-54321i32);
592        test_key_impl(0i32);
593        test_key_impl(i32::MAX);
594        test_key_impl(i32::MIN);
595
596        test_key_impl(12345u32);
597        test_key_impl(0u32);
598        test_key_impl(u32::MAX);
599
600        test_key_impl(123456789012345i64);
601        test_key_impl(-98765432109876i64);
602        test_key_impl(0i64);
603        test_key_impl(i64::MAX);
604        test_key_impl(i64::MIN);
605
606        test_key_impl(123456789012345u64);
607        test_key_impl(0u64);
608        test_key_impl(u64::MAX);
609    }
610
611    #[test]
612    fn test_float_keys() {
613        test_key_impl(OrderedFloat(123.45f32));
614        test_key_impl(OrderedFloat(-987.65f32));
615        test_key_impl(OrderedFloat(0.0f32));
616        test_key_impl(OrderedFloat(f32::MAX));
617        test_key_impl(OrderedFloat(f32::MIN));
618        test_key_impl(OrderedFloat(f32::INFINITY));
619        test_key_impl(OrderedFloat(f32::NEG_INFINITY));
620        test_key_impl(OrderedFloat(f32::NAN)); // Test NaN serialization/deserialization
621
622        test_key_impl(OrderedFloat(123456.789012f64));
623        test_key_impl(OrderedFloat(-987654.321098f64));
624        test_key_impl(OrderedFloat(0.0f64));
625        test_key_impl(OrderedFloat(f64::MAX));
626        test_key_impl(OrderedFloat(f64::MIN));
627        test_key_impl(OrderedFloat(f64::INFINITY));
628        test_key_impl(OrderedFloat(f64::NEG_INFINITY));
629        test_key_impl(OrderedFloat(f64::NAN)); // Test NaN serialization/deserialization
630    }
631
632    #[test]
633    fn test_float_ordering() {
634        // Test normal ordering
635        assert!(OrderedFloat(1.0f32) < OrderedFloat(2.0f32));
636        assert!(OrderedFloat(-1.0f64) < OrderedFloat(1.0f64));
637
638        // Test infinity ordering
639        assert!(OrderedFloat(f32::MAX) < OrderedFloat(f32::INFINITY));
640        assert!(OrderedFloat(f64::NEG_INFINITY) < OrderedFloat(f64::MIN));
641
642        // Test NaN ordering (ordered-float puts NaN greater than all other numbers)
643        assert!(OrderedFloat(f32::INFINITY) < OrderedFloat(f32::NAN));
644        assert!(OrderedFloat(f64::MAX) < OrderedFloat(f64::NAN));
645        assert!(OrderedFloat(f32::NAN).cmp(&OrderedFloat(f32::NAN)) == Ordering::Equal);
646    }
647
648    #[test]
649    fn test_fixed_string_key_from_str() {
650        // Test shorter string (padding)
651        let key_short = FixedStringKey::<10>::from_str("hello");
652        assert_eq!(key_short.0[0..5], *b"hello");
653        assert_eq!(key_short.0[5..], [0u8; 5]);
654        assert_eq!(key_short.to_string_lossy(), "hello");
655
656        // Test longer string (truncation)
657        let key_long = FixedStringKey::<3>::from_str("world");
658        assert_eq!(key_long.0, *b"wor");
659        assert_eq!(key_long.to_string_lossy(), "wor");
660
661        // Test exact length string
662        let key_exact = FixedStringKey::<5>::from_str("exact");
663        assert_eq!(key_exact.0, *b"exact");
664        assert_eq!(key_exact.to_string_lossy(), "exact");
665
666        // Test empty string
667        let key_empty = FixedStringKey::<4>::from_str("");
668        assert_eq!(key_empty.0, [0u8; 4]);
669        assert_eq!(key_empty.to_string_lossy(), "");
670    }
671
672    #[test]
673    fn test_fixed_string_key_to_string_lossy() {
674        let key1 = FixedStringKey::<10>::from_str("test\0ing"); // Contains null byte
675        assert_eq!(key1.to_string_lossy(), "test"); // Stops at null
676
677        let key2 = FixedStringKey::<5>::from_str("abcde");
678        assert_eq!(key2.to_string_lossy(), "abcde"); // No null byte
679
680        let key3 = FixedStringKey::<3>::from_str("xyz123"); // Truncated
681        assert_eq!(key3.to_string_lossy(), "xyz");
682    }
683
684    #[test]
685    fn test_fixed_string_key_serialization() {
686        test_key_impl(FixedStringKey::<8>::from_str("testkey"));
687        test_key_impl(FixedStringKey::<4>::from_str("longkey")); // truncated
688        test_key_impl(FixedStringKey::<12>::from_str("short")); // padded
689        test_key_impl(FixedStringKey::<5>::from_str("")); // empty
690    }
691
692    #[test]
693    fn test_fixed_string_key_ordering() {
694        let key1 = FixedStringKey::<10>::from_str("apple");
695        let key2 = FixedStringKey::<10>::from_str("apply");
696        let key3 = FixedStringKey::<10>::from_str("banana");
697        let key4 = FixedStringKey::<10>::from_str("apple"); // Equal to key1
698        let key5 = FixedStringKey::<10>::from_str("app"); // Shorter, padded
699
700        assert!(key1 < key2);
701        assert!(key2 < key3);
702        assert!(key1 < key3);
703        assert_eq!(key1.cmp(&key4), Ordering::Equal);
704        assert!(key5 < key1); // "app\0..." < "apple..."
705    }
706
707    #[test]
708    fn test_bool_keys() {
709        test_key_impl(true);
710        test_key_impl(false);
711    }
712
713    #[test]
714    fn test_datetime_keys() {
715        // Test current time
716        // test_key_impl(Utc::now());
717
718        // // Test epoch
719        // test_key_impl(Utc.timestamp_opt(0, 0).single().unwrap());
720
721        // // Test future date
722        // test_key_impl(Utc.timestamp_opt(32503680000, 999999999).single().unwrap()); // Year 3000
723
724        // // Test past date
725        // test_key_impl(Utc.timestamp_opt(-62135596800, 0).single().unwrap()); // Year 0
726
727        // // Test ordering
728        // let dt1 = Utc.timestamp_opt(1000, 0).single().unwrap();
729        // let dt2 = Utc.timestamp_opt(2000, 0).single().unwrap();
730        // assert!(dt1 < dt2);
731
732        // // Test subsecond precision
733        // let dt3 = Utc.timestamp_opt(1000, 500).single().unwrap();
734        // let dt4 = Utc.timestamp_opt(1000, 1000).single().unwrap();
735        // assert!(dt3 < dt4);
736
737        // Test actual datetime 2010-10-13T12:43:04Z
738
739        let dt = chrono::DateTime::parse_from_rfc3339("2010-10-13T12:43:04Z")
740            .unwrap()
741            .to_utc();
742        test_key_impl(dt);
743    }
744}