#![allow(dead_code)]
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
use beve::Value;
use serde::{Deserialize, Serialize};
static LIVE_BYTES: AtomicUsize = AtomicUsize::new(0);
static PEAK_BYTES: AtomicUsize = AtomicUsize::new(0);
struct TrackingAllocator;
unsafe impl GlobalAlloc for TrackingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = unsafe { System.alloc(layout) };
if !ptr.is_null() {
grew(layout.size());
}
ptr
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let ptr = unsafe { System.alloc_zeroed(layout) };
if !ptr.is_null() {
grew(layout.size());
}
ptr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) };
shrank(layout.size());
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let out = unsafe { System.realloc(ptr, layout, new_size) };
if !out.is_null() {
if new_size >= layout.size() {
grew(new_size - layout.size());
} else {
shrank(layout.size() - new_size);
}
}
out
}
}
#[global_allocator]
static ALLOCATOR: TrackingAllocator = TrackingAllocator;
fn grew(bytes: usize) {
let live = LIVE_BYTES.fetch_add(bytes, Ordering::Relaxed) + bytes;
PEAK_BYTES.fetch_max(live, Ordering::Relaxed);
}
fn shrank(bytes: usize) {
LIVE_BYTES.fetch_sub(bytes, Ordering::Relaxed);
}
fn peak_growth<T>(f: impl FnOnce() -> T) -> (T, usize) {
let base = LIVE_BYTES.load(Ordering::Relaxed);
PEAK_BYTES.store(base, Ordering::Relaxed);
let out = f();
let peak = PEAK_BYTES.load(Ordering::Relaxed);
(out, peak.saturating_sub(base))
}
fn allocation_bound(input_len: usize) -> usize {
const RESERVE_CEILING: usize = 8 * 1024 * 1024;
const PER_INPUT_BYTE: usize = 1024;
RESERVE_CEILING
.saturating_mul(beve::MAX_RECURSION_DEPTH)
.saturating_add(input_len.saturating_mul(PER_INPUT_BYTE))
}
pub fn decode_arbitrary(data: &[u8]) {
let (_, peak) = peak_growth(|| {
let _ = beve::from_slice::<Value>(data);
let _ = beve::validate_slice(data);
});
let bound = allocation_bound(data.len());
assert!(
peak <= bound,
"decoding {} bytes reached {peak} live bytes, over the {bound}-byte bound",
data.len()
);
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Message {
id: u32,
payload: Payload,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
enum Payload {
Telemetry(Vec<f64>),
MetaOnly(Meta),
Snapshot { label: String, counters: Vec<u32> },
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
enum Meta {
Unit,
Codes(Vec<u32>),
Window { start: u64, metrics: Vec<f32> },
}
struct Generator<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> Generator<'a> {
fn new(data: &'a [u8]) -> Self {
Generator { data, pos: 0 }
}
fn byte(&mut self) -> u8 {
let b = self.data.get(self.pos).copied().unwrap_or(0);
self.pos = self.pos.saturating_add(1);
b
}
fn array<const N: usize>(&mut self) -> [u8; N] {
let mut out = [0u8; N];
for slot in out.iter_mut() {
*slot = self.byte();
}
out
}
fn u32(&mut self) -> u32 {
u32::from_le_bytes(self.array::<4>())
}
fn u64(&mut self) -> u64 {
u64::from_le_bytes(self.array::<8>())
}
fn f32(&mut self) -> f32 {
let v = f32::from_bits(self.u32());
if v.is_finite() { v } else { 0.0 }
}
fn f64(&mut self) -> f64 {
let v = f64::from_bits(self.u64());
if v.is_finite() { v } else { 0.0 }
}
fn len(&mut self, max: usize) -> usize {
(self.byte() as usize) % (max + 1)
}
fn variant(&mut self, count: u8) -> u8 {
self.byte() % count
}
fn message(&mut self) -> Message {
Message {
id: self.u32(),
payload: self.payload(),
}
}
fn payload(&mut self) -> Payload {
match self.variant(3) {
0 => Payload::Telemetry((0..self.len(47)).map(|_| self.f64()).collect()),
1 => Payload::MetaOnly(self.meta()),
_ => Payload::Snapshot {
label: self.label(),
counters: (0..self.len(31)).map(|_| self.u32()).collect(),
},
}
}
fn meta(&mut self) -> Meta {
match self.variant(3) {
0 => Meta::Unit,
1 => Meta::Codes((0..self.len(23)).map(|_| self.u32()).collect()),
_ => Meta::Window {
start: self.u64(),
metrics: (0..self.len(23)).map(|_| self.f32()).collect(),
},
}
}
fn label(&mut self) -> String {
const ALPHABET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
let n = 1 + self.len(23);
(0..n)
.map(|_| ALPHABET[self.byte() as usize % ALPHABET.len()] as char)
.collect()
}
}
pub fn roundtrip(data: &[u8]) {
let message = Generator::new(data).message();
let buffered = beve::to_vec(&message).expect("buffered encode of a generated message");
let mut streamed = Vec::new();
beve::to_writer_streaming(&mut streamed, &message)
.expect("streaming encode of a generated message");
let measured = beve::serialized_size(&message).expect("serialized_size of a generated message");
assert_eq!(
measured,
streamed.len() as u64,
"serialized_size disagreed with the streamed length for {message:?}"
);
for (name, bytes) in [("buffered", &buffered), ("streamed", &streamed)] {
beve::validate_slice(bytes)
.unwrap_or_else(|e| panic!("{name} encoding failed validation: {e:?} for {message:?}"));
let decoded: Message = beve::from_slice(bytes)
.unwrap_or_else(|e| panic!("buffered decode of {name} encoding: {e:?}"));
assert_eq!(decoded, message, "buffered decode of {name} encoding");
let streamed_back: Message = beve::from_reader_streaming(std::io::Cursor::new(bytes))
.unwrap_or_else(|e| panic!("streaming decode of {name} encoding: {e:?}"));
assert_eq!(
streamed_back, message,
"streaming decode of {name} encoding"
);
}
}