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