libdd_profiling_protobuf/
sample.rs1use crate::{Label, Record, Value, WireType, NO_OPT_ZERO};
5
6#[cfg(feature = "prost_impls")]
7use crate::prost_impls;
8
9use std::io::{self, Write};
10
11#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
20pub struct Sample<'a> {
21 pub location_ids: Record<&'a [u64], 1, NO_OPT_ZERO>,
24 pub values: Record<&'a [i64], 2, NO_OPT_ZERO>,
30 pub labels: &'a [Record<Label, 3, NO_OPT_ZERO>],
37}
38
39unsafe impl Value for Sample<'_> {
42 const WIRE_TYPE: WireType = WireType::LengthDelimited;
43
44 fn proto_len(&self) -> u64 {
45 self.location_ids.proto_len()
46 + self.values.proto_len()
47 + self.labels.iter().map(Record::proto_len).sum::<u64>()
48 }
49
50 fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
51 self.location_ids.encode(writer)?;
52 self.values.encode(writer)?;
53 for label in self.labels {
54 label.encode(writer)?;
55 }
56 Ok(())
57 }
58}
59
60#[cfg(feature = "prost_impls")]
61impl From<Sample<'_>> for prost_impls::Sample {
62 fn from(sample: Sample) -> Self {
63 #[allow(clippy::needless_update)]
65 Self {
66 location_ids: Vec::from_iter(sample.location_ids.value.iter().copied()),
67 values: Vec::from_iter(sample.values.value.iter().copied()),
68 labels: sample
69 .labels
70 .iter()
71 .map(|field| field.value)
72 .map(prost_impls::Label::from)
73 .collect(),
74 ..Self::default()
75 }
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use bolero::generator::TypeGenerator;
83 use prost::Message;
84
85 #[test]
86 fn empty() {
87 let sample = Sample {
88 location_ids: [].as_slice().into(),
89 values: [].as_slice().into(),
90 labels: &[],
91 };
92 let prost_sample = prost_impls::Sample {
93 location_ids: vec![],
94 values: vec![],
95 labels: vec![],
96 };
97
98 use prost::Message;
99 let len = sample.proto_len() as usize;
100 let mut buffer = Vec::with_capacity(len);
101 sample.encode(&mut buffer).unwrap();
102 let roundtrip = prost_impls::Sample::decode(buffer.as_slice()).unwrap();
103 assert_eq!(prost_sample, roundtrip);
104 }
105
106 #[test]
107 fn roundtrip() {
108 let locations = Vec::<u64>::produce();
109 let values = Vec::<i64>::produce();
110 let labels = Vec::<Label>::produce();
111
112 bolero::check!()
113 .with_generator((locations, values, labels))
114 .for_each(|(location_ids, values, labels)| {
115 let labels = labels
116 .iter()
117 .map(|l| Record::<_, 3, NO_OPT_ZERO>::from(*l))
118 .collect::<Vec<_>>();
119 let sample = Sample {
120 location_ids: Record::from(location_ids.as_slice()),
121 values: Record::from(values.as_slice()),
122 labels: labels.as_slice(),
123 };
124
125 let prost_sample = prost_impls::Sample::from(sample);
126
127 let mut buffer = Vec::with_capacity(sample.proto_len() as usize);
128 sample.encode(&mut buffer).unwrap();
129 let roundtrip = prost_impls::Sample::decode(buffer.as_slice()).unwrap();
130 assert_eq!(prost_sample, roundtrip);
131
132 let mut buffer2 = Vec::with_capacity(sample.proto_len() as usize);
133 prost_sample.encode(&mut buffer2).unwrap();
134 let roundtrip2 = prost_impls::Sample::decode(buffer2.as_slice()).unwrap();
135 assert_eq!(roundtrip, roundtrip2);
136 });
137 }
138}