1use crate::{constants, ArgType, Argument, Header, Metatag, RawSeverity, Record, Value};
8use std::array::TryFromSliceError;
9use std::borrow::{Borrow, Cow};
10use std::fmt::Debug;
11use std::io::Cursor;
12use std::ops::Deref;
13use thiserror::Error;
14
15#[cfg(fuchsia_api_level_less_than = "NEXT")]
16use fidl_fuchsia_diagnostics::Severity;
17#[cfg(fuchsia_api_level_at_least = "NEXT")]
18use fidl_fuchsia_diagnostics_types::Severity;
19
20pub struct Encoder<B> {
23 pub(crate) buf: B,
24 options: EncoderOpts,
26}
27
28#[derive(Default)]
30pub struct EncoderOpts {
31 pub always_log_file_line: bool,
35}
36
37pub struct WriteEventParams<'a, E, T, MS> {
39 pub event: E,
41 pub tags: &'a [T],
43 pub metatags: MS,
45 pub pid: zx::Koid,
47 pub tid: zx::Koid,
49 pub dropped: u64,
51}
52
53impl<B> Encoder<B>
54where
55 B: MutableBuffer,
56{
57 pub fn new(buf: B, options: EncoderOpts) -> Self {
59 Self { buf, options }
60 }
61
62 pub fn inner(&self) -> &B {
64 &self.buf
65 }
66
67 pub fn take(self) -> B {
69 self.buf
70 }
71
72 pub fn write_event<'a, E, MS, T>(
76 &mut self,
77 params: WriteEventParams<'a, E, T, MS>,
78 ) -> Result<(), EncodingError>
79 where
80 E: RecordEvent,
81 MS: Iterator<Item = &'a Metatag>,
82 T: AsRef<str>,
83 {
84 let WriteEventParams { event, tags, metatags, pid, tid, dropped } = params;
85 let severity = event.raw_severity();
86 self.write_inner(event.timestamp(), severity, |this| {
87 this.write_raw_argument(constants::PID, pid.raw_koid())?;
88 this.write_raw_argument(constants::TID, tid.raw_koid())?;
89 if dropped > 0 {
90 this.write_raw_argument(constants::NUM_DROPPED, dropped)?;
91 }
92 if this.options.always_log_file_line || severity >= Severity::Error.into_primitive() {
93 if let Some(mut file) = event.file() {
95 let split = file.split("../");
96 file = split.last().unwrap();
97 this.write_raw_argument(constants::FILE, Value::Text(Cow::Borrowed(file)))?;
98 }
99
100 if let Some(line) = event.line() {
101 this.write_raw_argument(constants::LINE, line as u64)?;
102 }
103 }
104
105 for metatag in metatags {
107 match metatag {
108 Metatag::Target => this.write_raw_argument(constants::TAG, event.target())?,
109 }
110 }
111
112 event.write_arguments(this)?;
113
114 for tag in tags {
115 this.write_raw_argument(constants::TAG, tag.as_ref())?;
116 }
117 Ok(())
118 })?;
119 Ok(())
120 }
121
122 pub fn write_record<R>(&mut self, record: R) -> Result<(), EncodingError>
124 where
125 R: RecordFields,
126 {
127 self.write_inner(record.timestamp(), record.raw_severity(), |this| {
128 record.write_arguments(this)
129 })
130 }
131
132 fn write_inner<F>(
133 &mut self,
134 timestamp: zx::BootInstant,
135 severity: RawSeverity,
136 write_args: F,
137 ) -> Result<(), EncodingError>
138 where
139 F: FnOnce(&mut Self) -> Result<(), EncodingError>,
140 {
141 let starting_idx = self.buf.cursor();
143 let header_slot = self.buf.put_slot(std::mem::size_of::<u64>())?;
145 self.write_i64(timestamp.into_nanos())?;
146
147 write_args(self)?;
148
149 let mut header = Header(0);
150 header.set_type(crate::TRACING_FORMAT_LOG_RECORD_TYPE);
151 header.set_severity(severity);
152
153 let length = self.buf.cursor() - starting_idx;
154 header.set_len(length);
155
156 assert_eq!(length % 8, 0, "all records must be written 8-byte aligned");
157 self.buf.fill_slot(header_slot, &header.0.to_le_bytes());
158 Ok(())
159 }
160
161 pub fn write_raw_argument(
163 &mut self,
164 name: &str,
165 value: impl WriteArgumentValue<B>,
166 ) -> Result<(), EncodingError> {
167 self.inner_write_argument(move |header, encoder| {
168 encoder.write_argument_name(header, name)?;
169 value.write_value(header, encoder)?;
170 Ok(())
171 })
172 }
173
174 pub fn write_argument<'a>(
176 &mut self,
177 argument: impl Borrow<Argument<'a>>,
178 ) -> Result<(), EncodingError> {
179 let argument = argument.borrow();
180 self.inner_write_argument(move |header, encoder| {
181 encoder.write_argument_name(header, argument.name())?;
182 argument.write_value(header, encoder)?;
183 Ok(())
184 })
185 }
186
187 fn write_argument_name(
188 &mut self,
189 header: &mut Header,
190 name: &str,
191 ) -> Result<(), EncodingError> {
192 self.write_string(name)?;
193 header.set_name_ref(string_mask(name));
194 Ok(())
195 }
196
197 fn inner_write_argument(
198 &mut self,
199 cb: impl FnOnce(&mut Header, &mut Self) -> Result<(), EncodingError>,
200 ) -> Result<(), EncodingError> {
201 let starting_idx = self.buf.cursor();
202 let header_slot = self.buf.put_slot(std::mem::size_of::<Header>())?;
203
204 let mut header = Header(0);
205 cb(&mut header, self)?;
206
207 let record_len = self.buf.cursor() - starting_idx;
208 assert_eq!(record_len % 8, 0, "arguments must be 8-byte aligned");
209
210 header.set_size_words((record_len / 8) as u16);
211 self.buf.fill_slot(header_slot, &header.0.to_le_bytes());
212
213 Ok(())
214 }
215
216 fn write_u64(&mut self, n: u64) -> Result<(), EncodingError> {
218 self.buf.put_u64_le(n).map_err(|_| EncodingError::BufferTooSmall)
219 }
220
221 fn write_i64(&mut self, n: i64) -> Result<(), EncodingError> {
223 self.buf.put_i64_le(n).map_err(|_| EncodingError::BufferTooSmall)
224 }
225
226 fn write_f64(&mut self, n: f64) -> Result<(), EncodingError> {
228 self.buf.put_f64(n).map_err(|_| EncodingError::BufferTooSmall)
229 }
230
231 fn write_string(&mut self, src: &str) -> Result<(), EncodingError> {
233 self.write_bytes(src.as_bytes())
234 }
235
236 #[doc(hidden)]
238 pub fn write_bytes(&mut self, src: &[u8]) -> Result<(), EncodingError> {
239 self.buf.put_slice(src).map_err(|_| EncodingError::BufferTooSmall)?;
240 unsafe {
241 let align = std::mem::size_of::<u64>();
242 let num_padding_bytes = (align - src.len() % align) % align;
243 self.buf.advance_cursor(num_padding_bytes);
245 }
246 Ok(())
247 }
248}
249
250mod private {
251 use super::*;
252
253 pub trait Sealed {}
254 impl Sealed for Value<'_> {}
255 impl Sealed for Argument<'_> {}
256 impl Sealed for u64 {}
257 impl Sealed for f64 {}
258 impl Sealed for i64 {}
259 impl Sealed for bool {}
260 impl Sealed for String {}
261 impl Sealed for &str {}
262 impl Sealed for Cow<'_, str> {}
263}
264
265pub trait WriteArgumentValue<B>: private::Sealed {
267 fn write_value(
269 &self,
270 header: &mut Header,
271 encoder: &mut Encoder<B>,
272 ) -> Result<(), EncodingError>;
273}
274
275impl<B: MutableBuffer> WriteArgumentValue<B> for Argument<'_> {
276 fn write_value(
277 &self,
278 header: &mut Header,
279 encoder: &mut Encoder<B>,
280 ) -> Result<(), EncodingError> {
281 match self {
282 Self::Pid(value) | Self::Tid(value) => value.raw_koid().write_value(header, encoder),
283 Self::Line(value) | Self::Dropped(value) => value.write_value(header, encoder),
284 Self::Tag(value) | Self::File(value) | Self::Message(value) => {
285 value.write_value(header, encoder)
286 }
287 Self::Other { value, .. } => value.write_value(header, encoder),
288 }
289 }
290}
291
292impl<B: MutableBuffer> WriteArgumentValue<B> for i64 {
293 fn write_value(
294 &self,
295 header: &mut Header,
296 encoder: &mut Encoder<B>,
297 ) -> Result<(), EncodingError> {
298 header.set_type(ArgType::I64 as u8);
299 encoder.write_i64(*self)
300 }
301}
302
303impl<B: MutableBuffer> WriteArgumentValue<B> for u64 {
304 fn write_value(
305 &self,
306 header: &mut Header,
307 encoder: &mut Encoder<B>,
308 ) -> Result<(), EncodingError> {
309 header.set_type(ArgType::U64 as u8);
310 encoder.write_u64(*self)
311 }
312}
313
314impl<B: MutableBuffer> WriteArgumentValue<B> for f64 {
315 fn write_value(
316 &self,
317 header: &mut Header,
318 encoder: &mut Encoder<B>,
319 ) -> Result<(), EncodingError> {
320 header.set_type(ArgType::F64 as u8);
321 encoder.write_f64(*self)
322 }
323}
324
325impl<B: MutableBuffer> WriteArgumentValue<B> for bool {
326 fn write_value(
327 &self,
328 header: &mut Header,
329 _encoder: &mut Encoder<B>,
330 ) -> Result<(), EncodingError> {
331 header.set_type(ArgType::Bool as u8);
332 header.set_bool_val(*self);
333 Ok(())
334 }
335}
336
337impl<B: MutableBuffer> WriteArgumentValue<B> for &str {
338 fn write_value(
339 &self,
340 header: &mut Header,
341 encoder: &mut Encoder<B>,
342 ) -> Result<(), EncodingError> {
343 header.set_type(ArgType::String as u8);
344 header.set_value_ref(string_mask(self));
345 encoder.write_string(self)
346 }
347}
348
349impl<B: MutableBuffer> WriteArgumentValue<B> for String {
350 fn write_value(
351 &self,
352 header: &mut Header,
353 encoder: &mut Encoder<B>,
354 ) -> Result<(), EncodingError> {
355 self.as_str().write_value(header, encoder)
356 }
357}
358
359impl<B: MutableBuffer> WriteArgumentValue<B> for Cow<'_, str> {
360 fn write_value(
361 &self,
362 header: &mut Header,
363 encoder: &mut Encoder<B>,
364 ) -> Result<(), EncodingError> {
365 self.as_ref().write_value(header, encoder)
366 }
367}
368
369impl<B: MutableBuffer> WriteArgumentValue<B> for Value<'_> {
370 fn write_value(
371 &self,
372 header: &mut Header,
373 encoder: &mut Encoder<B>,
374 ) -> Result<(), EncodingError> {
375 match self {
376 Value::SignedInt(s) => s.write_value(header, encoder),
377 Value::UnsignedInt(u) => u.write_value(header, encoder),
378 Value::Floating(f) => f.write_value(header, encoder),
379 Value::Text(t) => t.write_value(header, encoder),
380 Value::Boolean(b) => b.write_value(header, encoder),
381 }
382 }
383}
384
385fn string_mask(s: &str) -> u16 {
386 let len = s.len();
387 if len == 0 {
388 return 0;
389 }
390 (len as u16) | (1 << 15)
391}
392
393pub trait RecordEvent {
395 fn raw_severity(&self) -> RawSeverity;
397 fn file(&self) -> Option<&str>;
399 fn line(&self) -> Option<u32>;
401 fn target(&self) -> &str;
403 fn write_arguments<B: MutableBuffer>(
405 self,
406 writer: &mut Encoder<B>,
407 ) -> Result<(), EncodingError>;
408 fn timestamp(&self) -> zx::BootInstant;
410}
411
412pub trait RecordFields {
414 fn raw_severity(&self) -> RawSeverity;
416
417 fn timestamp(&self) -> zx::BootInstant;
419
420 fn write_arguments<B: MutableBuffer>(
422 self,
423 writer: &mut Encoder<B>,
424 ) -> Result<(), EncodingError>;
425}
426
427pub struct TestRecord<'a> {
429 pub severity: RawSeverity,
431 pub timestamp: zx::BootInstant,
433 pub file: Option<&'a str>,
435 pub line: Option<u32>,
437 pub record_arguments: Vec<Argument<'a>>,
439}
440
441impl TestRecord<'_> {
442 pub fn from<'a>(file: &'a str, line: u32, record: &'a Record<'a>) -> TestRecord<'a> {
444 TestRecord {
445 severity: record.severity,
446 timestamp: record.timestamp,
447 file: Some(file),
448 line: Some(line),
449 record_arguments: record.arguments.clone(),
450 }
451 }
452}
453
454impl RecordEvent for TestRecord<'_> {
455 fn raw_severity(&self) -> RawSeverity {
456 self.severity
457 }
458
459 fn file(&self) -> Option<&str> {
460 self.file
461 }
462
463 fn line(&self) -> Option<u32> {
464 self.line
465 }
466
467 fn target(&self) -> &str {
468 unimplemented!("Unused at the moment");
469 }
470
471 fn timestamp(&self) -> zx::BootInstant {
472 self.timestamp
473 }
474
475 fn write_arguments<B: MutableBuffer>(
476 self,
477 writer: &mut Encoder<B>,
478 ) -> Result<(), EncodingError> {
479 for argument in self.record_arguments {
480 writer.write_argument(argument)?;
481 }
482 Ok(())
483 }
484}
485
486impl RecordFields for Record<'_> {
487 fn raw_severity(&self) -> RawSeverity {
488 self.severity
489 }
490
491 fn write_arguments<B: MutableBuffer>(
492 self,
493 writer: &mut Encoder<B>,
494 ) -> Result<(), EncodingError> {
495 for arg in self.arguments {
496 writer.write_argument(arg)?;
497 }
498 Ok(())
499 }
500
501 fn timestamp(&self) -> zx::BootInstant {
502 self.timestamp
503 }
504}
505
506#[cfg(test)]
507impl RecordFields for &Record<'_> {
508 fn raw_severity(&self) -> RawSeverity {
509 self.severity
510 }
511
512 fn write_arguments<B: MutableBuffer>(
513 self,
514 writer: &mut Encoder<B>,
515 ) -> Result<(), EncodingError> {
516 for arg in &self.arguments {
517 writer.write_argument(arg)?;
518 }
519 Ok(())
520 }
521
522 fn timestamp(&self) -> zx::BootInstant {
523 self.timestamp
524 }
525}
526
527pub trait MutableBuffer {
529 fn capacity(&self) -> usize;
533
534 fn cursor(&self) -> usize;
536
537 unsafe fn advance_cursor(&mut self, n: usize);
544
545 unsafe fn put_slice_at(&mut self, src: &[u8], offset: usize);
552
553 fn has_remaining(&self, num_bytes: usize) -> bool;
555
556 fn put_slot(&mut self, width: usize) -> Result<WriteSlot, EncodingError> {
559 if self.has_remaining(width) {
560 let slot = WriteSlot { range: self.cursor()..(self.cursor() + width) };
561 unsafe {
562 self.advance_cursor(width);
563 }
564 Ok(slot)
565 } else {
566 Err(EncodingError::BufferTooSmall)
567 }
568 }
569
570 fn fill_slot(&mut self, slot: WriteSlot, src: &[u8]) {
572 assert_eq!(
573 src.len(),
574 slot.range.end - slot.range.start,
575 "WriteSlots can only insert exactly-sized content into the buffer"
576 );
577 unsafe {
578 self.put_slice_at(src, slot.range.start);
579 }
580 }
581
582 fn put_slice(&mut self, src: &[u8]) -> Result<(), EncodingError> {
589 if self.has_remaining(src.len()) {
590 unsafe {
591 self.put_slice_at(src, self.cursor());
592 self.advance_cursor(src.len());
593 }
594 Ok(())
595 } else {
596 Err(EncodingError::NoCapacity)
597 }
598 }
599
600 fn put_u64_le(&mut self, n: u64) -> Result<(), EncodingError> {
618 self.put_slice(&n.to_le_bytes())
619 }
620
621 fn put_i64_le(&mut self, n: i64) -> Result<(), EncodingError> {
639 self.put_slice(&n.to_le_bytes())
640 }
641
642 fn put_f64(&mut self, n: f64) -> Result<(), EncodingError> {
660 self.put_slice(&n.to_bits().to_ne_bytes())
661 }
662}
663
664#[must_use]
666pub struct WriteSlot {
667 range: std::ops::Range<usize>,
668}
669
670#[derive(Debug, Default)]
672pub struct ResizableBuffer(Vec<u8>);
673
674impl From<Vec<u8>> for ResizableBuffer {
675 fn from(buf: Vec<u8>) -> Self {
676 Self(buf)
677 }
678}
679
680impl Deref for ResizableBuffer {
681 type Target = Vec<u8>;
682
683 fn deref(&self) -> &Self::Target {
685 &self.0
686 }
687}
688
689impl ResizableBuffer {
690 pub fn into_inner(self) -> Vec<u8> {
692 self.0
693 }
694}
695
696impl MutableBuffer for Cursor<ResizableBuffer> {
697 fn capacity(&self) -> usize {
698 self.get_ref().0.len()
699 }
700
701 fn cursor(&self) -> usize {
702 self.position() as usize
703 }
704
705 fn has_remaining(&self, _num_bytes: usize) -> bool {
706 true
707 }
708
709 unsafe fn advance_cursor(&mut self, n: usize) {
710 self.set_position(self.position() + n as u64);
711 }
712
713 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
714 let this = &mut self.get_mut().0;
715 if offset < this.len() {
716 let available = this.len() - offset;
717
718 let min = available.min(to_put.len());
720 let dest = &mut this[offset..(offset + min)];
721 dest.copy_from_slice(&to_put[..min]);
722
723 if available < to_put.len() {
725 this.extend_from_slice(&to_put[available..]);
726 }
727 } else {
728 this.resize(offset, 0);
731 this.extend_from_slice(to_put);
732 }
733 }
734}
735
736impl<T: MutableBuffer + ?Sized> MutableBuffer for &mut T {
737 fn has_remaining(&self, num_bytes: usize) -> bool {
738 (**self).has_remaining(num_bytes)
739 }
740 fn capacity(&self) -> usize {
741 (**self).capacity()
742 }
743
744 fn cursor(&self) -> usize {
745 (**self).cursor()
746 }
747
748 unsafe fn advance_cursor(&mut self, n: usize) {
749 (**self).advance_cursor(n);
750 }
751
752 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
753 (**self).put_slice_at(to_put, offset);
754 }
755}
756
757impl<T: MutableBuffer + ?Sized> MutableBuffer for Box<T> {
758 fn has_remaining(&self, num_bytes: usize) -> bool {
759 (**self).has_remaining(num_bytes)
760 }
761 fn capacity(&self) -> usize {
762 (**self).capacity()
763 }
764
765 fn cursor(&self) -> usize {
766 (**self).cursor()
767 }
768
769 unsafe fn advance_cursor(&mut self, n: usize) {
770 (**self).advance_cursor(n);
771 }
772
773 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
774 (**self).put_slice_at(to_put, offset);
775 }
776}
777
778impl MutableBuffer for Cursor<Vec<u8>> {
779 fn has_remaining(&self, num_bytes: usize) -> bool {
780 (self.cursor() + num_bytes) <= self.capacity()
781 }
782
783 fn capacity(&self) -> usize {
784 self.get_ref().len()
785 }
786
787 fn cursor(&self) -> usize {
788 self.position() as usize
789 }
790
791 unsafe fn advance_cursor(&mut self, n: usize) {
792 self.set_position(self.position() + n as u64);
793 }
794
795 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
796 let dest = &mut self.get_mut()[offset..(offset + to_put.len())];
797 dest.copy_from_slice(to_put);
798 }
799}
800
801impl MutableBuffer for Cursor<&mut [u8]> {
802 fn has_remaining(&self, num_bytes: usize) -> bool {
803 (self.cursor() + num_bytes) <= self.capacity()
804 }
805
806 fn capacity(&self) -> usize {
807 self.get_ref().len()
808 }
809
810 fn cursor(&self) -> usize {
811 self.position() as usize
812 }
813
814 unsafe fn advance_cursor(&mut self, n: usize) {
815 self.set_position(self.position() + n as u64);
816 }
817
818 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
819 let dest = &mut self.get_mut()[offset..(offset + to_put.len())];
820 dest.copy_from_slice(to_put);
821 }
822}
823
824impl<const N: usize> MutableBuffer for Cursor<[u8; N]> {
825 fn has_remaining(&self, num_bytes: usize) -> bool {
826 (self.cursor() + num_bytes) <= self.capacity()
827 }
828 fn capacity(&self) -> usize {
829 self.get_ref().len()
830 }
831
832 fn cursor(&self) -> usize {
833 self.position() as usize
834 }
835
836 unsafe fn advance_cursor(&mut self, n: usize) {
837 self.set_position(self.position() + n as u64);
838 }
839
840 unsafe fn put_slice_at(&mut self, to_put: &[u8], offset: usize) {
841 let dest = &mut self.get_mut()[offset..(offset + to_put.len())];
842 dest.copy_from_slice(to_put);
843 }
844}
845
846#[derive(Debug, Error)]
848pub enum EncodingError {
849 #[error("buffer is too small")]
851 BufferTooSmall,
852
853 #[error("unsupported value type")]
856 Unsupported,
857
858 #[error("the buffer has no remaining capacity")]
860 NoCapacity,
861
862 #[error(transparent)]
865 Other(Box<dyn std::error::Error + Send + Sync>),
866}
867
868impl EncodingError {
869 pub fn other<E>(err: E) -> Self
871 where
872 E: std::error::Error + Send + Sync + 'static,
873 {
874 Self::Other(err.into())
875 }
876}
877
878impl From<TryFromSliceError> for EncodingError {
879 fn from(_: TryFromSliceError) -> Self {
880 EncodingError::BufferTooSmall
881 }
882}
883
884#[cfg(test)]
885mod tests {
886 use super::*;
887 use crate::parse::parse_record;
888
889 #[fuchsia::test]
890 fn build_basic_record() {
891 let mut encoder = Encoder::new(Cursor::new([0u8; 1024]), EncoderOpts::default());
892 encoder
893 .write_event(WriteEventParams::<_, &str, _> {
894 event: TestRecord {
895 severity: Severity::Info.into_primitive(),
896 timestamp: zx::BootInstant::from_nanos(12345),
897 file: None,
898 line: None,
899 record_arguments: vec![],
900 },
901 tags: &[],
902 metatags: std::iter::empty(),
903 pid: zx::Koid::from_raw(0),
904 tid: zx::Koid::from_raw(0),
905 dropped: 0,
906 })
907 .expect("wrote event");
908 let (record, _) = parse_record(encoder.inner().get_ref()).expect("wrote valid record");
909 assert_eq!(
910 record,
911 Record {
912 timestamp: zx::BootInstant::from_nanos(12345),
913 severity: Severity::Info.into_primitive(),
914 arguments: vec![
915 Argument::pid(zx::Koid::from_raw(0)),
916 Argument::tid(zx::Koid::from_raw(0)),
917 ]
918 }
919 );
920 }
921
922 #[fuchsia::test]
923 fn build_records_with_location() {
924 let mut encoder = Encoder::new(Cursor::new([0u8; 1024]), EncoderOpts::default());
925 encoder
926 .write_event(WriteEventParams::<_, &str, _> {
927 event: TestRecord {
928 severity: Severity::Error.into_primitive(),
929 timestamp: zx::BootInstant::from_nanos(12345),
930 file: Some("foo.rs"),
931 line: Some(10),
932 record_arguments: vec![],
933 },
934 tags: &[],
935 metatags: std::iter::empty(),
936 pid: zx::Koid::from_raw(0),
937 tid: zx::Koid::from_raw(0),
938 dropped: 0,
939 })
940 .expect("wrote event");
941 let (record, _) = parse_record(encoder.inner().get_ref()).expect("wrote valid record");
942 assert_eq!(
943 record,
944 Record {
945 timestamp: zx::BootInstant::from_nanos(12345),
946 severity: Severity::Error.into_primitive(),
947 arguments: vec![
948 Argument::pid(zx::Koid::from_raw(0)),
949 Argument::tid(zx::Koid::from_raw(0)),
950 Argument::file("foo.rs"),
951 Argument::line(10),
952 ]
953 }
954 );
955 }
956
957 #[fuchsia::test]
958 fn build_record_with_dropped_count() {
959 let mut encoder = Encoder::new(Cursor::new([0u8; 1024]), EncoderOpts::default());
960 encoder
961 .write_event(WriteEventParams::<_, &str, _> {
962 event: TestRecord {
963 severity: Severity::Warn.into_primitive(),
964 timestamp: zx::BootInstant::from_nanos(12345),
965 file: None,
966 line: None,
967 record_arguments: vec![],
968 },
969 tags: &[],
970 metatags: std::iter::empty(),
971 pid: zx::Koid::from_raw(0),
972 tid: zx::Koid::from_raw(0),
973 dropped: 7,
974 })
975 .expect("wrote event");
976 let (record, _) = parse_record(encoder.inner().get_ref()).expect("wrote valid record");
977 assert_eq!(
978 record,
979 Record {
980 timestamp: zx::BootInstant::from_nanos(12345),
981 severity: Severity::Warn.into_primitive(),
982 arguments: vec![
983 Argument::pid(zx::Koid::from_raw(0)),
984 Argument::tid(zx::Koid::from_raw(0)),
985 Argument::dropped(7),
986 ]
987 }
988 );
989 }
990
991 #[test]
992 fn resizable_vec_mutable_buffer() {
993 let mut vec = Cursor::new(ResizableBuffer(vec![1u8, 2, 3]));
995 unsafe {
996 vec.put_slice_at(&[4, 5, 6], 3);
997 }
998 assert_eq!(vec.get_ref().0, vec![1, 2, 3, 4, 5, 6]);
999
1000 let mut vec = Cursor::new(ResizableBuffer(vec![1, 3, 7, 9, 11, 13, 15]));
1003 unsafe {
1004 vec.put_slice_at(&[2, 4, 6], 2);
1005 }
1006 assert_eq!(vec.get_ref().0, vec![1, 3, 2, 4, 6, 13, 15]);
1007
1008 let mut vec = Cursor::new(ResizableBuffer(vec![1, 2, 3]));
1010 unsafe {
1011 vec.put_slice_at(&[4, 5, 6, 7], 0);
1012 }
1013 assert_eq!(vec.get_ref().0, vec![4, 5, 6, 7]);
1014
1015 let mut vec = Cursor::new(ResizableBuffer(vec![1, 2, 3]));
1017 unsafe {
1018 vec.put_slice_at(&[4, 5, 6], 5);
1019 }
1020 assert_eq!(vec.get_ref().0, vec![1, 2, 3, 0, 0, 4, 5, 6]);
1021 }
1022}