use std::cell::RefCell;
use super::audit_context::AuditCtx;
#[derive(Debug, Clone)]
pub struct BufferedDdl {
pub payload: Vec<u8>,
pub audit: Option<AuditCtx>,
}
pub type DdlBuffer = Vec<BufferedDdl>;
thread_local! {
static ACTIVE_BUFFER: RefCell<Option<DdlBuffer>> = const { RefCell::new(None) };
}
pub fn activate() {
ACTIVE_BUFFER.with(|b| {
let mut guard = b.borrow_mut();
if guard.is_none() {
*guard = Some(Vec::new());
}
});
}
pub fn try_buffer(payload: Vec<u8>) -> bool {
ACTIVE_BUFFER.with(|b| {
let mut guard = b.borrow_mut();
if let Some(buf) = guard.as_mut() {
buf.push(BufferedDdl {
payload,
audit: super::audit_context::current(),
});
true
} else {
false
}
})
}
pub fn take() -> Option<DdlBuffer> {
ACTIVE_BUFFER.with(|b| b.borrow_mut().take())
}
pub fn discard() {
ACTIVE_BUFFER.with(|b| {
let _ = b.borrow_mut().take();
});
}
pub fn is_active() -> bool {
ACTIVE_BUFFER.with(|b| b.borrow().is_some())
}
pub fn buffer_len() -> usize {
ACTIVE_BUFFER.with(|b| b.borrow().as_ref().map(|v| v.len()).unwrap_or(0))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inactive_buffer_does_not_capture() {
discard(); assert!(!try_buffer(vec![1, 2, 3]));
assert!(!is_active());
}
#[test]
fn active_buffer_captures() {
activate();
assert!(is_active());
assert!(try_buffer(vec![1]));
assert!(try_buffer(vec![2]));
let buf = take().unwrap();
assert_eq!(buf.len(), 2);
assert_eq!(buf[0].payload, vec![1]);
assert_eq!(buf[1].payload, vec![2]);
assert!(!is_active());
}
#[test]
fn discard_clears_buffer() {
activate();
try_buffer(vec![1]);
discard();
assert!(!is_active());
assert!(take().is_none());
}
#[test]
fn take_on_inactive_returns_none() {
discard();
assert!(take().is_none());
}
}