1use crate::codec::{
10 self, Frame, FrameRef, HEADER_SIZE, PoolEntry, PoolEntryRef, SchemaInfo, StackPoolEntry,
11 StackPoolEntryRef, WireTypeId,
12};
13use crate::schema::{SchemaEntry, SchemaRegistry};
14use crate::types::{FieldType, FieldValueRef, InternedStackFrames, InternedString, StackFrames};
15use std::collections::HashMap;
16use std::fmt;
17
18#[derive(Debug, Clone)]
22pub struct DecodeError {
23 pub pos: usize,
24 pub message: String,
25}
26
27impl fmt::Display for DecodeError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "decode error at byte {}: {}", self.pos, self.message)
30 }
31}
32
33impl std::error::Error for DecodeError {}
34
35#[derive(Debug)]
37pub enum TryForEachError<E> {
38 Decode(DecodeError),
39 User(E),
40}
41
42impl<E: fmt::Display> fmt::Display for TryForEachError<E> {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 TryForEachError::Decode(e) => write!(f, "{e}"),
46 TryForEachError::User(e) => write!(f, "{e}"),
47 }
48 }
49}
50
51impl<E: fmt::Display + fmt::Debug> std::error::Error for TryForEachError<E> {}
52
53#[non_exhaustive]
58pub struct RawEvent<'a, 'f> {
59 pub type_id: WireTypeId,
60 pub name: &'f str,
61 pub timestamp_ns: u64,
62 pub fields: &'f [FieldValueRef<'a>],
63 pub schema: &'f SchemaEntry,
64 pub string_pool: &'f StringPool,
65 pub stack_pool: &'f StackPool,
66}
67
68impl<'a, 'f> RawEvent<'a, 'f> {
69 pub fn field_names(&self) -> impl Iterator<Item = &'f str> {
71 self.schema.fields.iter().map(|f| f.name.as_str())
72 }
73
74 #[cfg(feature = "serde-deserialize")]
89 pub fn deserialize<E: serde::de::DeserializeOwned>(&self) -> Result<E, crate::de::DeserError> {
90 crate::de::from_raw_event(self)
91 }
92}
93
94#[derive(Debug, Default)]
100pub struct StringPool(pub(crate) HashMap<InternedString, String>);
101
102impl StringPool {
103 pub(crate) fn new() -> Self {
104 Self(HashMap::default())
105 }
106
107 pub(crate) fn insert(&mut self, id: InternedString, value: String) {
108 self.0.insert(id, value);
109 }
110
111 pub fn get(&self, id: InternedString) -> Option<&str> {
112 self.0.get(&id).map(|s| s.as_str())
113 }
114
115 pub fn len(&self) -> usize {
116 self.0.len()
117 }
118
119 pub fn is_empty(&self) -> bool {
120 self.0.is_empty()
121 }
122
123 pub fn iter(&self) -> impl Iterator<Item = (InternedString, &str)> {
125 self.0.iter().map(|(&id, v)| (id, v.as_str()))
126 }
127}
128
129#[derive(Debug, Default)]
133pub struct StackPool(pub(crate) HashMap<InternedStackFrames, Vec<u64>>);
134
135impl StackPool {
136 pub(crate) fn new() -> Self {
137 Self(HashMap::default())
138 }
139
140 pub(crate) fn insert(&mut self, id: InternedStackFrames, frames: StackFrames) {
141 self.0.insert(id, frames.0);
142 }
143
144 pub fn get(&self, id: InternedStackFrames) -> Option<&[u64]> {
145 self.0.get(&id).map(|v| v.as_slice())
146 }
147
148 pub fn len(&self) -> usize {
149 self.0.len()
150 }
151
152 pub fn is_empty(&self) -> bool {
153 self.0.is_empty()
154 }
155
156 pub fn iter(&self) -> impl Iterator<Item = (InternedStackFrames, &[u64])> {
158 self.0.iter().map(|(&id, v)| (id, v.as_slice()))
159 }
160}
161
162#[derive(Debug, Clone, PartialEq)]
164pub enum DecodedFrame {
165 Schema(SchemaEntry),
166 Event {
167 type_id: WireTypeId,
168 timestamp_ns: u64,
170 values: Vec<crate::types::FieldValue>,
171 },
172 StringPool(Vec<PoolEntry>),
173 StackPool(Vec<StackPoolEntry>),
174 SchemaAnnotations {
175 type_id: WireTypeId,
176 annotations: Vec<crate::schema::FieldAnnotation>,
177 },
178}
179
180#[derive(Debug, Clone, PartialEq)]
182pub enum DecodedFrameRef<'a> {
183 Schema(SchemaEntry),
184 Event {
185 type_id: WireTypeId,
186 timestamp_ns: u64,
187 values: Vec<FieldValueRef<'a>>,
188 },
189 StringPool(Vec<PoolEntryRef<'a>>),
190 StackPool(Vec<StackPoolEntryRef<'a>>),
191 SchemaAnnotations {
192 type_id: WireTypeId,
193 annotations: Vec<crate::schema::FieldAnnotation>,
194 },
195}
196
197struct SchemaCache {
198 entry: SchemaEntry,
199 field_tags: Vec<u8>,
201 has_timestamp_on_wire: bool,
203}
204
205pub struct Decoder<'a> {
210 data: &'a [u8],
211 pos: usize,
212 registry: SchemaRegistry,
213 schema_cache: Vec<Option<SchemaCache>>,
214 string_pool: StringPool,
215 stack_pool: StackPool,
216 version: u8,
217 timestamp_base_ns: u64,
218}
219
220impl<'a> Decoder<'a> {
221 pub fn new(data: &'a [u8]) -> Option<Self> {
222 let version = codec::decode_header(data)?;
223 Some(Self {
224 data,
225 pos: HEADER_SIZE,
226 registry: SchemaRegistry::new(),
227 schema_cache: Vec::new(),
228 string_pool: StringPool::new(),
229 stack_pool: StackPool::new(),
230 version,
231 timestamp_base_ns: 0,
232 })
233 }
234
235 pub fn registry(&self) -> &SchemaRegistry {
236 &self.registry
237 }
238
239 pub fn version(&self) -> u8 {
240 self.version
241 }
242
243 pub fn position(&self) -> usize {
249 self.pos
250 }
251
252 pub fn data_len(&self) -> usize {
254 self.data.len()
255 }
256
257 pub fn string_pool(&self) -> &StringPool {
258 &self.string_pool
259 }
260
261 pub fn stack_pool(&self) -> &StackPool {
262 &self.stack_pool
263 }
264
265 fn reset_state(&mut self) {
269 self.registry = SchemaRegistry::new();
270 self.schema_cache.clear();
271 self.string_pool = StringPool::new();
272 self.stack_pool = StackPool::new();
273 self.timestamp_base_ns = 0;
274 }
275
276 fn try_consume_reset_header(&mut self) -> bool {
279 if self.pos + HEADER_SIZE <= self.data.len()
280 && codec::decode_header(&self.data[self.pos..]).is_some()
281 {
282 self.reset_state();
283 self.pos += HEADER_SIZE;
284 true
285 } else {
286 false
287 }
288 }
289
290 pub fn into_encoder<W: std::io::Write>(self, writer: W) -> crate::encoder::Encoder<W> {
297 crate::encoder::Encoder::from_decoder(
298 self.registry,
299 self.string_pool,
300 self.stack_pool,
301 self.timestamp_base_ns,
302 writer,
303 )
304 }
305
306 pub(crate) fn schema_info(&self, type_id: WireTypeId) -> Option<SchemaInfo<'_>> {
307 self.schema_cache
308 .get(type_id.0 as usize)
309 .and_then(|s| s.as_ref())
310 .map(|c| SchemaInfo {
311 field_tags: &c.field_tags,
312 has_timestamp_on_wire: c.has_timestamp_on_wire,
313 })
314 }
315
316 fn register_schema(
317 &mut self,
318 type_id: WireTypeId,
319 entry: SchemaEntry,
320 has_timestamp_on_wire: bool,
321 ) -> Result<(), String> {
322 let idx = type_id.0 as usize;
323 if idx >= self.schema_cache.len() {
324 self.schema_cache.resize_with(idx + 1, || None);
325 }
326 self.schema_cache[idx] = Some(SchemaCache {
327 field_tags: entry.fields.iter().map(|f| f.field_type as u8).collect(),
328 entry: entry.clone(),
329 has_timestamp_on_wire,
330 });
331 self.registry.register(type_id, entry)
332 }
333
334 pub fn next_frame(&mut self) -> Result<Option<DecodedFrame>, DecodeError> {
338 if self.pos >= self.data.len() {
339 return Ok(None);
340 }
341 if self.try_consume_reset_header() {
342 return self.next_frame();
343 }
344 let remaining = &self.data[self.pos..];
345 let base = self.timestamp_base_ns;
346 let (frame, consumed) =
347 match codec::decode_frame(remaining, |type_id| self.schema_info(type_id), base) {
348 Some(r) => r,
349 None => return Ok(None),
350 };
351 self.pos += consumed;
352 match frame {
353 Frame::Schema {
354 type_id,
355 entry,
356 has_timestamp_on_wire,
357 } => {
358 let result = DecodedFrame::Schema(entry.clone());
359 self.register_schema(type_id, entry, has_timestamp_on_wire)
360 .map_err(|msg| DecodeError {
361 pos: self.pos,
362 message: msg,
363 })?;
364 Ok(Some(result))
365 }
366 Frame::Event {
367 type_id,
368 timestamp_ns,
369 values,
370 } => {
371 self.timestamp_base_ns = timestamp_ns;
372 Ok(Some(DecodedFrame::Event {
373 type_id,
374 timestamp_ns,
375 values,
376 }))
377 }
378 Frame::StringPool(entries) => {
379 for e in &entries {
380 if let Ok(s) = String::from_utf8(e.data.clone()) {
381 self.string_pool.insert(InternedString(e.pool_id), s);
382 }
383 }
384 Ok(Some(DecodedFrame::StringPool(entries)))
385 }
386 Frame::StackPool(entries) => {
387 for e in &entries {
388 self.stack_pool
389 .insert(InternedStackFrames(e.pool_id), e.frames.clone().into());
390 }
391 Ok(Some(DecodedFrame::StackPool(entries)))
392 }
393 Frame::TimestampReset(ts) => {
394 self.timestamp_base_ns = ts;
395 self.next_frame() }
397 Frame::SchemaAnnotations {
398 type_id,
399 annotations,
400 } => {
401 if let Some(cache) = self
403 .schema_cache
404 .get_mut(type_id.0 as usize)
405 .and_then(|s| s.as_mut())
406 {
407 cache.entry.annotations.extend_from_slice(&annotations);
408 }
409 if let Some(entry) = self.registry.schemas.get_mut(&type_id) {
410 entry.annotations.extend_from_slice(&annotations);
411 }
412 Ok(Some(DecodedFrame::SchemaAnnotations {
413 type_id,
414 annotations,
415 }))
416 }
417 }
418 }
419
420 pub fn decode_all(&mut self) -> Vec<DecodedFrame> {
422 let mut frames = Vec::new();
423 while let Ok(Some(f)) = self.next_frame() {
424 frames.push(f);
425 }
426 frames
427 }
428
429 pub fn next_frame_ref(&mut self) -> Result<Option<DecodedFrameRef<'a>>, DecodeError> {
432 if self.pos >= self.data.len() {
433 return Ok(None);
434 }
435 if self.try_consume_reset_header() {
436 return self.next_frame_ref();
437 }
438 let remaining = &self.data[self.pos..];
439 let base = self.timestamp_base_ns;
440 let (frame, consumed) =
441 match codec::decode_frame_ref(remaining, |type_id| self.schema_info(type_id), base) {
442 Some(r) => r,
443 None => return Ok(None),
444 };
445 self.pos += consumed;
446 match frame {
447 FrameRef::Schema {
448 type_id,
449 entry,
450 has_timestamp_on_wire,
451 } => {
452 let result = DecodedFrameRef::Schema(entry.clone());
453 self.register_schema(type_id, entry, has_timestamp_on_wire)
454 .map_err(|msg| DecodeError {
455 pos: self.pos,
456 message: msg,
457 })?;
458 Ok(Some(result))
459 }
460 FrameRef::Event {
461 type_id,
462 timestamp_ns,
463 values,
464 } => {
465 self.timestamp_base_ns = timestamp_ns;
466 Ok(Some(DecodedFrameRef::Event {
467 type_id,
468 timestamp_ns,
469 values,
470 }))
471 }
472 FrameRef::StringPool(entries) => {
473 for e in &entries {
474 if let Ok(s) = std::str::from_utf8(e.data) {
475 self.string_pool
476 .insert(InternedString(e.pool_id), s.to_string());
477 }
478 }
479 Ok(Some(DecodedFrameRef::StringPool(entries)))
480 }
481 FrameRef::StackPool(entries) => {
482 for e in &entries {
483 self.stack_pool
484 .insert(InternedStackFrames(e.pool_id), e.to_stack_frames());
485 }
486 Ok(Some(DecodedFrameRef::StackPool(entries)))
487 }
488 FrameRef::TimestampReset(ts) => {
489 self.timestamp_base_ns = ts;
490 self.next_frame_ref()
491 }
492 FrameRef::SchemaAnnotations {
493 type_id,
494 annotations,
495 } => {
496 if let Some(cache) = self
497 .schema_cache
498 .get_mut(type_id.0 as usize)
499 .and_then(|s| s.as_mut())
500 {
501 cache.entry.annotations.extend_from_slice(&annotations);
502 }
503 if let Some(entry) = self.registry.schemas.get_mut(&type_id) {
504 entry.annotations.extend_from_slice(&annotations);
505 }
506 Ok(Some(DecodedFrameRef::SchemaAnnotations {
507 type_id,
508 annotations,
509 }))
510 }
511 }
512 }
513
514 pub fn decode_all_ref(&mut self) -> Vec<DecodedFrameRef<'a>> {
516 let mut frames = Vec::new();
517 while let Ok(Some(f)) = self.next_frame_ref() {
518 frames.push(f);
519 }
520 frames
521 }
522
523 pub fn for_each_event(
532 &mut self,
533 mut f: impl for<'f> FnMut(RawEvent<'a, 'f>),
534 ) -> Result<(), DecodeError> {
535 self.try_for_each_event(|ev| {
536 f(ev);
537 Ok::<(), std::convert::Infallible>(())
538 })
539 .map_err(|e| match e {
540 TryForEachError::Decode(d) => d,
541 TryForEachError::User(inf) => match inf {},
542 })
543 }
544
545 pub fn try_for_each_event<E>(
548 &mut self,
549 mut f: impl for<'f> FnMut(RawEvent<'a, 'f>) -> Result<(), E>,
550 ) -> Result<(), TryForEachError<E>> {
551 let mut values_buf: Vec<FieldValueRef<'a>> = Vec::new();
552 while self.pos < self.data.len() {
553 let remaining = &self.data[self.pos..];
554 let tag = match remaining.first() {
555 Some(t) => *t,
556 None => break,
557 };
558 match tag {
559 codec::TAG_EVENT => {
560 let mut pos = 1;
561 let type_id = match remaining.get(pos..pos + 2) {
562 Some(b) => {
563 pos += 2;
564 WireTypeId(u16::from_le_bytes(b.try_into().unwrap()))
565 }
566 None => {
567 return Err(TryForEachError::Decode(DecodeError {
568 pos: self.pos,
569 message: "truncated event frame".into(),
570 }));
571 }
572 };
573 let cache = match self
574 .schema_cache
575 .get(type_id.0 as usize)
576 .and_then(|s| s.as_ref())
577 {
578 Some(c) => c,
579 None => {
580 return Err(TryForEachError::Decode(DecodeError {
581 pos: self.pos,
582 message: format!("unknown type_id {type_id:?}"),
583 }));
584 }
585 };
586
587 let timestamp_ns = if cache.has_timestamp_on_wire {
588 match codec::decode_u24_le(&remaining[pos..]) {
589 Some(delta) => {
590 pos += 3;
591 self.timestamp_base_ns + delta as u64
592 }
593 None => {
594 return Err(TryForEachError::Decode(DecodeError {
595 pos: self.pos + pos,
596 message: "truncated timestamp delta".into(),
597 }));
598 }
599 }
600 } else {
601 self.timestamp_base_ns
603 };
604
605 values_buf.clear();
606 for &ftag in &cache.field_tags {
607 let inner_type = match FieldType::from_tag(ftag) {
608 Some(ft) => ft,
609 None => {
610 return Err(TryForEachError::Decode(DecodeError {
611 pos: self.pos + pos,
612 message: format!("unknown field type tag {ftag:#x}"),
613 }));
614 }
615 };
616 if inner_type.is_optional() {
617 match remaining.get(pos) {
618 Some(0x00) => {
619 values_buf.push(FieldValueRef::None);
620 pos += 1;
621 }
622 Some(_) => {
623 pos += 1;
624 match FieldValueRef::decode(inner_type.inner(), remaining, pos)
625 {
626 Some((val, consumed)) => {
627 values_buf.push(val);
628 pos += consumed;
629 }
630 None => {
631 return Err(TryForEachError::Decode(DecodeError {
632 pos: self.pos + pos,
633 message: "truncated optional field value".into(),
634 }));
635 }
636 }
637 }
638 None => {
639 return Err(TryForEachError::Decode(DecodeError {
640 pos: self.pos + pos,
641 message: "truncated optional field prefix".into(),
642 }));
643 }
644 }
645 } else {
646 match FieldValueRef::decode(inner_type, remaining, pos) {
647 Some((val, consumed)) => {
648 values_buf.push(val);
649 pos += consumed;
650 }
651 None => {
652 return Err(TryForEachError::Decode(DecodeError {
653 pos: self.pos + pos,
654 message: "truncated field value".into(),
655 }));
656 }
657 }
658 }
659 }
660 {
666 let Self {
667 pos: self_pos,
668 timestamp_base_ns,
669 ..
670 } = self;
671 *self_pos += pos;
672 *timestamp_base_ns = timestamp_ns;
673 }
674 f(RawEvent {
675 type_id,
676 name: &cache.entry.name,
677 timestamp_ns,
678 fields: &values_buf,
679 schema: &cache.entry,
680 string_pool: &self.string_pool,
681 stack_pool: &self.stack_pool,
682 })
683 .map_err(TryForEachError::User)?;
684 }
685 codec::TAG_TIMESTAMP_RESET => {
686 let ts = match self.data.get(self.pos + 1..self.pos + 9) {
687 Some(b) => u64::from_le_bytes(b.try_into().unwrap()),
688 None => {
689 return Err(TryForEachError::Decode(DecodeError {
690 pos: self.pos,
691 message: "truncated timestamp reset".into(),
692 }));
693 }
694 };
695 self.timestamp_base_ns = ts;
696 self.pos += 9;
697 }
698 _ => {
699 if tag == codec::MAGIC[0] && self.try_consume_reset_header() {
701 continue;
702 }
703 match self.next_frame_ref() {
704 Ok(Some(_)) => {}
705 Ok(None) => {
706 return Err(TryForEachError::Decode(DecodeError {
707 pos: self.pos,
708 message: format!("failed to decode frame with tag 0x{tag:02x}"),
709 }));
710 }
711 Err(e) => return Err(TryForEachError::Decode(e)),
712 }
713 }
714 }
715 }
716 Ok(())
717 }
718
719 pub fn events(&mut self) -> EventIter<'_, 'a> {
723 EventIter { decoder: self }
724 }
725}
726
727impl<'a> Iterator for Decoder<'a> {
728 type Item = Result<DecodedFrameRef<'a>, DecodeError>;
729
730 fn next(&mut self) -> Option<Self::Item> {
731 self.next_frame_ref().transpose()
732 }
733}
734
735pub struct EventIter<'d, 'a> {
738 decoder: &'d mut Decoder<'a>,
739}
740
741impl<'d, 'a> Iterator for EventIter<'d, 'a> {
742 type Item = Result<DecodedFrameRef<'a>, DecodeError>;
743
744 fn next(&mut self) -> Option<Self::Item> {
745 loop {
746 match self.decoder.next()? {
747 Ok(frame @ DecodedFrameRef::Event { .. }) => return Some(Ok(frame)),
748 Ok(_) => continue, Err(e) => return Some(Err(e)),
750 }
751 }
752 }
753}
754
755#[cfg(test)]
756mod tests {
757 use super::*;
758 use crate::encoder::Encoder;
759 use crate::schema::FieldDef;
760 use crate::types::{FieldType, FieldValue};
761
762 #[test]
763 fn decode_empty_stream() {
764 let enc = Encoder::new();
765 let data = enc.finish();
766 let mut dec = Decoder::new(&data).unwrap();
767 assert_eq!(dec.version(), 1);
768 assert!(dec.next_frame().unwrap().is_none());
769 }
770
771 #[test]
772 fn decode_schema_frame() {
773 let mut enc = Encoder::new();
774 enc.register_schema(
775 "Ev",
776 vec![FieldDef {
777 name: "v".into(),
778 field_type: FieldType::Varint,
779 }],
780 )
781 .unwrap();
782 let data = enc.finish();
783 let mut dec = Decoder::new(&data).unwrap();
784 let frame = dec.next_frame().unwrap().unwrap();
785 assert!(matches!(frame, DecodedFrame::Schema(s) if s.name == "Ev"));
786 }
787
788 #[test]
789 fn decode_event_after_schema() {
790 let mut enc = Encoder::new();
791 let schema = enc
792 .register_schema(
793 "Ev",
794 vec![FieldDef {
795 name: "v".into(),
796 field_type: FieldType::Varint,
797 }],
798 )
799 .unwrap();
800 enc.write_event(&schema, 1_000, &[FieldValue::Varint(42)])
801 .unwrap();
802 let data = enc.finish();
803
804 let mut dec = Decoder::new(&data).unwrap();
805 let frames = dec.decode_all();
806 assert_eq!(frames.len(), 2);
807 if let DecodedFrame::Event { values, .. } = &frames[1] {
808 assert_eq!(*values, vec![FieldValue::Varint(42)]);
809 } else {
810 panic!("expected event");
811 }
812 }
813
814 #[test]
815 fn decode_string_pool_builds_map() {
816 let mut enc = Encoder::new();
817 let id = enc.intern_string("hello").unwrap();
818 let data = enc.finish();
819
820 let mut dec = Decoder::new(&data).unwrap();
821 dec.decode_all();
822 assert_eq!(dec.string_pool().get(id), Some("hello"));
823 }
824
825 #[test]
826 fn decode_multiple_events() {
827 let mut enc = Encoder::new();
828 let schema = enc
829 .register_schema(
830 "Ev",
831 vec![FieldDef {
832 name: "v".into(),
833 field_type: FieldType::Varint,
834 }],
835 )
836 .unwrap();
837 for i in 0..10u64 {
838 enc.write_event(&schema, i * 1000, &[FieldValue::Varint(i)])
839 .unwrap();
840 }
841 let data = enc.finish();
842
843 let mut dec = Decoder::new(&data).unwrap();
844 let frames = dec.decode_all();
845 assert_eq!(frames.len(), 11);
846 }
847
848 #[test]
849 fn bad_header_returns_none() {
850 assert!(Decoder::new(&[0x00, 0x00, 0x00, 0x00, 1]).is_none());
851 }
852
853 #[test]
854 fn iterator_yields_all_frames() {
855 let mut enc = Encoder::new();
856 let schema = enc
857 .register_schema(
858 "Ev",
859 vec![FieldDef {
860 name: "v".into(),
861 field_type: FieldType::Varint,
862 }],
863 )
864 .unwrap();
865 for i in 0..3u64 {
866 enc.write_event(&schema, i * 1000, &[FieldValue::Varint(i)])
867 .unwrap();
868 }
869 let data = enc.finish();
870
871 let dec = Decoder::new(&data).unwrap();
872 let frames: Vec<_> = dec.collect::<Result<Vec<_>, _>>().unwrap();
873 assert_eq!(frames.len(), 4);
875 assert!(matches!(frames[0], DecodedFrameRef::Schema(_)));
876 assert!(matches!(frames[1], DecodedFrameRef::Event { .. }));
877 }
878
879 #[test]
880 fn iterator_early_termination() {
881 let mut enc = Encoder::new();
882 let schema = enc
883 .register_schema(
884 "Ev",
885 vec![FieldDef {
886 name: "v".into(),
887 field_type: FieldType::Varint,
888 }],
889 )
890 .unwrap();
891 for i in 0..10u64 {
892 enc.write_event(&schema, i * 1000, &[FieldValue::Varint(i)])
893 .unwrap();
894 }
895 let data = enc.finish();
896
897 let mut dec = Decoder::new(&data).unwrap();
898 let first_two: Vec<_> = dec.by_ref().take(2).collect::<Result<Vec<_>, _>>().unwrap();
900 assert_eq!(first_two.len(), 2);
901 let next = dec.next();
903 assert!(next.is_some());
904 }
905
906 #[test]
907 fn events_iterator_skips_schema() {
908 let mut enc = Encoder::new();
909 let schema = enc
910 .register_schema(
911 "Ev",
912 vec![FieldDef {
913 name: "v".into(),
914 field_type: FieldType::Varint,
915 }],
916 )
917 .unwrap();
918 enc.write_event(&schema, 1_000, &[FieldValue::Varint(42)])
919 .unwrap();
920 enc.write_event(&schema, 2_000, &[FieldValue::Varint(99)])
921 .unwrap();
922 let data = enc.finish();
923
924 let mut dec = Decoder::new(&data).unwrap();
925 let events: Vec<_> = dec.events().collect::<Result<Vec<_>, _>>().unwrap();
926 assert_eq!(events.len(), 2);
928 for ev in &events {
929 assert!(matches!(ev, DecodedFrameRef::Event { .. }));
930 }
931 }
932
933 #[test]
934 fn events_iterator_first_event_only() {
935 let mut enc = Encoder::new();
936 let schema = enc
937 .register_schema(
938 "Ev",
939 vec![FieldDef {
940 name: "v".into(),
941 field_type: FieldType::Varint,
942 }],
943 )
944 .unwrap();
945 for i in 0..5u64 {
946 enc.write_event(&schema, i * 1000, &[FieldValue::Varint(i)])
947 .unwrap();
948 }
949 let data = enc.finish();
950
951 let mut dec = Decoder::new(&data).unwrap();
952 let first = dec.events().next().unwrap().unwrap();
954 assert!(matches!(first, DecodedFrameRef::Event { .. }));
955 }
956}