#[cfg(feature = "atomic")]
use bstack::BStack;
#[cfg(feature = "atomic")]
use std::io;
#[cfg(feature = "atomic")]
const SENTINEL: u64 = u64::MAX;
#[cfg(feature = "atomic")]
const HEADER_SIZE: usize = 16;
#[cfg(feature = "atomic")]
fn main() -> io::Result<()> {
let path = "linked_list_example.bstack";
let _ = std::fs::remove_file(path);
let stack = BStack::open(path)?;
let mut blocks = [
"This example ",
"demonstrates ",
"the usage of ",
"get_batched_gen ",
"generator pattern",
];
blocks.reverse();
let mut head_offset = SENTINEL; for block in blocks.iter() {
let data_bytes = block.as_bytes();
let data_size = data_bytes.len() as u64;
let mut node = Vec::with_capacity(HEADER_SIZE + data_bytes.len());
node.extend_from_slice(&head_offset.to_le_bytes()); node.extend_from_slice(&data_size.to_le_bytes()); node.extend_from_slice(data_bytes);
head_offset = stack.push(&node)?;
}
println!(
"Built {}-node list; head at offset {}",
blocks.len(),
head_offset
);
let mut buffer = Vec::new(); let mut header = [0u8; HEADER_SIZE]; let mut node_info: Vec<(usize, u64)> = Vec::new();
let mut current_offset = head_offset;
let mut current_pos = 0usize;
let mut reading_header = true;
stack.get_batched_gen(|| {
if current_offset == SENTINEL || node_info.len() >= 100 {
return None;
}
if reading_header {
reading_header = false;
let buf_slice =
unsafe { std::slice::from_raw_parts_mut(header.as_mut_ptr(), HEADER_SIZE) };
Some((current_offset, buf_slice))
} else {
let next_offset = u64::from_le_bytes(header[..8].try_into().unwrap());
let data_size = u64::from_le_bytes(header[8..].try_into().unwrap()) as usize;
let data_file_offset = current_offset + HEADER_SIZE as u64;
buffer.resize(current_pos + data_size, 0);
let buf_ptr = buffer[current_pos..current_pos + data_size].as_mut_ptr();
node_info.push((data_size, next_offset));
current_offset = next_offset;
current_pos += data_size;
reading_header = true;
let buf_slice = unsafe { std::slice::from_raw_parts_mut(buf_ptr, data_size) };
Some((data_file_offset, buf_slice))
}
})?;
let node_count = node_info.len();
println!("\nTraversed {} nodes under a single lock", node_count);
println!("Total buffer size: {} bytes", buffer.len());
let mut pos = 0usize;
for (i, &(data_size, next_offset)) in node_info.iter().enumerate() {
let data = &buffer[pos..pos + data_size];
let text = std::str::from_utf8(data).unwrap();
println!(
" Node {}: size={}, text={:?}, next={}",
i,
data_size,
text,
if next_offset == SENTINEL {
"null".to_string()
} else {
next_offset.to_string()
}
);
pos += data_size;
}
println!(
"\nReconstructed text: {:?}",
std::str::from_utf8(&buffer).unwrap()
);
println!(
"Expected: \"This example demonstrates the usage of get_batched_gen generator pattern\""
);
Ok(())
}
#[cfg(not(feature = "atomic"))]
fn main() {
eprintln!("This example requires the 'atomic' feature.");
eprintln!("Run: cargo run --example linked_list --features atomic");
}