11_aa_custom_stream_callbacks/
11_aa_custom_stream_callbacks.rs1use compression::{
2 ArchiveStream, ByteStream, CustomArchiveStreamCallbacks, CustomByteStreamCallbacks, FieldKey,
3 Header,
4};
5use std::cell::RefCell;
6use std::collections::VecDeque;
7use std::rc::Rc;
8
9#[derive(Default)]
10struct MemoryByteState {
11 data: Vec<u8>,
12 position: usize,
13}
14
15#[derive(Clone)]
16struct SharedByteCallbacks {
17 inner: Rc<RefCell<MemoryByteState>>,
18}
19
20impl CustomByteStreamCallbacks for SharedByteCallbacks {
21 fn write(&mut self, buffer: &[u8]) -> compression::Result<usize> {
22 let mut state = self.inner.borrow_mut();
23 let start = state.position;
24 let end = start + buffer.len();
25 if end > state.data.len() {
26 state.data.resize(end, 0);
27 }
28 state.data[start..end].copy_from_slice(buffer);
29 state.position = end;
30 Ok(buffer.len())
31 }
32
33 fn read(&mut self, buffer: &mut [u8]) -> compression::Result<usize> {
34 let mut state = self.inner.borrow_mut();
35 let available = state.data.len().saturating_sub(state.position);
36 let count = available.min(buffer.len());
37 buffer[..count].copy_from_slice(&state.data[state.position..state.position + count]);
38 state.position += count;
39 Ok(count)
40 }
41
42 fn seek(&mut self, offset: i64, whence: i32) -> compression::Result<i64> {
43 let mut state = self.inner.borrow_mut();
44 let base = match whence {
45 0 => 0_i64,
46 1 => i64::try_from(state.position).unwrap_or(i64::MAX),
47 2 => i64::try_from(state.data.len()).unwrap_or(i64::MAX),
48 _ => return Ok(-1),
49 };
50 let next = base + offset;
51 state.position = usize::try_from(next).unwrap_or(0);
52 Ok(next)
53 }
54}
55
56#[derive(Default)]
57struct MemoryArchiveState {
58 headers: VecDeque<Vec<u8>>,
59 blobs: VecDeque<(FieldKey, Vec<u8>)>,
60}
61
62#[derive(Clone)]
63struct SharedArchiveCallbacks {
64 inner: Rc<RefCell<MemoryArchiveState>>,
65}
66
67impl CustomArchiveStreamCallbacks for SharedArchiveCallbacks {
68 fn write_header(&mut self, header: &Header) -> compression::Result<()> {
69 self.inner
70 .borrow_mut()
71 .headers
72 .push_back(header.encoded_data()?);
73 Ok(())
74 }
75
76 fn write_blob(&mut self, key: FieldKey, buffer: &[u8]) -> compression::Result<()> {
77 self.inner
78 .borrow_mut()
79 .blobs
80 .push_back((key, buffer.to_vec()));
81 Ok(())
82 }
83
84 fn read_header(&mut self) -> compression::Result<Option<Header>> {
85 let Some(header) = self.inner.borrow_mut().headers.pop_front() else {
86 return Ok(None);
87 };
88 Ok(Some(Header::from_encoded_data(&header)?))
89 }
90
91 fn read_blob(&mut self, key: FieldKey, buffer: &mut [u8]) -> compression::Result<()> {
92 let (expected_key, bytes) = self.inner.borrow_mut().blobs.pop_front().expect("blob");
93 assert_eq!(expected_key, key);
94 buffer.copy_from_slice(&bytes);
95 Ok(())
96 }
97}
98
99fn main() -> Result<(), Box<dyn std::error::Error>> {
100 let byte_state = Rc::new(RefCell::new(MemoryByteState::default()));
101 let mut stream = ByteStream::custom(SharedByteCallbacks { inner: byte_state })?;
102 stream.write_all(b"hello custom stream")?;
103 stream.seek(0, 0)?;
104 let mut buffer = vec![0_u8; 19];
105 stream.read(&mut buffer)?;
106 assert_eq!(&buffer, b"hello custom stream");
107
108 let archive_state = Rc::new(RefCell::new(MemoryArchiveState::default()));
109 let mut writer = ArchiveStream::custom(SharedArchiveCallbacks {
110 inner: archive_state.clone(),
111 })?;
112 let mut header = Header::new()?;
113 header.append_field_uint(FieldKey::TYP, u64::from(b'F'))?;
114 header.append_field_string(FieldKey::PAT, "custom.txt")?;
115 header.append_field_uint(FieldKey::SIZ, buffer.len() as u64)?;
116 header.append_field_blob(FieldKey::DAT, buffer.len() as u64)?;
117 writer.write_header(&header)?;
118 writer.write_blob(FieldKey::DAT, &buffer)?;
119
120 let mut reader = ArchiveStream::custom(SharedArchiveCallbacks {
121 inner: archive_state,
122 })?;
123 let decoded_header = reader.read_header()?.expect("header");
124 assert_eq!(decoded_header.path()?.as_deref(), Some("custom.txt"));
125 let mut decoded = vec![0_u8; buffer.len()];
126 reader.read_blob(FieldKey::DAT, &mut decoded)?;
127 assert_eq!(decoded, buffer);
128
129 println!("✅ Custom AppleArchive byte/archive stream callbacks OK");
130 Ok(())
131}