krabka_bench_driver/
payload.rs1use {
14 crate::numeric::saturating_u128_to_u64,
15 bytes::{Bytes, BytesMut},
16 krabka_units::prelude::*,
17 std::time::{SystemTime, UNIX_EPOCH},
18};
19
20pub const MAGIC: [u8; 8] = *b"KRABKA_B";
23pub const HEADER_LEN: usize = MAGIC.len() + 8 + 8; #[must_use]
31pub fn template(msg_size: ByteSize) -> BytesMut {
32 let len = msg_size.bytes_usize().max(HEADER_LEN);
33 let mut b = BytesMut::with_capacity(len);
34 b.resize(len, 0u8);
35 for (i, byte) in b.iter_mut().enumerate().skip(HEADER_LEN) {
38 *byte = u8::try_from(i & 0xff).unwrap_or_default();
39 }
40 b
41}
42
43#[must_use]
56pub fn key(key_size: ByteSize, sequence: u64) -> Option<Bytes> {
57 let len = key_size.bytes_usize();
58 if len == 0 {
59 return None;
60 }
61 let mut buf = BytesMut::with_capacity(len);
62 buf.resize(len, 0u8);
63 let stamped = len.min(8);
64 for (slot, byte) in buf.iter_mut().zip(sequence.to_be_bytes()) {
65 *slot = byte;
66 }
67 for (index, byte) in buf.iter_mut().enumerate().skip(stamped) {
68 *byte = u8::try_from(index & 0xff).unwrap_or_default();
69 }
70 Some(buf.freeze())
71}
72
73pub fn stamp_into(buf: &mut BytesMut, scenario_id: u64) -> Bytes {
77 assert2::debug_assert!(buf.len() >= HEADER_LEN, "buf too short for header");
78 let nanos = SystemTime::now()
79 .duration_since(UNIX_EPOCH)
80 .map_or(0, |d| saturating_u128_to_u64(d.as_nanos()));
81 let header = MAGIC
82 .into_iter()
83 .chain(scenario_id.to_be_bytes())
84 .chain(nanos.to_be_bytes());
85 for (slot, byte) in buf.iter_mut().zip(header) {
86 *slot = byte;
87 }
88 Bytes::copy_from_slice(buf)
90}
91
92#[must_use]
96pub fn read_send_nanos(value: &[u8], scenario_id: u64) -> Option<u64> {
97 let (magic, rest) = value.split_first_chunk::<8>()?;
98 let (sid, rest) = rest.split_first_chunk::<8>()?;
99 let (nanos, _) = rest.split_first_chunk::<8>()?;
100 if *magic != MAGIC || u64::from_be_bytes(*sid) != scenario_id {
101 return None;
102 }
103 Some(u64::from_be_bytes(*nanos))
104}
105
106#[cfg(test)]
107mod tests {
108
109 use super::*;
110
111 #[test]
112 fn a_zero_key_size_means_a_keyless_record() {
113 assert2::assert!(key(ByteSize::ZERO, 7).is_none());
114 }
115
116 #[test]
117 fn a_key_has_the_configured_size_and_varies_per_record() {
118 let first = key(bytes(16), 1).expect("a sized key");
119 let second = key(bytes(16), 2).expect("a sized key");
120 assert2::assert!(first.len() == 16);
121 assert2::assert!(second.len() == 16);
122 assert2::assert!(first != second);
123 assert2::assert!(first[..8] == 1u64.to_be_bytes());
124 }
125
126 #[test]
127 fn a_key_shorter_than_the_sequence_is_still_the_configured_size() {
128 let short = key(bytes(4), 0x0102_0304_0506_0708).expect("a sized key");
129 assert2::assert!(short.len() == 4);
130 assert2::assert!(short[..] == [0x01, 0x02, 0x03, 0x04]);
131 }
132
133 #[test]
134 fn round_trip_send_nanos() {
135 let mut t = template(bytes(64));
136 let b = stamp_into(&mut t, 0xdead_beef);
137 let n = read_send_nanos(&b, 0xdead_beef).expect("magic+sid match");
138 assert2::assert!(n > 0);
139 }
140
141 #[test]
142 fn rejects_wrong_scenario_id() {
143 let mut t = template(bytes(64));
144 let b = stamp_into(&mut t, 42);
145 assert2::assert!(read_send_nanos(&b, 7).is_none());
146 }
147
148 #[test]
149 fn rejects_short() {
150 assert2::assert!(read_send_nanos(&[0u8; 8], 0).is_none());
151 }
152
153 #[test]
154 fn rejects_bad_magic() {
155 let mut b = vec![0u8; HEADER_LEN];
156 b[16..24].copy_from_slice(&123u64.to_be_bytes());
157 assert2::assert!(read_send_nanos(&b, 0).is_none());
158 }
159
160 #[test]
161 fn template_size_honoured_above_header() {
162 assert2::assert!(template(kibibytes(1)).len() == 1024);
163 assert2::assert!(template(bytes(512)).len() == 512);
164 }
165
166 #[test]
167 fn template_min_size_is_header() {
168 assert2::assert!(template(ByteSize::ZERO).len() == HEADER_LEN);
169 }
170}