1use crate::TraceEvent;
8use crate::codec::{self, PoolEntry, StackPoolEntry, WireTypeId};
9use crate::schema::{SchemaEntry, SchemaRegistry};
10use crate::types::{
11 CountingWriter, EncodeState, EventEncoder, InternedStackFrames, InternedString,
12};
13use std::any::TypeId;
14use std::collections::{HashMap, HashSet};
15use std::hash::{BuildHasherDefault, Hasher};
16use std::io::{self, Write};
17use std::sync::Arc;
18
19#[doc(hidden)]
24#[derive(Default)]
25pub struct FxHasher(u64);
26
27impl FxHasher {
28 #[inline]
29 fn hash_word(&mut self, word: u64) {
30 self.0 = (self.0.rotate_left(5) ^ word).wrapping_mul(0x517cc1b727220a95);
31 }
32}
33
34impl Hasher for FxHasher {
35 #[inline]
36 fn write(&mut self, mut bytes: &[u8]) {
37 while bytes.len() >= 8 {
38 self.hash_word(u64::from_ne_bytes(bytes[..8].try_into().unwrap()));
39 bytes = &bytes[8..];
40 }
41 if bytes.len() >= 4 {
42 self.hash_word(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as u64);
43 bytes = &bytes[4..];
44 }
45 for &b in bytes {
46 self.hash_word(b as u64);
47 }
48 }
49
50 #[inline]
51 fn write_u8(&mut self, i: u8) {
52 self.hash_word(i as u64);
53 }
54
55 #[inline]
56 fn write_u16(&mut self, i: u16) {
57 self.hash_word(i as u64);
58 }
59
60 #[inline]
61 fn write_u32(&mut self, i: u32) {
62 self.hash_word(i as u64);
63 }
64
65 #[inline]
66 fn write_u64(&mut self, i: u64) {
67 self.hash_word(i);
68 }
69
70 #[inline]
71 fn write_usize(&mut self, i: usize) {
72 self.hash_word(i as u64);
73 }
74
75 #[inline]
76 fn write_u128(&mut self, i: u128) {
77 self.hash_word(i as u64);
78 self.hash_word((i >> 64) as u64);
79 }
80
81 #[inline]
82 fn finish(&self) -> u64 {
83 self.0
84 }
85}
86
87#[doc(hidden)]
88pub type FxBuildHasher = BuildHasherDefault<FxHasher>;
89#[doc(hidden)]
90pub type FxHashMap<K, V> = HashMap<K, V, FxBuildHasher>;
91#[doc(hidden)]
92pub type FxHashSet<T> = HashSet<T, FxBuildHasher>;
93
94#[derive(Clone, Debug)]
103pub struct Schema {
104 pub(crate) entry: Arc<SchemaEntry>,
105 name_key: Arc<str>,
108}
109
110impl Schema {
111 pub fn new(name: &str, fields: Vec<crate::schema::FieldDef>) -> Self {
116 let name_key: Arc<str> = Arc::from(name);
117 Self {
118 entry: Arc::new(SchemaEntry {
119 name: name.to_string(),
120 has_timestamp: true,
121 fields,
122 annotations: Vec::new(),
123 }),
124 name_key,
125 }
126 }
127
128 pub fn from_entry(entry: SchemaEntry) -> Self {
130 let name_key: Arc<str> = Arc::from(entry.name.as_str());
131 Self {
132 entry: Arc::new(entry),
133 name_key,
134 }
135 }
136
137 pub fn name(&self) -> &str {
139 &self.entry.name
140 }
141
142 pub fn fields(&self) -> &[crate::schema::FieldDef] {
144 &self.entry.fields
145 }
146}
147
148#[derive(Clone, PartialEq, Eq, Hash)]
151enum SchemaKey {
152 Name(Arc<str>),
153 RustType(TypeId),
154}
155
156pub struct Encoder<W: Write = Vec<u8>> {
164 state: EncodeState<W>,
165 registry: SchemaRegistry,
166 string_pool: FxHashMap<String, u32>,
167 next_pool_id: u32,
168 stack_pool: FxHashMap<Box<[u64]>, u32>,
169 next_stack_pool_id: u32,
170 schema_ids: FxHashMap<SchemaKey, WireTypeId>,
171 slot_cache: Vec<u32>,
174 registered_ids: [u64; (crate::STATIC_WIRE_ID_LIMIT as usize) / 64],
178}
179
180impl Default for Encoder<Vec<u8>> {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186impl Encoder<Vec<u8>> {
187 pub fn new() -> Self {
188 let mut buf = Vec::new();
189 codec::encode_header(&mut buf).expect("Vec::write_all cannot fail");
190 Self {
191 state: EncodeState::new(buf),
192 registry: SchemaRegistry::new(),
193 string_pool: FxHashMap::default(),
194 next_pool_id: 0,
195 stack_pool: FxHashMap::default(),
196 next_stack_pool_id: 0,
197 schema_ids: FxHashMap::default(),
198 slot_cache: Vec::new(),
199 registered_ids: [0; (crate::STATIC_WIRE_ID_LIMIT as usize) / 64],
200 }
201 }
202
203 pub fn finish(self) -> Vec<u8> {
205 self.state.writer.into_inner()
206 }
207}
208
209impl<W: Write> Encoder<W> {
210 pub fn new_to(mut writer: W) -> io::Result<Self> {
213 codec::encode_header(&mut writer)?;
214 Ok(Self {
215 state: EncodeState::new(writer),
216 registry: SchemaRegistry::new(),
217 string_pool: FxHashMap::default(),
218 next_pool_id: 0,
219 stack_pool: FxHashMap::default(),
220 next_stack_pool_id: 0,
221 schema_ids: FxHashMap::default(),
222 slot_cache: Vec::new(),
223 registered_ids: [0; (crate::STATIC_WIRE_ID_LIMIT as usize) / 64],
224 })
225 }
226
227 pub(crate) fn from_decoder(
230 mut registry: SchemaRegistry,
231 string_pool: crate::decoder::StringPool,
232 stack_pool: crate::decoder::StackPool,
233 timestamp_base_ns: u64,
234 writer: W,
235 ) -> Self {
236 let mut pool = FxHashMap::default();
237 let mut next_pool_id: u32 = 0;
238 for (id, value) in string_pool.0.into_iter() {
239 pool.insert(value, id.raw_id());
240 if id.raw_id() >= next_pool_id {
241 next_pool_id = id.raw_id() + 1;
242 }
243 }
244
245 let mut new_stack_pool: FxHashMap<Box<[u64]>, u32> = FxHashMap::default();
246 let mut next_stack_pool_id: u32 = 0;
247 for (id, frames) in stack_pool.0.into_iter() {
248 new_stack_pool.insert(frames.into_boxed_slice(), id.raw_id());
249 if id.raw_id() >= next_stack_pool_id {
250 next_stack_pool_id = id.raw_id() + 1;
251 }
252 }
253
254 let mut schema_ids = FxHashMap::default();
255 for (wire_id, entry) in registry.entries() {
256 schema_ids.insert(SchemaKey::Name(Arc::from(entry.name.as_str())), wire_id);
257 }
258 registry.sync_next_id();
259
260 let mut state = EncodeState::new(writer);
261 state.set_ts_base_unchecked(timestamp_base_ns);
262
263 Self {
264 state,
265 registry,
266 string_pool: pool,
267 next_pool_id,
268 stack_pool: new_stack_pool,
269 next_stack_pool_id,
270 schema_ids,
271 slot_cache: Vec::new(),
272 registered_ids: [0; (crate::STATIC_WIRE_ID_LIMIT as usize) / 64],
273 }
274 }
275
276 pub fn into_inner(self) -> W {
278 self.state.writer.into_inner()
279 }
280
281 pub fn as_inner(&self) -> &W {
283 self.state.writer.inner()
284 }
285
286 pub fn bytes_written(&self) -> u64 {
288 self.state.writer.bytes_written()
289 }
290
291 pub fn reset_to(&mut self, mut new_writer: W) -> io::Result<W> {
294 codec::encode_header(&mut new_writer)?;
295 self.string_pool.clear();
296 self.next_pool_id = 0;
297 self.stack_pool.clear();
298 self.next_stack_pool_id = 0;
299 self.registry.clear();
300 self.schema_ids.clear();
301 self.slot_cache.fill(0);
302 self.registered_ids.fill(0);
303 let old_state = std::mem::replace(&mut self.state, EncodeState::new(new_writer));
305 Ok(old_state.writer.into_inner())
306 }
307
308 fn ensure_registered(&mut self, schema: &Schema) -> io::Result<WireTypeId> {
314 let key = SchemaKey::Name(Arc::clone(&schema.name_key));
315 if let Some(&wire_id) = self.schema_ids.get(&key) {
316 let Some(existing) = self.registry.get(wire_id) else {
318 return Err(io::Error::other(format!(
319 "corrupted internal state. {wire_id:?} in schema_ids but not in registry."
320 )));
321 };
322 if *existing == *schema.entry {
323 return Ok(wire_id);
324 }
325 return Err(io::Error::new(
326 io::ErrorKind::InvalidInput,
327 format!(
328 "schema already registered with different definition: {}",
329 schema.name()
330 ),
331 ));
332 }
333 let id = self.registry.next_type_id();
334 codec::encode_schema(id, &schema.entry, &mut self.state.writer)?;
335 if !schema.entry.annotations.is_empty() {
336 codec::encode_schema_annotations(
337 id,
338 &schema.entry.annotations,
339 &mut self.state.writer,
340 )?;
341 }
342 self.registry
343 .register(id, (*schema.entry).clone())
344 .expect("schema registration failed");
345 self.schema_ids.insert(key, id);
346 Ok(id)
347 }
348
349 pub fn register_schema(
359 &mut self,
360 name: &str,
361 fields: Vec<crate::schema::FieldDef>,
362 ) -> io::Result<Schema> {
363 let schema = Schema::new(name, fields);
364 self.ensure_registered(&schema)?;
365 Ok(schema)
366 }
367
368 pub fn register_existing(&mut self, schema: &Schema) -> io::Result<WireTypeId> {
373 self.ensure_registered(schema)
374 }
375
376 pub fn write_event(
385 &mut self,
386 schema: &Schema,
387 values: &[crate::types::FieldValue],
388 ) -> io::Result<()> {
389 use crate::types::FieldValue;
390
391 let type_id = self.ensure_registered(schema)?;
392 let expected_fields = schema.entry.fields.len();
393
394 let ts_ns = match values.first() {
395 Some(FieldValue::Varint(ns)) => *ns,
396 _ => {
397 return Err(io::Error::new(
398 io::ErrorKind::InvalidInput,
399 "first value must be FieldValue::Varint(timestamp_ns)",
400 ));
401 }
402 };
403 let field_values = &values[1..];
404
405 if field_values.len() != expected_fields {
406 return Err(io::Error::new(
407 io::ErrorKind::InvalidInput,
408 format!(
409 "value count ({}) does not match schema field count ({}) for schema '{}'",
410 field_values.len(),
411 expected_fields,
412 schema.name(),
413 ),
414 ));
415 }
416
417 let ts_delta = self.state.encode_timestamp_delta(ts_ns)?;
418 self.state.writer.write_all(&[codec::TAG_EVENT])?;
419 self.state.writer.write_all(&type_id.0.to_le_bytes())?;
420 codec::encode_u24_le(ts_delta, &mut self.state.writer)?;
421 let mut enc = EventEncoder::new(&mut self.state);
422 for (i, v) in field_values.iter().enumerate() {
423 enc.write_field_value(v, schema.entry.fields[i].field_type)?;
424 }
425 Ok(())
426 }
427
428 pub fn write<T: TraceEvent + 'static>(&mut self, event: &T) -> io::Result<()> {
431 let slot = T::type_slot();
432 let tid = if slot != 0 && slot < crate::STATIC_WIRE_ID_LIMIT {
433 let word = (slot >> 6) as usize;
434 let bit = 1u64 << (slot & 63);
435 if self.registered_ids[word] & bit == 0 {
436 self.register_fast_id::<T>(slot)?;
437 }
438 WireTypeId(slot)
439 } else {
440 let s = slot as usize;
441 let cached = self.slot_cache.get(s).copied().unwrap_or(0);
442 if cached != 0 {
443 WireTypeId((cached - 1) as u16)
444 } else {
445 self.resolve_dynamic_wire_id::<T>(s)?
446 }
447 };
448 let ts_ns = event.timestamp();
449 let ts_delta = self.state.encode_timestamp_delta(ts_ns)?;
450 self.state.writer.write_all(&[codec::TAG_EVENT])?;
451 self.state.writer.write_all(&tid.0.to_le_bytes())?;
452 codec::encode_u24_le(ts_delta, &mut self.state.writer)?;
453 let mut enc = EventEncoder::new(&mut self.state);
454 event.encode_fields(&mut enc)
455 }
456
457 #[cold]
461 fn resolve_dynamic_wire_id<T: TraceEvent + 'static>(
462 &mut self,
463 slot: usize,
464 ) -> io::Result<WireTypeId> {
465 let key = SchemaKey::RustType(TypeId::of::<T>());
466 let tid = if let Some(&existing) = self.schema_ids.get(&key) {
467 existing
468 } else {
469 let schema = Schema::from_entry(T::schema_entry());
470 let id = self.ensure_registered(&schema)?;
471 self.schema_ids.insert(key, id);
472 id
473 };
474 if slot != 0 {
475 if self.slot_cache.len() <= slot {
476 self.slot_cache.resize(slot + 1, 0);
477 }
478 self.slot_cache[slot] = (tid.0 as u32) + 1;
479 }
480 Ok(tid)
481 }
482
483 #[cold]
486 fn register_fast_id<T: TraceEvent + 'static>(&mut self, id: u16) -> io::Result<()> {
487 let entry = T::schema_entry();
488 let wire = WireTypeId(id);
489 codec::encode_schema(wire, &entry, &mut self.state.writer)?;
490 if !entry.annotations.is_empty() {
491 codec::encode_schema_annotations(wire, &entry.annotations, &mut self.state.writer)?;
492 }
493 self.registry.register(wire, entry).map_err(|e| {
494 io::Error::new(
495 io::ErrorKind::InvalidInput,
496 format!("wire id {id} collision: {e}"),
497 )
498 })?;
499 self.registered_ids[(id >> 6) as usize] |= 1u64 << (id & 63);
501 Ok(())
502 }
503
504 pub fn intern_string(&mut self, s: &str) -> io::Result<InternedString> {
506 if let Some(&id) = self.string_pool.get(s) {
507 return Ok(InternedString(id));
508 }
509 let id = self.next_pool_id;
510 self.next_pool_id += 1;
511 self.string_pool.insert(s.to_string(), id);
512 codec::encode_string_pool(
513 &[PoolEntry {
514 pool_id: id,
515 data: s.as_bytes().to_vec(),
516 }],
517 &mut self.state.writer,
518 )?;
519 Ok(InternedString(id))
520 }
521
522 pub fn write_string_pool(&mut self, entries: &[PoolEntry]) -> io::Result<()> {
523 codec::encode_string_pool(entries, &mut self.state.writer)
524 }
525
526 pub fn intern_stack_frames(&mut self, frames: &[u64]) -> io::Result<InternedStackFrames> {
529 if let Some(&id) = self.stack_pool.get(frames) {
530 return Ok(InternedStackFrames(id));
531 }
532 let id = self.next_stack_pool_id;
533 self.next_stack_pool_id += 1;
534 self.stack_pool.insert(frames.into(), id);
535 codec::encode_stack_pool(
536 &[StackPoolEntry {
537 pool_id: id,
538 frames: frames.to_vec(),
541 }],
542 &mut self.state.writer,
543 )?;
544 Ok(InternedStackFrames(id))
545 }
546
547 pub fn write_stack_pool(&mut self, entries: &[StackPoolEntry]) -> io::Result<()> {
548 codec::encode_stack_pool(entries, &mut self.state.writer)
549 }
550
551 pub fn flush(&mut self) -> io::Result<()> {
553 self.state.writer.flush()
554 }
555
556 pub fn into_raw_encoder(self) -> RawEncoder<W> {
563 RawEncoder {
564 writer: self.state.writer,
565 }
566 }
567}
568
569pub struct RawEncoder<W> {
576 writer: CountingWriter<W>,
577}
578
579impl<W: Write> RawEncoder<W> {
580 pub fn write_raw(&mut self, bytes: &[u8]) -> io::Result<()> {
582 self.writer.write_all(bytes)
583 }
584
585 pub fn bytes_written(&self) -> u64 {
588 self.writer.bytes_written()
589 }
590
591 pub fn flush(&mut self) -> io::Result<()> {
593 self.writer.flush()
594 }
595
596 pub fn into_inner(self) -> W {
598 self.writer.into_inner()
599 }
600}
601
602impl Encoder<Vec<u8>> {
603 pub fn write_infallible<T: TraceEvent + 'static>(&mut self, event: &T) {
604 self.write(event).expect("writing to Vec<u8> is infallible")
605 }
606
607 pub fn intern_string_infallible(&mut self, s: &str) -> InternedString {
608 self.intern_string(s)
609 .expect("interning into Vec<u8> is infallible")
610 }
611
612 pub fn intern_stack_frames_infallible(&mut self, frames: &[u64]) -> InternedStackFrames {
613 self.intern_stack_frames(frames)
614 .expect("interning into Vec<u8> is infallible")
615 }
616
617 pub fn reset_to_infallible(&mut self, data: Vec<u8>) -> Vec<u8> {
619 self.reset_to(data)
620 .expect("writing to Vec<u8> is infallible")
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627 use crate::schema::FieldDef;
628 use crate::types::{FieldType, FieldValue};
629
630 #[test]
631 fn encoder_writes_header() {
632 let enc = Encoder::new();
633 let data = enc.finish();
634 assert_eq!(&data[..5], &[0x54, 0x52, 0x43, 0x00, 1]);
635 }
636
637 #[test]
638 fn encoder_register_and_write_event() {
639 let mut enc = Encoder::new();
640 let schema = enc
641 .register_schema(
642 "Ev",
643 vec![FieldDef {
644 name: "v".into(),
645 field_type: FieldType::Varint,
646 }],
647 )
648 .unwrap();
649 enc.write_event(
650 &schema,
651 &[FieldValue::Varint(1_000), FieldValue::Varint(42)],
652 )
653 .unwrap();
654 let data = enc.finish();
655 assert!(data.len() > 5);
656 }
657
658 #[test]
659 fn idempotent_re_registration() {
660 let mut enc = Encoder::new();
661 let fields = vec![FieldDef {
662 name: "v".into(),
663 field_type: FieldType::Varint,
664 }];
665 let _s1 = enc.register_schema("Ev", fields.clone()).unwrap();
666 let _s2 = enc.register_schema("Ev", fields).unwrap();
667 }
669
670 #[test]
671 fn re_registration_different_schema_errors() {
672 let mut enc = Encoder::new();
673 enc.register_schema(
674 "Ev",
675 vec![FieldDef {
676 name: "v".into(),
677 field_type: FieldType::Varint,
678 }],
679 )
680 .unwrap();
681 let result = enc.register_schema(
682 "Ev",
683 vec![FieldDef {
684 name: "different".into(),
685 field_type: FieldType::Bool,
686 }],
687 );
688 assert!(result.is_err());
689 }
690
691 #[test]
692 fn schema_auto_registers_on_write() {
693 use crate::decoder::{DecodedFrame, Decoder};
694
695 let schema = Schema::new(
697 "Lazy",
698 vec![FieldDef {
699 name: "v".into(),
700 field_type: FieldType::Varint,
701 }],
702 );
703
704 let mut enc = Encoder::new();
706 enc.write_event(
707 &schema,
708 &[FieldValue::Varint(1_000), FieldValue::Varint(42)],
709 )
710 .unwrap();
711
712 let bytes = enc.finish();
713 let mut dec = Decoder::new(&bytes).unwrap();
714 let frames = dec.decode_all();
715 assert!(matches!(&frames[0], DecodedFrame::Schema(s) if s.name == "Lazy"));
716 if let DecodedFrame::Event { values, .. } = &frames[1] {
717 assert_eq!(*values, vec![FieldValue::Varint(42)]);
718 } else {
719 panic!("expected event");
720 }
721 }
722
723 #[test]
724 fn schema_portable_across_encoders() {
725 use crate::decoder::{DecodedFrame, Decoder};
726
727 let mut enc1 = Encoder::new();
728 let schema = enc1
729 .register_schema(
730 "Shared",
731 vec![FieldDef {
732 name: "v".into(),
733 field_type: FieldType::Varint,
734 }],
735 )
736 .unwrap();
737 enc1.write_event(&schema, &[FieldValue::Varint(1_000), FieldValue::Varint(1)])
738 .unwrap();
739
740 let mut enc2 = Encoder::new();
742 enc2.write_event(&schema, &[FieldValue::Varint(2_000), FieldValue::Varint(2)])
743 .unwrap();
744
745 for (enc, expected_val) in [(enc1, 1u64), (enc2, 2u64)] {
747 let bytes = enc.finish();
748 let mut dec = Decoder::new(&bytes).unwrap();
749 let frames = dec.decode_all();
750 let event = frames
751 .iter()
752 .find(|f| matches!(f, DecodedFrame::Event { .. }))
753 .unwrap();
754 if let DecodedFrame::Event { values, .. } = event {
755 assert_eq!(values[0], FieldValue::Varint(expected_val));
756 }
757 }
758 }
759
760 #[test]
761 fn encoder_intern_string_deduplicates() {
762 let mut enc = Encoder::new();
763 let id1 = enc.intern_string("hello").unwrap();
764 let id2 = enc.intern_string("hello").unwrap();
765 let id3 = enc.intern_string("world").unwrap();
766 assert_eq!(id1, id2);
767 assert_ne!(id1, id3);
768 }
769
770 #[test]
771 fn encoder_intern_stack_frames_deduplicates() {
772 let mut enc = Encoder::new();
773 let stack_a: &[u64] = &[0x1000, 0x2000, 0x3000];
774 let stack_b: &[u64] = &[0x4000, 0x5000];
775 let id1 = enc.intern_stack_frames(stack_a).unwrap();
776 let id2 = enc.intern_stack_frames(stack_a).unwrap();
777 let id3 = enc.intern_stack_frames(stack_b).unwrap();
778 assert_eq!(id1, id2);
779 assert_ne!(id1, id3);
780 }
781
782 #[test]
783 fn stack_pool_round_trip_via_decoder() {
784 use crate::decoder::Decoder;
785 use crate::types::InternedStackFrames;
786
787 let mut enc = Encoder::new();
788 let stack_a: &[u64] = &[0xdead, 0xbeef, 0xcafe];
789 let stack_b: &[u64] = &[0x1, 0x2];
790 let id_a = enc.intern_stack_frames(stack_a).unwrap();
791 let id_b = enc.intern_stack_frames(stack_b).unwrap();
792 let bytes = enc.finish();
793
794 let mut dec = Decoder::new(&bytes).unwrap();
795 let _ = dec.decode_all();
796 assert_eq!(
797 dec.stack_pool().get(InternedStackFrames(id_a.raw_id())),
798 Some(stack_a)
799 );
800 assert_eq!(
801 dec.stack_pool().get(InternedStackFrames(id_b.raw_id())),
802 Some(stack_b)
803 );
804 }
805
806 #[test]
807 fn for_each_event_populates_stack_pool() {
808 use crate::decoder::Decoder;
809 use crate::schema::FieldDef;
810 use crate::types::{FieldType, FieldValue, InternedStackFrames};
811
812 let mut enc = Encoder::new();
813 let schema = enc
814 .register_schema(
815 "CpuSampleEvent",
816 vec![FieldDef {
817 name: "callchain".into(),
818 field_type: FieldType::PooledStackFrames,
819 }],
820 )
821 .unwrap();
822 let stack: &[u64] = &[0x1234, 0x5678, 0x9abc];
823 let id = enc.intern_stack_frames(stack).unwrap();
824 enc.write_event(
825 &schema,
826 &[
827 FieldValue::Varint(1_000_000),
828 FieldValue::PooledStackFrames(id),
829 ],
830 )
831 .unwrap();
832 let bytes = enc.finish();
833
834 let mut dec = Decoder::new(&bytes).unwrap();
835 let mut event_count = 0;
836 dec.for_each_event(|_ev| {
837 event_count += 1;
838 })
839 .unwrap();
840 assert_eq!(event_count, 1);
841 assert_eq!(
842 dec.stack_pool().get(InternedStackFrames(id.raw_id())),
843 Some(stack),
844 );
845 }
846
847 #[test]
848 fn encoder_intern_empty_stack_frames() {
849 use crate::decoder::Decoder;
850 use crate::types::InternedStackFrames;
851
852 let mut enc = Encoder::new();
853 let id1 = enc.intern_stack_frames(&[]).unwrap();
854 let id2 = enc.intern_stack_frames(&[]).unwrap();
855 assert_eq!(id1, id2);
856 let bytes = enc.finish();
857
858 let mut dec = Decoder::new(&bytes).unwrap();
859 let _ = dec.decode_all();
860 assert_eq!(
861 dec.stack_pool().get(InternedStackFrames(id1.raw_id())),
862 Some(&[][..])
863 );
864 }
865
866 #[test]
867 fn write_stack_pool_multi_entry_round_trip() {
868 use crate::decoder::Decoder;
869 use crate::types::InternedStackFrames;
870
871 let mut enc = Encoder::new();
872 let entries = vec![
873 StackPoolEntry {
874 pool_id: 0,
875 frames: vec![0xaaaa, 0xbbbb, 0xcccc],
876 },
877 StackPoolEntry {
878 pool_id: 1,
879 frames: vec![0x1111],
880 },
881 StackPoolEntry {
882 pool_id: 2,
883 frames: vec![],
884 },
885 ];
886 enc.write_stack_pool(&entries).unwrap();
887 let bytes = enc.finish();
888
889 let mut dec = Decoder::new(&bytes).unwrap();
890 let _ = dec.decode_all();
891 assert_eq!(
892 dec.stack_pool().get(InternedStackFrames(0)),
893 Some(&[0xaaaa, 0xbbbb, 0xcccc][..])
894 );
895 assert_eq!(
896 dec.stack_pool().get(InternedStackFrames(1)),
897 Some(&[0x1111][..])
898 );
899 assert_eq!(dec.stack_pool().get(InternedStackFrames(2)), Some(&[][..]));
900 }
901
902 #[test]
903 fn decoder_into_encoder_deduplicates_interned_stack_frames() {
904 use crate::decoder::Decoder;
905
906 let mut enc = Encoder::new();
907 let id1 = enc.intern_stack_frames(&[0x10, 0x20]).unwrap();
908 let base = enc.finish();
909
910 let mut decoder = Decoder::new(&base).unwrap();
911 while decoder.next_frame_ref().ok().flatten().is_some() {}
912 let mut output = Vec::new();
913 let mut ext = decoder.into_encoder(&mut output);
914 let id2 = ext.intern_stack_frames(&[0x10, 0x20]).unwrap();
915 let id3 = ext.intern_stack_frames(&[0x30]).unwrap();
916 assert_eq!(id1.raw_id(), id2.raw_id());
917 assert_ne!(id2.raw_id(), id3.raw_id());
918 }
919
920 #[test]
921 fn timestamp_round_trip() {
922 use crate::decoder::{DecodedFrame, Decoder};
923
924 let mut enc = Encoder::new();
925 let schema = enc
926 .register_schema(
927 "TS",
928 vec![FieldDef {
929 name: "v".into(),
930 field_type: FieldType::Varint,
931 }],
932 )
933 .unwrap();
934
935 let ts1 = 100_000u64;
936 let ts2 = 50_000u64;
937 let ts3 = 200_000_000u64;
938 let ts4 = 100_000_000u64;
939 enc.write_event(&schema, &[FieldValue::Varint(ts1), FieldValue::Varint(1)])
940 .unwrap();
941 enc.write_event(&schema, &[FieldValue::Varint(ts2), FieldValue::Varint(2)])
942 .unwrap();
943 enc.write_event(&schema, &[FieldValue::Varint(ts3), FieldValue::Varint(3)])
944 .unwrap();
945 enc.write_event(&schema, &[FieldValue::Varint(ts4), FieldValue::Varint(4)])
946 .unwrap();
947
948 let bytes = enc.finish();
949 let mut dec = Decoder::new(&bytes).unwrap();
950 let events: Vec<_> = dec
951 .decode_all()
952 .into_iter()
953 .filter_map(|f| match f {
954 DecodedFrame::Event {
955 timestamp_ns,
956 values,
957 ..
958 } => Some((timestamp_ns, values)),
959 _ => None,
960 })
961 .collect();
962
963 assert_eq!(events.len(), 4);
964 assert_eq!(events[0].0, Some(ts1));
965 assert_eq!(events[0].1, vec![FieldValue::Varint(1)]);
966 assert_eq!(events[1].0, Some(ts2));
967 assert_eq!(events[1].1, vec![FieldValue::Varint(2)]);
968 assert_eq!(events[2].0, Some(ts3));
969 assert_eq!(events[2].1, vec![FieldValue::Varint(3)]);
970 assert_eq!(events[3].0, Some(ts4));
971 assert_eq!(events[3].1, vec![FieldValue::Varint(4)]);
972 }
973
974 #[test]
975 fn encoder_new_to_writer() {
976 let mut buf = Vec::new();
977 let enc = Encoder::new_to(&mut buf).unwrap();
978 drop(enc);
979 assert!(buf.len() >= 5);
980 assert_eq!(&buf[..5], &[0x54, 0x52, 0x43, 0x00, 1]);
981 }
982
983 #[test]
984 fn decoder_into_encoder_appends_without_header() {
985 use crate::decoder::{DecodedFrame, Decoder};
986
987 let mut enc = Encoder::new();
989 let schema = enc
990 .register_schema(
991 "Ev",
992 vec![FieldDef {
993 name: "v".into(),
994 field_type: FieldType::Varint,
995 }],
996 )
997 .unwrap();
998 enc.write_event(&schema, &[FieldValue::Varint(1_000), FieldValue::Varint(1)])
999 .unwrap();
1000 let base = enc.finish();
1001
1002 let mut decoder = Decoder::new(&base).unwrap();
1004 while decoder.next_frame_ref().ok().flatten().is_some() {}
1005 let mut output = Vec::new();
1006 let mut ext = decoder.into_encoder(&mut output);
1007 ext.write_event(&schema, &[FieldValue::Varint(2_000), FieldValue::Varint(2)])
1009 .unwrap();
1010 drop(ext);
1011
1012 let mut combined = base.clone();
1014 combined.extend_from_slice(&output);
1015 let mut dec = Decoder::new(&combined).unwrap();
1016 let events: Vec<_> = dec
1017 .decode_all()
1018 .into_iter()
1019 .filter_map(|f| match f {
1020 DecodedFrame::Event {
1021 timestamp_ns,
1022 values,
1023 ..
1024 } => Some((timestamp_ns, values)),
1025 _ => None,
1026 })
1027 .collect();
1028 assert_eq!(events.len(), 2);
1029 assert_eq!(events[0].0, Some(1_000));
1030 assert_eq!(events[1].0, Some(2_000));
1031 }
1032
1033 #[test]
1034 fn decoder_into_encoder_deduplicates_interned_strings() {
1035 use crate::decoder::{DecodedFrame, Decoder};
1036
1037 let mut enc = Encoder::new();
1039 let id1 = enc.intern_string("hello").unwrap();
1040 let base = enc.finish();
1041
1042 let mut decoder = Decoder::new(&base).unwrap();
1044 while decoder.next_frame_ref().ok().flatten().is_some() {}
1045 let mut output = Vec::new();
1046 let mut ext = decoder.into_encoder(&mut output);
1047 let id2 = ext.intern_string("hello").unwrap();
1049 let id3 = ext.intern_string("world").unwrap();
1050 drop(ext);
1051
1052 assert_eq!(id1, id2, "existing string should reuse pool ID");
1053 assert_ne!(id2, id3);
1054
1055 let mut combined = base.clone();
1057 combined.extend_from_slice(&output);
1058 let mut dec = Decoder::new(&combined).unwrap();
1059 let frames = dec.decode_all();
1060 let pool_frames: Vec<_> = frames
1061 .iter()
1062 .filter(|f| matches!(f, DecodedFrame::StringPool(_)))
1063 .collect();
1064 assert_eq!(pool_frames.len(), 2);
1066 }
1067
1068 struct FastSlot {
1071 ts: u64,
1072 }
1073 impl TraceEvent for FastSlot {
1074 fn type_slot() -> u16 {
1075 5
1076 }
1077 fn event_name() -> &'static str {
1078 "FastSlot"
1079 }
1080 fn field_defs() -> Vec<FieldDef> {
1081 Vec::new()
1082 }
1083 fn timestamp(&self) -> u64 {
1084 self.ts
1085 }
1086 fn encode_fields<W: Write>(&self, _enc: &mut EventEncoder<'_, W>) -> io::Result<()> {
1087 Ok(())
1088 }
1089 }
1090
1091 #[test]
1092 fn fast_slot_registers_at_slot_id() {
1093 use crate::decoder::Decoder;
1094
1095 let mut enc = Encoder::new();
1096 enc.write(&FastSlot { ts: 1_000_000 }).unwrap();
1097 let dynamic = enc
1099 .register_schema(
1100 "Dyn",
1101 vec![FieldDef {
1102 name: "v".into(),
1103 field_type: FieldType::Varint,
1104 }],
1105 )
1106 .unwrap();
1107 enc.write_event(
1108 &dynamic,
1109 &[FieldValue::Varint(2_000), FieldValue::Varint(1)],
1110 )
1111 .unwrap();
1112 let bytes = enc.finish();
1113
1114 let mut dec = Decoder::new(&bytes).unwrap();
1115 let _ = dec.decode_all();
1116 assert_eq!(
1118 dec.registry().get(WireTypeId(5)).unwrap().name(),
1119 "FastSlot"
1120 );
1121 assert_eq!(
1123 dec.registry()
1124 .get(WireTypeId(crate::STATIC_WIRE_ID_LIMIT))
1125 .unwrap()
1126 .name(),
1127 "Dyn"
1128 );
1129 }
1130
1131 #[test]
1132 fn register_and_write() {
1133 use crate::decoder::{DecodedFrame, Decoder};
1134
1135 let mut enc = Encoder::new();
1136 let schema = enc
1137 .register_schema(
1138 "MyEvent",
1139 vec![
1140 FieldDef {
1141 name: "count".into(),
1142 field_type: FieldType::Varint,
1143 },
1144 FieldDef {
1145 name: "name".into(),
1146 field_type: FieldType::String,
1147 },
1148 ],
1149 )
1150 .unwrap();
1151
1152 enc.write_event(
1153 &schema,
1154 &[
1155 FieldValue::Varint(1_000_000),
1156 FieldValue::Varint(42),
1157 FieldValue::String("hello".into()),
1158 ],
1159 )
1160 .unwrap();
1161
1162 let bytes = enc.finish();
1163 let mut dec = Decoder::new(&bytes).unwrap();
1164 let frames = dec.decode_all();
1165 let events: Vec<_> = frames
1166 .into_iter()
1167 .filter_map(|f| match f {
1168 DecodedFrame::Event {
1169 timestamp_ns,
1170 values,
1171 ..
1172 } => Some((timestamp_ns, values)),
1173 _ => None,
1174 })
1175 .collect();
1176 assert_eq!(events.len(), 1);
1177 assert_eq!(events[0].0, Some(1_000_000));
1178 assert_eq!(events[0].1[0], FieldValue::Varint(42));
1179 assert_eq!(events[0].1[1], FieldValue::String("hello".into()));
1180 }
1181
1182 #[test]
1183 fn register_conflict_errors() {
1184 let mut enc = Encoder::new();
1185 enc.register_schema(
1186 "Ev",
1187 vec![FieldDef {
1188 name: "v".into(),
1189 field_type: FieldType::Varint,
1190 }],
1191 )
1192 .unwrap();
1193 let result = enc.register_schema(
1194 "Ev",
1195 vec![FieldDef {
1196 name: "other".into(),
1197 field_type: FieldType::Bool,
1198 }],
1199 );
1200 assert!(result.is_err());
1201 }
1202
1203 #[test]
1204 fn write_wrong_field_count_errors() {
1205 let mut enc = Encoder::new();
1206 let schema = enc
1207 .register_schema(
1208 "Ev",
1209 vec![FieldDef {
1210 name: "v".into(),
1211 field_type: FieldType::Varint,
1212 }],
1213 )
1214 .unwrap();
1215 let result = enc.write_event(
1217 &schema,
1218 &[
1219 FieldValue::Varint(0),
1220 FieldValue::Varint(1),
1221 FieldValue::Varint(2),
1222 ],
1223 );
1224 assert!(result.is_err());
1225 }
1226
1227 #[test]
1230 fn timestamp_base_advances_per_event() {
1231 use crate::decoder::{DecodedFrame, Decoder};
1232
1233 let mut enc = Encoder::new();
1234 let schema = enc
1235 .register_schema(
1236 "Ev",
1237 vec![FieldDef {
1238 name: "v".into(),
1239 field_type: FieldType::Varint,
1240 }],
1241 )
1242 .unwrap();
1243
1244 let ts1 = 12_000_000u64;
1245 let ts2 = 24_000_000u64;
1246 enc.write_event(&schema, &[FieldValue::Varint(ts1), FieldValue::Varint(1)])
1247 .unwrap();
1248 enc.write_event(&schema, &[FieldValue::Varint(ts2), FieldValue::Varint(2)])
1249 .unwrap();
1250
1251 let bytes = enc.finish();
1252
1253 let reset_count = bytes.iter().filter(|&&b| b == 0x05).count();
1254 assert_eq!(
1255 reset_count, 0,
1256 "base should advance per event, avoiding unnecessary resets"
1257 );
1258
1259 let mut dec = Decoder::new(&bytes).unwrap();
1260 let events: Vec<_> = dec
1261 .decode_all()
1262 .into_iter()
1263 .filter_map(|f| match f {
1264 DecodedFrame::Event { timestamp_ns, .. } => timestamp_ns,
1265 _ => None,
1266 })
1267 .collect();
1268 assert_eq!(events, vec![ts1, ts2]);
1269 }
1270
1271 #[test]
1272 fn reset_to_preserves_capacity() {
1273 let mut enc = Encoder::new();
1274 for i in 0..100 {
1275 enc.intern_string(&format!("string_{}", i)).unwrap();
1276 }
1277 let cap_before = enc.string_pool.capacity();
1278 let _bytes = enc.reset_to(Vec::new());
1279 let cap_after = enc.string_pool.capacity();
1280 assert_eq!(
1281 cap_before, cap_after,
1282 "string_pool capacity should be preserved after reset_to"
1283 );
1284 }
1285
1286 #[test]
1287 fn reset_to_returns_old_data_and_clears_state() {
1288 use crate::decoder::{DecodedFrame, Decoder};
1289
1290 let mut enc = Encoder::new();
1291 let schema = enc
1292 .register_schema(
1293 "Ev",
1294 vec![FieldDef {
1295 name: "v".into(),
1296 field_type: FieldType::Varint,
1297 }],
1298 )
1299 .unwrap();
1300 enc.write_event(
1301 &schema,
1302 &[FieldValue::Varint(1_000), FieldValue::Varint(42)],
1303 )
1304 .unwrap();
1305 let _s = enc.intern_string("hello").unwrap();
1306
1307 let old_bytes_written = enc.bytes_written();
1308 assert!(old_bytes_written > 0);
1309
1310 let old = enc.reset_to_infallible(Vec::new());
1312
1313 let mut dec = Decoder::new(&old).unwrap();
1315 let frames = dec.decode_all();
1316 assert!(frames.iter().any(|f| matches!(f, DecodedFrame::Schema(_))));
1317 assert!(
1318 frames
1319 .iter()
1320 .any(|f| matches!(f, DecodedFrame::Event { .. }))
1321 );
1322 assert!(
1323 frames
1324 .iter()
1325 .any(|f| matches!(f, DecodedFrame::StringPool(_)))
1326 );
1327
1328 assert!(
1330 enc.bytes_written() < old_bytes_written,
1331 "bytes_written should reset (got {} vs old {})",
1332 enc.bytes_written(),
1333 old_bytes_written
1334 );
1335
1336 enc.write_event(
1339 &schema,
1340 &[FieldValue::Varint(2_000), FieldValue::Varint(99)],
1341 )
1342 .unwrap();
1343
1344 let _s2 = enc.intern_string("hello").unwrap();
1346
1347 let new_bytes = enc.reset_to_infallible(Vec::new());
1349 let mut dec2 = Decoder::new(&new_bytes).unwrap();
1350 let new_frames = dec2.decode_all();
1351 assert!(
1353 new_frames
1354 .iter()
1355 .any(|f| matches!(f, DecodedFrame::Schema(s) if s.name == "Ev")),
1356 "new trace must contain schema definition"
1357 );
1358 assert!(
1360 new_frames
1361 .iter()
1362 .any(|f| matches!(f, DecodedFrame::StringPool(_))),
1363 "new trace must contain string pool"
1364 );
1365 let event = new_frames
1367 .iter()
1368 .find_map(|f| match f {
1369 DecodedFrame::Event {
1370 timestamp_ns,
1371 values,
1372 ..
1373 } => Some((timestamp_ns, values)),
1374 _ => None,
1375 })
1376 .expect("new trace must contain event");
1377 assert_eq!(*event.0, Some(2_000));
1378 assert_eq!(event.1[0], FieldValue::Varint(99));
1379 }
1380
1381 #[test]
1382 fn into_raw_encoder_preserves_byte_count() {
1383 let mut enc = Encoder::new();
1384 let schema = enc
1385 .register_schema(
1386 "Ev",
1387 vec![FieldDef {
1388 name: "v".into(),
1389 field_type: FieldType::Varint,
1390 }],
1391 )
1392 .unwrap();
1393 enc.write_event(
1394 &schema,
1395 &[FieldValue::Varint(1_000), FieldValue::Varint(42)],
1396 )
1397 .unwrap();
1398
1399 let bytes_before = enc.bytes_written();
1400 assert!(bytes_before > 0);
1401
1402 let raw = enc.into_raw_encoder();
1403 assert_eq!(
1404 raw.bytes_written(),
1405 bytes_before,
1406 "byte count must be preserved across conversion"
1407 );
1408 }
1409
1410 #[test]
1411 fn raw_encoder_write_raw_and_bytes_written() {
1412 let enc = Encoder::new();
1413 let initial = enc.bytes_written();
1414 let mut raw = enc.into_raw_encoder();
1415
1416 let payload = [0xAA; 100];
1417 raw.write_raw(&payload).unwrap();
1418
1419 assert_eq!(
1420 raw.bytes_written(),
1421 initial + payload.len() as u64,
1422 "bytes_written must include raw payload"
1423 );
1424 }
1425
1426 #[test]
1427 fn raw_encoder_into_inner_returns_all_data() {
1428 use crate::decoder::{DecodedFrame, Decoder};
1429
1430 let mut enc = Encoder::new();
1433 let schema = enc
1434 .register_schema(
1435 "Ev",
1436 vec![FieldDef {
1437 name: "v".into(),
1438 field_type: FieldType::Varint,
1439 }],
1440 )
1441 .unwrap();
1442 enc.write_event(&schema, &[FieldValue::Varint(1_000), FieldValue::Varint(1)])
1443 .unwrap();
1444
1445 let raw_batch = {
1447 let mut batch_enc = Encoder::new();
1448 batch_enc
1449 .write_event(&schema, &[FieldValue::Varint(2_000), FieldValue::Varint(2)])
1450 .unwrap();
1451 batch_enc.finish()
1452 };
1453
1454 let mut raw = enc.into_raw_encoder();
1455 raw.write_raw(&raw_batch).unwrap();
1456 let combined = raw.into_inner();
1457
1458 let mut dec = Decoder::new(&combined).unwrap();
1459 let events: Vec<_> = dec
1460 .decode_all()
1461 .into_iter()
1462 .filter_map(|f| match f {
1463 DecodedFrame::Event {
1464 timestamp_ns,
1465 values,
1466 ..
1467 } => Some((timestamp_ns, values)),
1468 _ => None,
1469 })
1470 .collect();
1471
1472 assert_eq!(events.len(), 2);
1473 assert_eq!(events[0].0, Some(1_000));
1474 assert_eq!(events[0].1, vec![FieldValue::Varint(1)]);
1475 assert_eq!(events[1].0, Some(2_000));
1476 assert_eq!(events[1].1, vec![FieldValue::Varint(2)]);
1477 }
1478}