Skip to main content

umadb_core/
events_tree_nodes.rs

1use crate::common::PageID;
2use crate::common::Position;
3use crate::page::PAGE_HEADER_SIZE;
4use crate::slice_reader::SliceReader;
5use bitflags::bitflags;
6use rustc_hash::FxHashSet;
7use std::io::{Cursor, Write};
8use umadb_dcb::DcbError;
9use umadb_dcb::DcbResult;
10use uuid::Uuid;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct EventRecord {
14    pub event_type: String,
15    pub data: Vec<u8>,
16    pub tags: Vec<String>,
17    pub uuid: Option<Uuid>,
18    pub metadata: Vec<(String, String)>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum EventValue {
23    Inline(EventRecord),
24    // For large record (data + metadata) stored across overflow pages
25    Overflow {
26        event_type: String,
27        data_len: u64,
28        tags: Vec<String>,
29        root_id: PageID,
30        uuid: Option<Uuid>,
31        metadata_len: u64,
32    },
33}
34
35/// Maximum number of metadata entries in a single event. Limited by the `u16`
36/// entry-count prefix used by the on-page encoding.
37pub const MAX_METADATA_ENTRIES: usize = u16::MAX as usize;
38
39/// Maximum length, in bytes, of a single metadata key or value. Limited by the
40/// `u16` length prefix used by the on-page encoding.
41pub const MAX_METADATA_ENTRY_LEN: usize = u16::MAX as usize;
42
43/// Maximum length, in bytes, of an event type string. Limited by the `u16`
44/// length prefix used by the on-page encoding.
45pub const MAX_EVENT_TYPE_LEN: usize = u16::MAX as usize;
46
47/// Maximum number of tags in a single event. Limited by the `u16` tag-count
48/// prefix used by the on-page encoding.
49pub const MAX_TAGS: usize = u16::MAX as usize;
50
51/// Maximum length, in bytes, of a single tag string. Limited by the `u16`
52/// length prefix used by the on-page encoding.
53pub const MAX_TAG_LEN: usize = u16::MAX as usize;
54
55pub fn validate_event_record_for_append(
56    page_size: usize,
57    record: EventRecord,
58) -> DcbResult<((EventValue, usize), Option<(EventValue, usize)>)> {
59    // validate_event_type(&record.event_type)?;
60    validate_tags(&record.tags)?;
61    validate_metadata(&record.metadata)?;
62
63    let mut node = EventLeafNode {
64        keys: vec![],
65        values: vec![],
66    };
67    let empty_size = node.calc_serialized_size();
68    node.keys.push(Position(0));
69    node.values.push(EventValue::Inline(record));
70    let inline_size = node.calc_serialized_size();
71    let inline_value = node.values.pop().expect("node has one value");
72
73    if inline_size + PAGE_HEADER_SIZE <= page_size {
74        return Ok(((inline_value, inline_size - empty_size), None));
75    }
76
77    let overflow_value = match &inline_value {
78        EventValue::Inline(record) => {
79            EventValue::Overflow {
80                event_type: record.event_type.clone(),
81                data_len: record.data.len() as u64,
82                tags: record.tags.clone(),
83                root_id: PageID(0),
84                uuid: record.uuid,
85                metadata_len: if record.metadata.is_empty() {
86                    0
87                } else {
88                    // Only non-zero matters for EventLeafNode::calc_serialized_size.
89                    1
90                },
91            }
92        }
93        EventValue::Overflow { .. } => {
94            return Err(DcbError::InternalError("Shouldn't get here".to_string()));
95        }
96    };
97
98    node.values.push(overflow_value);
99    let overflow_size = node.calc_serialized_size();
100    let overflow_value = node.values.pop().expect("node has one value");
101
102    if !(overflow_size + PAGE_HEADER_SIZE <= page_size) {
103        return Err(DcbError::InvalidArgument(
104            "event too large for page size".to_string(),
105        ));
106    }
107    Ok((
108        (inline_value, inline_size - empty_size),
109        Some((overflow_value, overflow_size - empty_size)),
110    ))
111}
112
113// Validate that the event type fits within the limits of the on-page
114// encoding.
115// pub fn validate_event_type(event_type: &str) -> DcbResult<()> {
116//     if event_type.len() > MAX_EVENT_TYPE_LEN {
117//         return Err(DcbError::InvalidArgument(format!(
118//             "event type has length {} bytes, exceeding the maximum of {}",
119//             event_type.len(),
120//             MAX_EVENT_TYPE_LEN
121//         )));
122//     }
123//     Ok(())
124// }
125
126/// Validate that the tags fit within the limits of the on-page encoding.
127pub fn validate_tags(tags: &[String]) -> DcbResult<()> {
128    if tags.len() > MAX_TAGS {
129        return Err(DcbError::InvalidArgument(format!(
130            "event has {} tags, exceeding the maximum of {}",
131            tags.len(),
132            MAX_TAGS
133        )));
134    }
135    // for tag in tags {
136    //     if tag.len() > MAX_TAG_LEN {
137    //         return Err(DcbError::InvalidArgument(format!(
138    //             "tag has length {} bytes, exceeding the maximum of {}",
139    //             tag.len(),
140    //             MAX_TAG_LEN
141    //         )));
142    //     }
143    // }
144    Ok(())
145}
146
147/// Validate that the metadata map fits within the limits of the on-page
148/// encoding (which uses `u16` length prefixes). Returns
149/// [`DcbError::InvalidArgument`] rather than letting an over-long key/value
150/// silently truncate its length prefix and corrupt the encoding.
151pub fn validate_metadata(metadata: &[(String, String)]) -> DcbResult<()> {
152    if metadata.len() > MAX_METADATA_ENTRIES {
153        return Err(DcbError::InvalidArgument(format!(
154            "metadata has {} entries, exceeding the maximum of {}",
155            metadata.len(),
156            MAX_METADATA_ENTRIES
157        )));
158    }
159    if has_duplicate_metadata_key(metadata) {
160        return Err(DcbError::InvalidArgument(
161            "metadata contains duplicate keys".to_string(),
162        ));
163    }
164    for (k, v) in metadata {
165        if k.len() > MAX_METADATA_ENTRY_LEN {
166            return Err(DcbError::InvalidArgument(format!(
167                "metadata key has length {} bytes, exceeding the maximum of {}",
168                k.len(),
169                MAX_METADATA_ENTRY_LEN
170            )));
171        }
172        if v.len() > MAX_METADATA_ENTRY_LEN {
173            return Err(DcbError::InvalidArgument(format!(
174                "metadata value for key '{}' has length {} bytes, exceeding the maximum of {}",
175                k,
176                v.len(),
177                MAX_METADATA_ENTRY_LEN
178            )));
179        }
180    }
181    Ok(())
182}
183
184/// Check if the metadata slice contains duplicate keys.
185/// Uses brute force for small slices (< 8 elements) and FxHashSet for larger ones.
186pub fn has_duplicate_metadata_key(metadata: &[(String, String)]) -> bool {
187    // 1. Fast path for empty or single-item slices
188    if metadata.len() < 2 {
189        return false;
190    }
191
192    // 2. Linear search for small sizes avoids hashing/allocation overhead
193    if metadata.len() < 9 {
194        for (i, (k1, _)) in metadata.iter().enumerate() {
195            // Using slicing and iterators completely eliminates bounds-checking
196            if metadata[i + 1..].iter().any(|(k2, _)| k1 == k2) {
197                return true;
198            }
199        }
200        return false;
201    }
202
203    // 3. Fallback to a fast hash set for larger slices
204    let mut set = FxHashSet::with_capacity_and_hasher(metadata.len(), Default::default());
205
206    // Using `.any()` combined with `.insert()` is short-circuiting and idiomatic
207    metadata.iter().any(|(k, _)| !set.insert(k))
208}
209
210/// Number of bytes needed to serialize the given metadata map.
211///
212/// Layout: 2 bytes entry count, then for each entry 2 bytes key length + key
213/// bytes + 2 bytes value length + value bytes.
214pub fn metadata_serialized_size(metadata: &[(String, String)]) -> usize {
215    let mut size = 2; // entry count (u16)
216    for (k, v) in metadata {
217        size += 2 + k.len() + 2 + v.len();
218    }
219    size
220}
221
222/// Serialize metadata pairs into the start of `buf`, returning the number of bytes written.
223pub fn serialize_metadata_into(metadata: &[(String, String)], buf: &mut [u8]) -> DcbResult<usize> {
224    // 1. Wrap the pre-allocated slice in a Cursor.
225    // This tracks the index automatically without allocating heap memory.
226    let mut cursor = Cursor::new(buf);
227
228    // 2. Write the total count of elements (2 bytes)
229    let n = metadata.len() as u16;
230    cursor.write_all(&n.to_le_bytes())?;
231
232    // 3. Loop directly through the slice references.
233    // Zero heap allocations happen here.
234    for (k, v) in metadata {
235        let kl = k.len() as u16;
236        cursor.write_all(&kl.to_le_bytes())?;
237        cursor.write_all(k.as_bytes())?;
238
239        let vl = v.len() as u16;
240        cursor.write_all(&vl.to_le_bytes())?;
241        cursor.write_all(v.as_bytes())?;
242    }
243
244    // 4. Get the exact final index position from the cursor
245    Ok(cursor.position() as usize)
246}
247
248// TODO: Move this because it's only used in tests.
249/// Serialize metadata into a freshly allocated buffer.
250pub fn serialize_metadata(metadata: &[(String, String)]) -> Vec<u8> {
251    let mut buf = vec![0u8; metadata_serialized_size(metadata)];
252    serialize_metadata_into(metadata, &mut buf).unwrap();
253    buf
254}
255
256/// Read a metadata map using the provided SliceReader.
257fn read_metadata(reader: &mut SliceReader<'_>) -> DcbResult<Vec<(String, String)>> {
258    let n = reader.read_u16()? as usize;
259    let mut metadata = Vec::with_capacity(n);
260
261    for _ in 0..n {
262        let kl = reader.read_u16()? as usize;
263        let key = reader.read_string(kl)?;
264
265        let vl = reader.read_u16()? as usize;
266        let value = reader.read_string(vl)?;
267
268        metadata.push((key, value));
269    }
270
271    Ok(metadata)
272}
273
274/// Deserialize a metadata map from a complete slice (used for the overflow
275/// chain, where metadata bytes follow the event data).
276pub fn deserialize_metadata(slice: &[u8]) -> DcbResult<Vec<(String, String)>> {
277    let mut reader = SliceReader::new(slice);
278    read_metadata(&mut reader)
279}
280
281impl PartialEq<EventValue> for EventRecord {
282    fn eq(&self, other: &EventValue) -> bool {
283        match other {
284            EventValue::Inline(rec) => self == rec,
285            EventValue::Overflow {
286                event_type,
287                data_len,
288                tags,
289                ..
290            } => {
291                &self.event_type == event_type
292                    && &self.tags == tags
293                    && (self.data.len() as u64) == *data_len
294            }
295        }
296    }
297}
298
299impl PartialEq<EventRecord> for EventValue {
300    fn eq(&self, other: &EventRecord) -> bool {
301        other == self
302    }
303}
304
305bitflags! {
306    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
307    pub struct EventValueFlags: u8 {
308        const OVERFLOW      = 0b0000_0001; // event payload in overflow node
309        const HAS_UUID      = 0b0000_0010; // event includes UUID field
310        const HAS_METADATA  = 0b0000_0100; // event includes metadata field
311    }
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
315pub struct EventLeafNode {
316    pub keys: Vec<Position>,
317    pub values: Vec<EventValue>,
318}
319
320impl EventLeafNode {
321    pub fn calc_serialized_size(&self) -> usize {
322        // 2 bytes for keys_len
323        let mut total_size = 2;
324
325        // 8 bytes for each Position in keys
326        total_size += self.keys.len() * 8;
327
328        // For each value
329        for value in &self.values {
330            // 1 byte for discriminator
331            total_size += 1;
332            match value {
333                EventValue::Inline(rec) => {
334                    // 2 bytes for event_type length + bytes for the string
335                    total_size += 2 + rec.event_type.len();
336                    // 2 bytes for data length + bytes for the data
337                    total_size += 2 + rec.data.len();
338                    // 2 bytes for number of tags
339                    total_size += 2;
340                    // For each tag: 2 bytes for length + bytes for the string
341                    for tag in &rec.tags {
342                        total_size += 2 + tag.len();
343                    }
344                    if rec.uuid.is_some() {
345                        total_size += 16;
346                    }
347                    if !rec.metadata.is_empty() {
348                        total_size += metadata_serialized_size(&rec.metadata);
349                    }
350                }
351                EventValue::Overflow {
352                    event_type,
353                    data_len: _,
354                    tags,
355                    root_id: _,
356                    uuid,
357                    metadata_len,
358                } => {
359                    // 2 bytes for event_type length + bytes for the string
360                    total_size += 2 + event_type.len();
361                    // 8 bytes for data_len (u64)
362                    total_size += 8;
363                    // 2 bytes for number of tags
364                    total_size += 2;
365                    // For each tag: 2 bytes for length + bytes for the string
366                    for tag in tags {
367                        total_size += 2 + tag.len();
368                    }
369                    // 8 bytes for root_id
370                    total_size += 8;
371                    if uuid.is_some() {
372                        total_size += 16;
373                    }
374                    if *metadata_len > 0 {
375                        // 8 bytes for metadata_len (u64)
376                        total_size += 8;
377                    }
378                }
379            }
380        }
381
382        total_size
383    }
384
385    /// No-allocation serialization into the provided buffer. Returns number of bytes written.
386    pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
387        let mut cursor = Cursor::new(buf);
388
389        // keys_len
390        let klen = self.keys.len() as u16;
391        cursor.write_all(&klen.to_le_bytes())?;
392
393        // keys
394        for key in &self.keys {
395            cursor.write_all(&key.0.to_le_bytes())?;
396        }
397
398        // values
399        for value in &self.values {
400            let mut flags = EventValueFlags::empty();
401            match value {
402                EventValue::Inline(rec) => {
403                    if rec.uuid.is_some() {
404                        flags |= EventValueFlags::HAS_UUID;
405                    }
406                    if !rec.metadata.is_empty() {
407                        flags |= EventValueFlags::HAS_METADATA;
408                    }
409                    cursor.write_all(&[flags.bits()])?;
410
411                    let et_len = rec.event_type.len() as u16;
412                    cursor.write_all(&et_len.to_le_bytes())?;
413                    cursor.write_all(rec.event_type.as_bytes())?;
414
415                    let dlen = rec.data.len() as u16;
416                    cursor.write_all(&dlen.to_le_bytes())?;
417                    cursor.write_all(&rec.data)?;
418
419                    let tlen = rec.tags.len() as u16;
420                    cursor.write_all(&tlen.to_le_bytes())?;
421
422                    for tag in &rec.tags {
423                        let tl = tag.len() as u16;
424                        cursor.write_all(&tl.to_le_bytes())?;
425                        cursor.write_all(tag.as_bytes())?;
426                    }
427
428                    if let Some(uuid) = rec.uuid {
429                        cursor.write_all(uuid.as_bytes())?;
430                    }
431
432                    if !rec.metadata.is_empty() {
433                        let pos = cursor.position() as usize;
434                        let remaining_buf = &mut cursor.get_mut()[pos..];
435
436                        // Propagate any error from the nested serialization
437                        let written = serialize_metadata_into(&rec.metadata, remaining_buf)?;
438
439                        // Advance the parent cursor past the written metadata
440                        cursor.set_position((pos + written) as u64);
441                    }
442                }
443                EventValue::Overflow {
444                    event_type,
445                    data_len,
446                    tags,
447                    root_id,
448                    uuid,
449                    metadata_len,
450                } => {
451                    flags |= EventValueFlags::OVERFLOW;
452                    if uuid.is_some() {
453                        flags |= EventValueFlags::HAS_UUID;
454                    }
455                    if *metadata_len > 0 {
456                        flags |= EventValueFlags::HAS_METADATA;
457                    }
458                    cursor.write_all(&[flags.bits()])?;
459
460                    let et_len = event_type.len() as u16;
461                    cursor.write_all(&et_len.to_le_bytes())?;
462                    cursor.write_all(event_type.as_bytes())?;
463
464                    cursor.write_all(&data_len.to_le_bytes())?;
465
466                    let tlen = tags.len() as u16;
467                    cursor.write_all(&tlen.to_le_bytes())?;
468
469                    for tag in tags {
470                        let tl = tag.len() as u16;
471                        cursor.write_all(&tl.to_le_bytes())?;
472                        cursor.write_all(tag.as_bytes())?;
473                    }
474
475                    cursor.write_all(&root_id.0.to_le_bytes())?;
476
477                    if let Some(uuid_val) = uuid {
478                        cursor.write_all(uuid_val.as_bytes())?;
479                    }
480
481                    if *metadata_len > 0 {
482                        cursor.write_all(&metadata_len.to_le_bytes())?;
483                    }
484                }
485            }
486        }
487
488        Ok(cursor.position() as usize)
489    }
490
491    pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
492        let mut reader = SliceReader::new(slice);
493
494        // Read keys
495        let keys_len = reader.read_u16()? as usize;
496        let mut keys = Vec::with_capacity(keys_len);
497        for _ in 0..keys_len {
498            keys.push(reader.read_position()?);
499        }
500
501        // Read values
502        let mut values = Vec::with_capacity(keys_len);
503
504        for _ in 0..keys_len {
505            // Flags
506            let flags_byte = reader.read_u8()?;
507            let flags = EventValueFlags::from_bits(flags_byte).ok_or_else(|| {
508                DcbError::DeserializationError("unknown flag bits set".to_string())
509            })?;
510
511            // Event Type
512            let event_type_len = reader.read_u16()? as usize;
513            let event_type = reader.read_string(event_type_len)?;
514
515            let overflow = flags.contains(EventValueFlags::OVERFLOW);
516            let has_uuid = flags.contains(EventValueFlags::HAS_UUID);
517            let has_metadata = flags.contains(EventValueFlags::HAS_METADATA);
518
519            if !overflow {
520                // --- Inline Event ---
521                let data_len = reader.read_u16()? as usize;
522                let data = reader.read_bytes(data_len)?.to_vec();
523
524                let num_tags = reader.read_u16()? as usize;
525                let mut tags = Vec::with_capacity(num_tags);
526                for _ in 0..num_tags {
527                    let tag_len = reader.read_u16()? as usize;
528                    let tag = reader.read_string(tag_len)?;
529                    tags.push(tag);
530                }
531                let uuid = if has_uuid {
532                    Some(reader.read_uuid()?)
533                } else {
534                    None
535                };
536                let metadata = if has_metadata {
537                    read_metadata(&mut reader)?
538                } else {
539                    Vec::new()
540                };
541
542                values.push(EventValue::Inline(EventRecord {
543                    event_type,
544                    data,
545                    tags,
546                    uuid,
547                    metadata,
548                }));
549            } else {
550                // --- Overflow Event ---
551                let data_len = reader.read_u64()?;
552
553                let num_tags = reader.read_u16()? as usize;
554                let mut tags = Vec::with_capacity(num_tags);
555                for _ in 0..num_tags {
556                    let tag_len = reader.read_u16()? as usize;
557                    let tag = reader.read_string(tag_len)?;
558                    tags.push(tag);
559                }
560
561                let root_id = reader.read_page_id()?;
562
563                let uuid = if has_uuid {
564                    Some(reader.read_uuid()?)
565                } else {
566                    None
567                };
568
569                let metadata_len = if has_metadata { reader.read_u64()? } else { 0 };
570
571                values.push(EventValue::Overflow {
572                    event_type,
573                    data_len,
574                    tags,
575                    root_id,
576                    uuid,
577                    metadata_len,
578                });
579            }
580        }
581
582        Ok(EventLeafNode { keys, values })
583    }
584
585    pub fn pop_last_key_and_value(&mut self) -> DcbResult<(Position, EventValue)> {
586        let last_key = self
587            .keys
588            .pop()
589            .expect("EventLeafNode should have some keys");
590        let last_value = self
591            .values
592            .pop()
593            .expect("EventLeafNode should have some values");
594        Ok((last_key, last_value))
595    }
596}
597
598#[derive(Debug, Clone, PartialEq, Eq)]
599pub struct EventOverflowNode {
600    pub next: PageID, // PageID(0) indicates end of chain
601    pub data: Vec<u8>,
602}
603
604impl EventOverflowNode {
605    pub fn calc_serialized_size(&self) -> usize {
606        // 8 bytes for next + data bytes
607        8 + self.data.len()
608    }
609
610    pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
611        let mut cursor = Cursor::new(buf);
612
613        // Write the next pointer (8 bytes)
614        cursor.write_all(&self.next.0.to_le_bytes())?;
615
616        // Write the data blob
617        cursor.write_all(&self.data)?;
618
619        Ok(cursor.position() as usize)
620    }
621
622    pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
623        let mut reader = SliceReader::new(slice);
624
625        // Read the next page pointer
626        let next = reader.read_page_id()?;
627
628        // Consume all remaining bytes for the data payload
629        let data = reader.read_bytes(reader.remaining())?.to_vec();
630
631        Ok(Self { next, data })
632    }
633}
634
635#[derive(Debug, Clone, PartialEq, Eq)]
636pub struct EventInternalNode {
637    pub keys: Vec<Position>,
638    pub child_ids: Vec<PageID>,
639}
640
641impl EventInternalNode {
642    pub fn calc_serialized_size(&self) -> usize {
643        // 2 bytes for keys_len
644        let mut total_size = 2;
645
646        // 8 bytes for each Position in keys
647        total_size += self.keys.len() * 8;
648
649        // 8 bytes for each PageID in child_ids
650        total_size += self.child_ids.len() * 8;
651
652        total_size
653    }
654
655    pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
656        let mut cursor = Cursor::new(buf);
657
658        // Keys length
659        let klen = self.keys.len() as u16;
660        cursor.write_all(&klen.to_le_bytes())?;
661
662        // Keys
663        for key in &self.keys {
664            cursor.write_all(&key.0.to_le_bytes())?;
665        }
666
667        // Child IDs (Length is intentionally not written)
668        for child_id in &self.child_ids {
669            cursor.write_all(&child_id.0.to_le_bytes())?;
670        }
671
672        Ok(cursor.position() as usize)
673    }
674
675    pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
676        let mut reader = SliceReader::new(slice);
677
678        // Read keys length
679        let keys_len = reader.read_u16()? as usize;
680
681        // Read keys (Positions)
682        let mut keys = Vec::with_capacity(keys_len);
683        for _ in 0..keys_len {
684            keys.push(reader.read_position()?);
685        }
686
687        // Derive child_ids length (always keys_len + 1 for internal nodes)
688        let child_ids_len = keys_len + 1;
689
690        // Read child IDs (PageIDs)
691        let mut child_ids = Vec::with_capacity(child_ids_len);
692        for _ in 0..child_ids_len {
693            child_ids.push(reader.read_page_id()?);
694        }
695
696        Ok(EventInternalNode { keys, child_ids })
697    }
698
699    pub fn replace_last_child_id(&mut self, old_id: PageID, new_id: PageID) -> DcbResult<()> {
700        // Replace the last child ID.
701        let last_idx = self.child_ids.len() - 1;
702        if self.child_ids[last_idx] == old_id {
703            self.child_ids[last_idx] = new_id;
704        } else {
705            return Err(DcbError::DatabaseCorrupted("Child ID mismatch".to_string()));
706        }
707        Ok(())
708    }
709    pub fn append_promoted_key_and_page_id(
710        &mut self,
711        promoted_key: Position,
712        promoted_page_id: PageID,
713    ) -> DcbResult<()> {
714        self.keys.push(promoted_key);
715        self.child_ids.push(promoted_page_id);
716        Ok(())
717    }
718    pub fn split_off(&mut self) -> DcbResult<(Position, Vec<Position>, Vec<PageID>)> {
719        let middle_idx = self.keys.len() - 2;
720        let promoted_key = self.keys.remove(middle_idx);
721        let new_keys = self.keys.split_off(middle_idx);
722        let new_child_ids = self.child_ids.split_off(middle_idx + 1);
723        Ok((promoted_key, new_keys, new_child_ids))
724    }
725}
726
727#[cfg(test)]
728mod tests {
729    use super::*;
730
731    #[test]
732    fn test_event_internal_serialize() {
733        // Create an EventInternalNode with known values
734        let internal_node = EventInternalNode {
735            keys: vec![Position(1000), Position(2000), Position(3000)],
736            child_ids: vec![PageID(100), PageID(200), PageID(300), PageID(400)],
737        };
738
739        // Serialize the EventInternalNode
740        let mut serialized = vec![0u8; internal_node.calc_serialized_size()];
741        internal_node.serialize_into(&mut serialized).unwrap();
742
743        // Verify the serialized output is not empty
744        assert!(!serialized.is_empty());
745
746        // Deserialize back to an EventInternalNode
747        let deserialized = EventInternalNode::from_slice(&serialized)
748            .expect("Failed to deserialize EventInternalNode");
749
750        // Verify that the deserialized node matches the original
751        assert_eq!(internal_node, deserialized);
752
753        // Verify specific properties
754        assert_eq!(3, deserialized.keys.len());
755        assert_eq!(4, deserialized.child_ids.len());
756
757        // Check keys
758        assert_eq!(Position(1000), deserialized.keys[0]);
759        assert_eq!(Position(2000), deserialized.keys[1]);
760        assert_eq!(Position(3000), deserialized.keys[2]);
761
762        // Check child_ids
763        assert_eq!(PageID(100), deserialized.child_ids[0]);
764        assert_eq!(PageID(200), deserialized.child_ids[1]);
765        assert_eq!(PageID(300), deserialized.child_ids[2]);
766        assert_eq!(PageID(400), deserialized.child_ids[3]);
767    }
768
769    #[test]
770    fn test_event_leaf_serialize_without_uuid() {
771        // Create an EventLeafNode with known values
772        let leaf_node = EventLeafNode {
773            keys: vec![Position(1000), Position(2000), Position(3000)],
774            values: vec![
775                EventValue::Inline(EventRecord {
776                    event_type: "event_type_1".to_string(),
777                    data: vec![1, 0, 0, 0], // 100 as little-endian bytes
778                    tags: vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()],
779                    uuid: None,
780                    metadata: Vec::new(),
781                }),
782                EventValue::Inline(EventRecord {
783                    event_type: "event_type_2".to_string(),
784                    data: vec![2, 0, 0, 0], // 200 as little-endian bytes
785                    tags: vec![
786                        "tag4".to_string(),
787                        "tag5".to_string(),
788                        "tag6".to_string(),
789                        "tag7".to_string(),
790                    ],
791                    uuid: None,
792                    metadata: Vec::new(),
793                }),
794                EventValue::Inline(EventRecord {
795                    event_type: "event_type_3".to_string(),
796                    data: vec![3, 0, 0, 0], // 300 as little-endian bytes
797                    tags: vec!["tag8".to_string(), "tag9".to_string()],
798                    uuid: None,
799                    metadata: Vec::new(),
800                }),
801            ],
802        };
803
804        // Serialize the EventLeafNode
805        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
806        leaf_node.serialize_into(&mut serialized).unwrap();
807
808        // Verify the serialized output is not empty
809        assert!(!serialized.is_empty());
810
811        // Deserialize back to an EventLeafNode
812        let deserialized =
813            EventLeafNode::from_slice(&serialized).expect("Failed to deserialize EventLeafNode");
814
815        // Verify that the deserialized node matches the original
816        assert_eq!(leaf_node, deserialized);
817
818        // Verify specific properties
819        assert_eq!(3, deserialized.keys.len());
820        assert_eq!(3, deserialized.values.len());
821
822        // Check keys
823        assert_eq!(Position(1000), deserialized.keys[0]);
824        assert_eq!(Position(2000), deserialized.keys[1]);
825        assert_eq!(Position(3000), deserialized.keys[2]);
826
827        // Check first value
828        match &deserialized.values[0] {
829            EventValue::Inline(v) => {
830                assert_eq!("event_type_1", v.event_type);
831                assert_eq!(vec![1, 0, 0, 0], v.data);
832                assert_eq!(
833                    vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()],
834                    v.tags
835                );
836                assert_eq!(None, v.uuid);
837            }
838            _ => panic!("Expected Inline for first value"),
839        }
840
841        // Check second value
842        match &deserialized.values[1] {
843            EventValue::Inline(v) => {
844                assert_eq!("event_type_2", v.event_type);
845                assert_eq!(vec![2, 0, 0, 0], v.data);
846                assert_eq!(
847                    vec![
848                        "tag4".to_string(),
849                        "tag5".to_string(),
850                        "tag6".to_string(),
851                        "tag7".to_string()
852                    ],
853                    v.tags
854                );
855                assert_eq!(None, v.uuid);
856            }
857            _ => panic!("Expected Inline for second value"),
858        }
859
860        // Check third value
861        match &deserialized.values[2] {
862            EventValue::Inline(v) => {
863                assert_eq!("event_type_3", v.event_type);
864                assert_eq!(vec![3, 0, 0, 0], v.data);
865                assert_eq!(vec!["tag8".to_string(), "tag9".to_string()], v.tags);
866                assert_eq!(None, v.uuid);
867            }
868            _ => panic!("Expected Inline for third value"),
869        }
870    }
871
872    #[test]
873    fn test_event_leaf_serialize_with_uuid() {
874        // Create an EventLeafNode with known values
875        let uuid1 = Uuid::new_v4();
876        let uuid2 = Uuid::new_v4();
877        let uuid3 = Uuid::new_v4();
878        let leaf_node = EventLeafNode {
879            keys: vec![Position(1000), Position(2000), Position(3000)],
880            values: vec![
881                EventValue::Inline(EventRecord {
882                    event_type: "event_type_1".to_string(),
883                    data: vec![1, 0, 0, 0], // 100 as little-endian bytes
884                    tags: vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()],
885                    uuid: Some(uuid1),
886                    metadata: Vec::new(),
887                }),
888                EventValue::Inline(EventRecord {
889                    event_type: "event_type_2".to_string(),
890                    data: vec![2, 0, 0, 0], // 200 as little-endian bytes
891                    tags: vec![
892                        "tag4".to_string(),
893                        "tag5".to_string(),
894                        "tag6".to_string(),
895                        "tag7".to_string(),
896                    ],
897                    uuid: Some(uuid2),
898                    metadata: Vec::new(),
899                }),
900                EventValue::Inline(EventRecord {
901                    event_type: "event_type_3".to_string(),
902                    data: vec![3, 0, 0, 0], // 300 as little-endian bytes
903                    tags: vec!["tag8".to_string(), "tag9".to_string()],
904                    uuid: Some(uuid3),
905                    metadata: Vec::new(),
906                }),
907            ],
908        };
909
910        // Serialize the EventLeafNode
911        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
912        leaf_node.serialize_into(&mut serialized).unwrap();
913
914        // Verify the serialized output is not empty
915        assert!(!serialized.is_empty());
916
917        // Deserialize back to an EventLeafNode
918        let deserialized =
919            EventLeafNode::from_slice(&serialized).expect("Failed to deserialize EventLeafNode");
920
921        // Verify that the deserialized node matches the original
922        assert_eq!(leaf_node, deserialized);
923
924        // Verify specific properties
925        assert_eq!(3, deserialized.keys.len());
926        assert_eq!(3, deserialized.values.len());
927
928        // Check keys
929        assert_eq!(Position(1000), deserialized.keys[0]);
930        assert_eq!(Position(2000), deserialized.keys[1]);
931        assert_eq!(Position(3000), deserialized.keys[2]);
932
933        // Check first value
934        match &deserialized.values[0] {
935            EventValue::Inline(v) => {
936                assert_eq!("event_type_1", v.event_type);
937                assert_eq!(vec![1, 0, 0, 0], v.data);
938                assert_eq!(
939                    vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()],
940                    v.tags
941                );
942                assert_eq!(Some(uuid1), v.uuid);
943            }
944            _ => panic!("Expected Inline for first value"),
945        }
946
947        // Check second value
948        match &deserialized.values[1] {
949            EventValue::Inline(v) => {
950                assert_eq!("event_type_2", v.event_type);
951                assert_eq!(vec![2, 0, 0, 0], v.data);
952                assert_eq!(
953                    vec![
954                        "tag4".to_string(),
955                        "tag5".to_string(),
956                        "tag6".to_string(),
957                        "tag7".to_string()
958                    ],
959                    v.tags
960                );
961                assert_eq!(Some(uuid2), v.uuid);
962            }
963            _ => panic!("Expected Inline for second value"),
964        }
965
966        // Check third value
967        match &deserialized.values[2] {
968            EventValue::Inline(v) => {
969                assert_eq!("event_type_3", v.event_type);
970                assert_eq!(vec![3, 0, 0, 0], v.data);
971                assert_eq!(vec!["tag8".to_string(), "tag9".to_string()], v.tags);
972                assert_eq!(Some(uuid3), v.uuid);
973            }
974            _ => panic!("Expected Inline for third value"),
975        }
976    }
977
978    #[test]
979    fn test_event_leaf_serialize_with_overflow_single_without_uuid() {
980        let leaf_node = EventLeafNode {
981            keys: vec![Position(111)],
982            values: vec![EventValue::Overflow {
983                event_type: "over_evt".to_string(),
984                data_len: 1234567,
985                tags: vec!["a".to_string(), "b".to_string()],
986                root_id: PageID(123),
987                uuid: None,
988                metadata_len: 0,
989            }],
990        };
991        // Serialize
992        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
993        leaf_node.serialize_into(&mut serialized).unwrap();
994        assert!(!serialized.is_empty());
995        // Deserialize
996        let deserialized = EventLeafNode::from_slice(&serialized)
997            .expect("Failed to deserialize EventLeafNode with overflow");
998        assert_eq!(leaf_node, deserialized);
999
1000        // Check specific fields
1001        assert_eq!(1, deserialized.keys.len());
1002        assert_eq!(Position(111), deserialized.keys[0]);
1003        assert_eq!(1, deserialized.values.len());
1004        match &deserialized.values[0] {
1005            EventValue::Overflow {
1006                event_type,
1007                data_len,
1008                tags,
1009                root_id,
1010                uuid,
1011                metadata_len,
1012            } => {
1013                assert_eq!("over_evt", event_type);
1014                assert_eq!(1234567, *data_len);
1015                assert_eq!(vec!["a".to_string(), "b".to_string()], *tags);
1016                assert_eq!(PageID(123), *root_id);
1017                assert_eq!(None, *uuid);
1018                assert_eq!(0, *metadata_len);
1019            }
1020            _ => panic!("Expected Overflow variant"),
1021        }
1022    }
1023
1024    #[test]
1025    fn test_event_leaf_serialize_with_overflow_single_with_uuid() {
1026        let uuid1 = Uuid::new_v4();
1027        let leaf_node = EventLeafNode {
1028            keys: vec![Position(111)],
1029            values: vec![EventValue::Overflow {
1030                event_type: "over_evt".to_string(),
1031                data_len: 1234567,
1032                tags: vec!["a".to_string(), "b".to_string()],
1033                root_id: PageID(123),
1034                uuid: Some(uuid1),
1035                metadata_len: 0,
1036            }],
1037        };
1038        // Serialize
1039        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
1040        leaf_node.serialize_into(&mut serialized).unwrap();
1041        assert!(!serialized.is_empty());
1042        // Deserialize
1043        let deserialized = EventLeafNode::from_slice(&serialized)
1044            .expect("Failed to deserialize EventLeafNode with overflow");
1045        assert_eq!(leaf_node, deserialized);
1046
1047        // Check specific fields
1048        assert_eq!(1, deserialized.keys.len());
1049        assert_eq!(Position(111), deserialized.keys[0]);
1050        assert_eq!(1, deserialized.values.len());
1051        match &deserialized.values[0] {
1052            EventValue::Overflow {
1053                event_type,
1054                data_len,
1055                tags,
1056                root_id,
1057                uuid,
1058                metadata_len: 0,
1059            } => {
1060                assert_eq!("over_evt", event_type);
1061                assert_eq!(1234567, *data_len);
1062                assert_eq!(vec!["a".to_string(), "b".to_string()], *tags);
1063                assert_eq!(PageID(123), *root_id);
1064                assert_eq!(Some(uuid1), *uuid);
1065            }
1066            _ => panic!("Expected Overflow variant"),
1067        }
1068    }
1069
1070    #[test]
1071    fn test_event_leaf_serialize_mixed_inline_and_overflow() {
1072        let inline = EventValue::Inline(EventRecord {
1073            event_type: "inline_evt".to_string(),
1074            data: vec![1, 2, 3],
1075            tags: vec!["x".to_string()],
1076            uuid: None,
1077            metadata: Vec::new(),
1078        });
1079        let overflow = EventValue::Overflow {
1080            event_type: "overflow_evt".to_string(),
1081            data_len: 9999,
1082            tags: vec!["y".to_string(), "z".to_string()],
1083            root_id: PageID(999),
1084            uuid: None,
1085            metadata_len: 0,
1086        };
1087        let leaf_node = EventLeafNode {
1088            keys: vec![Position(10), Position(20)],
1089            values: vec![inline.clone(), overflow.clone()],
1090        };
1091        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
1092        leaf_node.serialize_into(&mut serialized).unwrap();
1093        let deserialized = EventLeafNode::from_slice(&serialized).unwrap();
1094        assert_eq!(leaf_node, deserialized);
1095
1096        // Validate order and variants
1097        match &deserialized.values[0] {
1098            EventValue::Inline(rec) => {
1099                assert_eq!("inline_evt", rec.event_type);
1100                assert_eq!(vec![1, 2, 3], rec.data);
1101                assert_eq!(vec!["x".to_string()], rec.tags);
1102                assert_eq!(None, rec.uuid);
1103            }
1104            _ => panic!("Expected Inline at index 0"),
1105        }
1106        match &deserialized.values[1] {
1107            EventValue::Overflow {
1108                event_type,
1109                data_len,
1110                tags,
1111                root_id,
1112                uuid,
1113                metadata_len,
1114            } => {
1115                assert_eq!("overflow_evt", event_type);
1116                assert_eq!(9999, *data_len);
1117                assert_eq!(vec!["y".to_string(), "z".to_string()], *tags);
1118                assert_eq!(PageID(999), *root_id);
1119                assert_eq!(None, *uuid);
1120                assert_eq!(0, *metadata_len);
1121            }
1122            _ => panic!("Expected Overflow at index 1"),
1123        }
1124    }
1125
1126    #[test]
1127    fn test_metadata_serialize_roundtrip() {
1128        let mut metadata = Vec::new();
1129        metadata.push(("source".to_string(), "web".to_string()));
1130        metadata.push(("correlation_id".to_string(), "abc-123".to_string()));
1131        metadata.push(("empty_value".to_string(), "".to_string()));
1132
1133        let bytes = serialize_metadata(&metadata);
1134        assert_eq!(bytes.len(), metadata_serialized_size(&metadata));
1135
1136        let deserialized = deserialize_metadata(&bytes).unwrap();
1137        assert_eq!(metadata, deserialized);
1138    }
1139
1140    #[test]
1141    fn test_validate_metadata_within_limits_ok() {
1142        let mut metadata = Vec::new();
1143        metadata.push(("k".to_string(), "v".to_string()));
1144        // A key and value exactly at the maximum length are allowed.
1145        metadata.push(("a".repeat(MAX_METADATA_ENTRY_LEN), "b".to_string()));
1146        metadata.push(("c".to_string(), "d".repeat(MAX_METADATA_ENTRY_LEN)));
1147        assert!(validate_metadata(&metadata).is_ok());
1148    }
1149
1150    // #[test]
1151    // fn test_validate_event_type_rejects_oversized() {
1152    //     let et = "a".repeat(MAX_EVENT_TYPE_LEN + 1);
1153    //     match validate_event_type(&et) {
1154    //         Err(DcbError::InvalidArgument(msg)) => {
1155    //             assert!(msg.contains("event type has length"));
1156    //             assert!(msg.contains("exceeding the maximum"));
1157    //         }
1158    //         other => panic!("Expected InvalidArgument, got {other:?}"),
1159    //     }
1160    // }
1161
1162    // #[test]
1163    // fn test_validate_tags_rejects_oversized_tag() {
1164    //     let tags = vec!["tag".repeat(MAX_TAG_LEN + 1)];
1165    //     match validate_tags(&tags) {
1166    //         Err(DcbError::InvalidArgument(msg)) => {
1167    //             assert!(msg.contains("tag has length"));
1168    //             assert!(msg.contains("exceeding the maximum"));
1169    //         }
1170    //         other => panic!("Expected InvalidArgument, got {other:?}"),
1171    //     }
1172    // }
1173
1174    #[test]
1175    fn test_validate_tags_rejects_too_many_tags() {
1176        let tags = vec!["tag".to_string(); MAX_TAGS + 1];
1177        match validate_tags(&tags) {
1178            Err(DcbError::InvalidArgument(msg)) => {
1179                assert!(msg.contains("event has"));
1180                assert!(msg.contains("tags, exceeding the maximum"));
1181            }
1182            other => panic!("Expected InvalidArgument, got {other:?}"),
1183        }
1184    }
1185
1186    #[test]
1187    fn test_has_duplicate() {
1188        // No duplicates
1189        let mut metadata = Vec::new();
1190        metadata.push(("key1".to_string(), "val1".to_string()));
1191        metadata.push(("key2".to_string(), "val2".to_string()));
1192        assert!(!has_duplicate_metadata_key(&metadata));
1193
1194        // With duplicates
1195        metadata.push(("key1".to_string(), "val3".to_string()));
1196        assert!(has_duplicate_metadata_key(&metadata));
1197
1198        // Test with more than 8 elements (switches to FxHashSet)
1199        let mut large_metadata = Vec::new();
1200        for i in 0..10 {
1201            large_metadata.push((format!("key{i}"), "val".to_string()));
1202        }
1203        assert!(!has_duplicate_metadata_key(&large_metadata));
1204
1205        large_metadata.push(("key5".to_string(), "duplicate".to_string()));
1206        assert!(has_duplicate_metadata_key(&large_metadata));
1207    }
1208
1209    #[test]
1210    fn test_validate_metadata_rejects_duplicates() {
1211        let mut metadata = Vec::new();
1212        metadata.push(("key1".to_string(), "val1".to_string()));
1213        metadata.push(("key1".to_string(), "val2".to_string()));
1214        match validate_metadata(&metadata) {
1215            Err(DcbError::InvalidArgument(msg)) => {
1216                assert!(msg.contains("duplicate keys"));
1217            }
1218            other => panic!("Expected InvalidArgument with duplicate keys message, got {other:?}"),
1219        }
1220    }
1221
1222    #[test]
1223    fn test_validate_metadata_rejects_oversized_value() {
1224        let mut metadata = Vec::new();
1225        metadata.push(("k".to_string(), "v".repeat(MAX_METADATA_ENTRY_LEN + 1)));
1226        match validate_metadata(&metadata) {
1227            Err(DcbError::InvalidArgument(_)) => {}
1228            other => panic!("Expected InvalidArgument, got {other:?}"),
1229        }
1230    }
1231
1232    #[test]
1233    fn test_validate_metadata_rejects_oversized_key() {
1234        let mut metadata = Vec::new();
1235        metadata.push(("k".repeat(MAX_METADATA_ENTRY_LEN + 1), "v".to_string()));
1236        match validate_metadata(&metadata) {
1237            Err(DcbError::InvalidArgument(_)) => {}
1238            other => panic!("Expected InvalidArgument, got {other:?}"),
1239        }
1240    }
1241
1242    #[test]
1243    fn test_metadata_serialize_roundtrip_at_max_entry_len() {
1244        // A key/value at exactly the maximum length must survive a round-trip.
1245        let mut metadata = Vec::new();
1246        metadata.push(("k".repeat(MAX_METADATA_ENTRY_LEN), "v".to_string()));
1247        metadata.push(("k2".to_string(), "v".repeat(MAX_METADATA_ENTRY_LEN)));
1248        let bytes = serialize_metadata(&metadata);
1249        assert_eq!(bytes.len(), metadata_serialized_size(&metadata));
1250        assert_eq!(metadata, deserialize_metadata(&bytes).unwrap());
1251    }
1252
1253    #[test]
1254    fn test_empty_metadata_serialize_roundtrip() {
1255        let metadata: Vec<(String, String)> = Vec::new();
1256        let bytes = serialize_metadata(&metadata);
1257        // Just the 2-byte entry count of zero.
1258        assert_eq!(bytes.len(), 2);
1259        assert_eq!(metadata, deserialize_metadata(&bytes).unwrap());
1260    }
1261
1262    #[test]
1263    fn test_event_leaf_serialize_inline_with_metadata() {
1264        let mut md1 = Vec::new();
1265        md1.push(("source".to_string(), "ingest".to_string()));
1266        md1.push(("schema".to_string(), "v2".to_string()));
1267
1268        let mut md3 = Vec::new();
1269        md3.push(("trace".to_string(), "deadbeef".to_string()));
1270
1271        let uuid2 = Uuid::new_v4();
1272        let leaf_node = EventLeafNode {
1273            keys: vec![Position(10), Position(20), Position(30)],
1274            values: vec![
1275                // Inline with metadata, no uuid
1276                EventValue::Inline(EventRecord {
1277                    event_type: "with_md".to_string(),
1278                    data: vec![1, 2, 3, 4],
1279                    tags: vec!["tag1".to_string()],
1280                    uuid: None,
1281                    metadata: md1.clone(),
1282                }),
1283                // Inline with both uuid and metadata
1284                EventValue::Inline(EventRecord {
1285                    event_type: "uuid_and_md".to_string(),
1286                    data: vec![5, 6],
1287                    tags: vec!["tag2".to_string(), "tag3".to_string()],
1288                    uuid: Some(uuid2),
1289                    metadata: md3.clone(),
1290                }),
1291                // Inline with empty metadata to confirm the flag stays unset
1292                EventValue::Inline(EventRecord {
1293                    event_type: "no_md".to_string(),
1294                    data: vec![7],
1295                    tags: vec![],
1296                    uuid: None,
1297                    metadata: Vec::new(),
1298                }),
1299            ],
1300        };
1301
1302        let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
1303        let written = leaf_node.serialize_into(&mut serialized).unwrap();
1304        assert_eq!(written, serialized.len());
1305
1306        let deserialized =
1307            EventLeafNode::from_slice(&serialized).expect("Failed to deserialize EventLeafNode");
1308        assert_eq!(leaf_node, deserialized);
1309
1310        match &deserialized.values[0] {
1311            EventValue::Inline(rec) => assert_eq!(md1, rec.metadata),
1312            _ => panic!("Expected Inline at index 0"),
1313        }
1314        match &deserialized.values[1] {
1315            EventValue::Inline(rec) => {
1316                assert_eq!(Some(uuid2), rec.uuid);
1317                assert_eq!(md3, rec.metadata);
1318            }
1319            _ => panic!("Expected Inline at index 1"),
1320        }
1321        match &deserialized.values[2] {
1322            EventValue::Inline(rec) => assert!(rec.metadata.is_empty()),
1323            _ => panic!("Expected Inline at index 2"),
1324        }
1325    }
1326
1327    #[test]
1328    fn test_event_overflow_node_serialize_roundtrip() {
1329        let node = EventOverflowNode {
1330            next: PageID(77),
1331            data: vec![7, 8, 9, 10],
1332        };
1333        let mut ser = vec![0u8; node.calc_serialized_size()];
1334        node.serialize_into(&mut ser).unwrap();
1335        assert_eq!(8 + 4, ser.len()); // 8 bytes next + 4 bytes data
1336        let de = EventOverflowNode::from_slice(&ser).unwrap();
1337        assert_eq!(node, de);
1338        assert_eq!(PageID(77), de.next);
1339        assert_eq!(vec![7, 8, 9, 10], de.data);
1340    }
1341}