use crate::raw::{VarInt, WireType, I32, I64};
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
use core::cmp;
pub(crate) const APPROXIMATE_DEPTH: usize = 32;
mod cursor;
mod visit;
pub use self::cursor::*;
#[derive(Debug)]
pub struct ProtoBufMut<T> {
bytes: Vec<u8>,
chunks: Vec<LenPrefixedChunk>,
root_state: T,
len_stack: Vec<LenStackFrame<T>>,
}
#[derive(Clone, Debug)]
pub struct ProtoBuf {
bytes: Box<[u8]>,
chunks: Box<[LenPrefixedChunk]>,
}
#[derive(Debug)]
struct LenStackFrame<T> {
len: usize,
head: usize,
chunk_idx: usize,
state: T,
}
#[derive(Debug, Clone, Copy)]
struct LenPrefixedChunk {
varint: Option<u64>,
start: usize,
}
impl<T> ProtoBufMut<T> {
#[inline(always)]
pub fn new(state: T) -> Self {
ProtoBufMut {
bytes: Vec::new(),
chunks: Vec::with_capacity(APPROXIMATE_DEPTH),
root_state: state,
len_stack: Vec::with_capacity(APPROXIMATE_DEPTH),
}
}
#[inline(always)]
pub fn new_reuse(mut reuse: ProtoBufMutReusable<T>, state: T) -> Self {
reuse.len_stack.clear();
ProtoBufMut {
bytes: Vec::with_capacity(reuse.capacity.bytes_len),
chunks: Vec::with_capacity(reuse.capacity.chunks_len),
root_state: state,
len_stack: reuse.len_stack,
}
}
#[inline(always)]
pub fn depth(&self) -> usize {
self.len_stack.len()
}
#[inline(always)]
pub fn push_varint(&mut self, v: VarInt) {
self.push(v.fill_bytes(&mut [0; 10]));
}
#[inline(always)]
pub fn push_varint_uint64(&mut self, v: u64) {
self.push_varint(VarInt::uint64(v));
}
#[inline(always)]
pub fn push_varint_sint64(&mut self, v: i64) {
self.push_varint(VarInt::sint64(v));
}
#[inline(always)]
pub fn push_varint_sint64z(&mut self, v: i64) {
self.push_varint(VarInt::sint64z(v));
}
#[inline(always)]
pub fn push_varint_bool(&mut self, v: bool) {
self.push_varint(VarInt::bool(v));
}
#[inline(always)]
pub fn push_varint_enum32(&mut self, v: i32) {
self.push_varint(VarInt::enum32(v));
}
#[inline(always)]
pub fn push_i32(&mut self, v: I32) {
self.push(&v.to_bytes());
}
#[inline(always)]
pub fn push_i32_float(&mut self, v: f32) {
self.push_i32(I32::float(v));
}
#[inline(always)]
pub fn push_i32_fixed32(&mut self, v: u32) {
self.push_i32(I32::fixed32(v));
}
#[inline(always)]
pub fn push_i32_sfixed32(&mut self, v: i32) {
self.push_i32(I32::sfixed32(v));
}
#[inline(always)]
pub fn push_i64(&mut self, v: I64) {
self.push(&v.to_bytes());
}
#[inline(always)]
pub fn push_i64_double(&mut self, v: f64) {
self.push_i64(I64::double(v));
}
#[inline(always)]
pub fn push_i64_fixed64(&mut self, v: u64) {
self.push_i64(I64::fixed64(v));
}
#[inline(always)]
pub fn push_i64_sfixed64(&mut self, v: i64) {
self.push_i64(I64::sfixed64(v));
}
#[inline(always)]
pub fn push(&mut self, b: &[u8]) {
self.bytes.extend_from_slice(b);
}
#[inline(always)]
pub fn push_field(&mut self, field_number: u64, wire_type: WireType) {
self.push_varint(VarInt::field(field_number, wire_type));
}
#[inline(always)]
pub fn push_field_varint(&mut self, field_number: u64) {
self.push_field(field_number, WireType::VarInt);
}
#[inline(always)]
pub fn push_field_i64(&mut self, field_number: u64) {
self.push_field(field_number, WireType::I64);
}
#[inline(always)]
pub fn push_field_i32(&mut self, field_number: u64) {
self.push_field(field_number, WireType::I32);
}
#[inline(always)]
pub fn push_field_len(&mut self, field_number: u64) {
self.push_field(field_number, WireType::Len);
}
#[inline(always)]
pub fn push_len_varint_uint64(&mut self, len: u64) {
self.push_varint_uint64(len);
}
#[inline]
pub(crate) fn reserve(&mut self, num_entries: usize) {
self.bytes.reserve((256 * num_entries) / (self.depth() + 1));
}
#[inline]
pub(crate) fn reserve_bytes(&mut self, num_bytes: usize) {
self.bytes.reserve(num_bytes);
}
pub fn begin_len(&mut self, state: T) {
if let Some(parent) = self.len_stack.last_mut() {
parent.len += self.bytes.len() - parent.head;
parent.head = self.bytes.len();
}
self.len_stack.push(LenStackFrame {
len: 0,
head: self.bytes.len(),
chunk_idx: self.chunks.len(),
state,
});
self.chunks.push(LenPrefixedChunk {
varint: None,
start: self.bytes.len(),
});
}
pub fn state_mut(&mut self) -> &mut T {
self.len_stack
.last_mut()
.map(|frame| &mut frame.state)
.unwrap_or(&mut self.root_state)
}
pub fn end_len(&mut self) {
if let Some(frame) = self.len_stack.pop() {
let len = frame.len + (self.bytes.len() - frame.head);
self.chunks[frame.chunk_idx].varint = Some(len as u64);
if let Some(parent) = self.len_stack.last_mut() {
parent.len += len + VarInt::uint64(len as u64).len();
parent.head = self.bytes.len();
}
}
}
#[inline]
pub fn freeze_reuse(self) -> (ProtoBuf, ProtoBufMutReusable<T>) {
let protobuf = ProtoBuf {
bytes: self.bytes.into_boxed_slice(),
chunks: self.chunks.into_boxed_slice(),
};
let len_stack = self.len_stack;
let reusable = ProtoBufMutReusable {
capacity: Capacity {
bytes_len: protobuf.len(),
chunks_len: protobuf.chunks.len(),
},
len_stack,
};
(protobuf, reusable)
}
#[inline(always)]
pub fn freeze(self) -> ProtoBuf {
ProtoBuf {
bytes: self.bytes.into_boxed_slice(),
chunks: self.chunks.into_boxed_slice(),
}
}
}
impl ProtoBuf {
pub fn pre_encoded(buf: impl Into<Box<[u8]>>) -> Self {
ProtoBuf {
bytes: buf.into(),
chunks: [].into(),
}
}
pub fn len(&self) -> usize {
visit::len(&self.bytes, &self.chunks)
}
pub fn to_vec(&self) -> Cow<'_, [u8]> {
visit::to_vec(&self.bytes, &self.chunks)
}
pub fn into_cursor(self) -> ProtoBufCursor {
ProtoBufCursor::new(self.bytes, self.chunks)
}
}
impl sval::Value for ProtoBuf {
fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
visit::to_stream(&self.bytes, &self.chunks, stream)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Capacity {
bytes_len: usize,
chunks_len: usize,
}
impl Capacity {
pub fn new() -> Self {
Self::default()
}
pub fn next(window: &[Capacity]) -> Capacity {
let mut bytes_len = 0;
let mut chunks_len = 0;
for capacity in window {
bytes_len = cmp::max(bytes_len, capacity.bytes_len);
chunks_len = cmp::max(chunks_len, capacity.chunks_len);
}
Capacity {
bytes_len: bytes_len.saturating_add(bytes_len.saturating_mul(2) / 4),
chunks_len: chunks_len.saturating_add(chunks_len.saturating_mul(2) / 4),
}
}
}
pub struct ProtoBufMutReusable<T> {
capacity: Capacity,
len_stack: Vec<LenStackFrame<T>>,
}
impl<T> Clone for ProtoBufMutReusable<T> {
fn clone(&self) -> Self {
ProtoBufMutReusable {
capacity: self.capacity,
len_stack: Vec::with_capacity(self.len_stack.capacity()),
}
}
}
impl<T> Default for ProtoBufMutReusable<T> {
fn default() -> Self {
ProtoBufMutReusable {
capacity: Default::default(),
len_stack: Default::default(),
}
}
}
impl<T> ProtoBufMutReusable<T> {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(mut self, capacity: Capacity) -> Self {
self.capacity = capacity;
self
}
pub fn capacity(&self) -> Capacity {
self.capacity
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn capacity_next() {
let window = [
Capacity {
bytes_len: 13,
chunks_len: 2,
},
Capacity {
bytes_len: 2,
chunks_len: 13,
},
];
let capacity = Capacity::next(&window);
assert_eq!(19, capacity.bytes_len);
assert_eq!(19, capacity.chunks_len);
}
}