use core::cell::Cell;
use core::ptr::NonNull;
pub struct MaxBuf {
pub owned_by_subprocess: Cell<bool>,
pub owned_by_reader: Cell<bool>,
pub remaining_bytes: Cell<i64>,
}
impl MaxBuf {
#[inline]
fn live<'a>(this: &'a NonNull<MaxBuf>) -> &'a MaxBuf {
unsafe { this.as_ref() }
}
pub fn create_for_subprocess(ptr: &mut Option<NonNull<MaxBuf>>, initial: Option<i64>) {
let Some(initial) = initial else {
*ptr = None;
return;
};
*ptr = Some(bun_core::heap::into_raw_nn(Box::new(MaxBuf {
owned_by_subprocess: Cell::new(true),
owned_by_reader: Cell::new(false),
remaining_bytes: Cell::new(initial),
})));
}
fn disowned(&self) -> bool {
!self.owned_by_subprocess.get() && !self.owned_by_reader.get()
}
fn destroy(this: NonNull<MaxBuf>) {
debug_assert!(Self::live(&this).disowned());
drop(unsafe { bun_core::heap::take(this.as_ptr()) });
}
pub fn remove_from_subprocess(ptr: &mut Option<NonNull<MaxBuf>>) {
let Some(this_nn) = *ptr else { return };
let this = Self::live(&this_nn);
debug_assert!(this.owned_by_subprocess.get());
this.owned_by_subprocess.set(false);
*ptr = None;
if this.disowned() {
MaxBuf::destroy(this_nn);
}
}
pub fn add_to_pipereader(value: Option<NonNull<MaxBuf>>, ptr: &mut Option<NonNull<MaxBuf>>) {
let Some(value_nn) = value else { return };
debug_assert!(ptr.is_none());
*ptr = Some(value_nn);
let v = Self::live(&value_nn);
debug_assert!(!v.owned_by_reader.get());
v.owned_by_reader.set(true);
}
pub fn remove_from_pipereader(ptr: &mut Option<NonNull<MaxBuf>>) {
let Some(this_nn) = *ptr else { return };
let this = Self::live(&this_nn);
debug_assert!(this.owned_by_reader.get());
this.owned_by_reader.set(false);
*ptr = None;
if this.disowned() {
MaxBuf::destroy(this_nn);
}
}
pub fn transfer_to_pipereader(
prev: &mut Option<NonNull<MaxBuf>>,
next: &mut Option<NonNull<MaxBuf>>,
) {
if prev.is_none() {
return;
}
*next = *prev;
*prev = None;
}
pub fn on_read_bytes(this: NonNull<MaxBuf>, bytes: u64) -> bool {
let this = Self::live(&this);
let delta = i64::try_from(bytes).unwrap_or(0);
let remaining = this.remaining_bytes.get().checked_sub(delta).unwrap_or(-1);
this.remaining_bytes.set(remaining);
remaining < 0 && this.owned_by_subprocess.get()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
Stdout,
Stderr,
}