use perfetto_sdk_sys::*;
use std::{cell::RefCell, ptr, slice};
pub struct StreamWriter {
pub(crate) writer: RefCell<PerfettoStreamWriter>,
}
impl StreamWriter {
pub fn new() -> Self {
Self::default()
}
pub fn available_bytes(&self) -> usize {
let writer = self.writer.borrow_mut();
assert!(writer.end >= writer.write_ptr);
unsafe { writer.end.offset_from(writer.write_ptr) as usize }
}
pub fn append_bytes_unchecked(&self, src: &[u8]) {
assert!(src.len() <= self.available_bytes());
let mut writer = self.writer.borrow_mut();
assert!(!writer.impl_.is_null());
unsafe { ptr::copy_nonoverlapping(src.as_ptr(), writer.write_ptr, src.len()) };
writer.write_ptr = writer.write_ptr.wrapping_add(src.len());
}
pub fn append_bytes(&self, src: &[u8]) {
if crate::__likely!(src.len() <= self.available_bytes()) {
self.append_bytes_unchecked(src);
return;
}
let mut writer = self.writer.borrow_mut();
assert!(!writer.impl_.is_null());
unsafe {
PerfettoStreamWriterAppendBytesSlowpath(&mut *writer as *mut _, src.as_ptr(), src.len())
};
}
pub fn append_byte(&self, value: u8) {
let mut writer = self.writer.borrow_mut();
assert!(!writer.impl_.is_null());
if crate::__unlikely!(self.available_bytes() < 1) {
unsafe { PerfettoStreamWriterNewChunk(&mut *writer as *mut _) };
}
assert!(1 <= self.available_bytes());
unsafe { ptr::write(writer.write_ptr, value) };
writer.write_ptr = writer.write_ptr.wrapping_add(1);
}
#[allow(clippy::mut_from_ref)]
pub fn reserve_bytes_unchecked(&self, size: usize) -> &mut [u8] {
assert!(size <= self.available_bytes());
let mut writer = self.writer.borrow_mut();
assert!(!writer.impl_.is_null());
let start_ptr = writer.write_ptr;
writer.write_ptr = writer.write_ptr.wrapping_add(size);
unsafe { slice::from_raw_parts_mut(start_ptr, size) }
}
#[allow(clippy::mut_from_ref)]
pub fn reserve_bytes(&self, size: usize) -> &mut [u8] {
if crate::__likely!(size <= self.available_bytes()) {
return self.reserve_bytes_unchecked(size);
}
let mut writer = self.writer.borrow_mut();
assert!(!writer.impl_.is_null());
unsafe { PerfettoStreamWriterReserveBytesSlowpath(&mut *writer as *mut _, size) };
let start_ptr = writer.write_ptr.wrapping_sub(size);
unsafe { slice::from_raw_parts_mut(start_ptr, size) }
}
pub fn get_written_size(&self) -> usize {
let writer = self.writer.borrow();
assert!(writer.begin <= writer.write_ptr);
let bytes_written = unsafe { writer.write_ptr.offset_from(writer.begin) as usize };
writer.written_previously + bytes_written
}
pub(crate) fn has_valid_writer(&self) -> bool {
!self.writer.borrow().impl_.is_null()
}
}
impl Default for StreamWriter {
fn default() -> Self {
Self {
writer: RefCell::new(PerfettoStreamWriter {
impl_: ptr::null_mut(),
begin: ptr::null_mut(),
end: ptr::null_mut(),
write_ptr: ptr::null_mut(),
written_previously: 0,
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn initial_state() {
let writer = StreamWriter::new();
assert_eq!(writer.available_bytes(), 0);
assert_eq!(writer.get_written_size(), 0);
}
}