Skip to main content

mapping/
testing.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{DeliveryHandler, PageRequest};
6use delivery_blob::compression::{ChunkedArchiveError, DataBuffer};
7use fuchsia_sync::Mutex;
8use std::ops::{Deref, DerefMut, Range};
9use std::sync::Arc;
10use storage_ptr_slice::MutPtrByteSlice;
11use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
12
13#[derive(Clone, Copy, IntoBytes, FromBytes, KnownLayout, Immutable)]
14#[repr(C, align(64))]
15struct Block([u8; 64]);
16
17impl Default for Block {
18    fn default() -> Self {
19        Self([0u8; 64])
20    }
21}
22
23/// A byte buffer aligned to 64 bytes, ensuring compatibility with cryptographic and DMA operations.
24#[derive(Clone, Default)]
25pub struct AlignedBuffer {
26    blocks: Vec<Block>,
27    len: usize,
28}
29
30impl AlignedBuffer {
31    pub fn new(len: usize) -> Self {
32        let block_count = len.div_ceil(64);
33        Self { blocks: vec![Block::default(); block_count], len }
34    }
35
36    pub fn len(&self) -> usize {
37        self.len
38    }
39
40    pub fn is_empty(&self) -> bool {
41        self.len == 0
42    }
43
44    pub fn resize(&mut self, new_len: usize, val: u8) {
45        let block_count = new_len.div_ceil(64);
46        if block_count > self.blocks.len() {
47            self.blocks.resize(block_count, Block::default());
48        } else {
49            self.blocks.truncate(block_count);
50        }
51        if new_len > self.len {
52            self.blocks.as_mut_bytes()[self.len..new_len].fill(val);
53        }
54        self.len = new_len;
55    }
56
57    pub fn as_slice(&self) -> &[u8] {
58        &self.blocks.as_bytes()[..self.len]
59    }
60
61    pub fn as_mut_slice(&mut self) -> &mut [u8] {
62        &mut self.blocks.as_mut_bytes()[..self.len]
63    }
64
65    pub fn to_vec(&self) -> Vec<u8> {
66        self.as_slice().to_vec()
67    }
68}
69
70impl Deref for AlignedBuffer {
71    type Target = [u8];
72    fn deref(&self) -> &Self::Target {
73        self.as_slice()
74    }
75}
76
77impl DerefMut for AlignedBuffer {
78    fn deref_mut(&mut self) -> &mut Self::Target {
79        self.as_mut_slice()
80    }
81}
82
83#[derive(Default)]
84pub struct TestVecBufferInner {
85    pub commits: Vec<(u64, usize)>,
86    pub output: Vec<u8>,
87}
88
89#[derive(Clone)]
90pub struct TestVecBufferReceiver(pub Arc<Mutex<TestVecBufferInner>>);
91
92impl TestVecBufferReceiver {
93    pub fn commits(&self) -> Vec<(u64, usize)> {
94        self.0.lock().commits.clone()
95    }
96
97    pub fn output(&self) -> Vec<u8> {
98        self.0.lock().output.clone()
99    }
100}
101
102pub struct TestVecBuffer {
103    pub data: AlignedBuffer,
104    pub range: Range<u64>,
105    pub committed_len: usize,
106    pub offset: u64,
107    pub receiver: TestVecBufferReceiver,
108}
109
110impl TestVecBuffer {
111    pub fn new(size: usize) -> (Self, TestVecBufferReceiver) {
112        Self::new_with_offset(size, 0)
113    }
114
115    pub fn new_with_offset(size: usize, offset: u64) -> (Self, TestVecBufferReceiver) {
116        let receiver = TestVecBufferReceiver(Arc::new(Mutex::new(TestVecBufferInner::default())));
117        let range = offset..offset + size as u64;
118        let buf = Self {
119            data: AlignedBuffer::new(size),
120            range,
121            committed_len: 0,
122            offset,
123            receiver: receiver.clone(),
124        };
125        (buf, receiver)
126    }
127
128    pub fn new_with_range(range: Range<u64>) -> (Self, TestVecBufferReceiver) {
129        let size = (range.end - range.start) as usize;
130        let receiver = TestVecBufferReceiver(Arc::new(Mutex::new(TestVecBufferInner::default())));
131        let buf = Self {
132            data: AlignedBuffer::new(size),
133            offset: range.start,
134            range,
135            committed_len: 0,
136            receiver: receiver.clone(),
137        };
138        (buf, receiver)
139    }
140
141    pub fn new_unprepared() -> (Self, TestVecBufferReceiver) {
142        Self::new_unprepared_with_range(0..0)
143    }
144
145    pub fn new_unprepared_with_range(range: Range<u64>) -> (Self, TestVecBufferReceiver) {
146        let receiver = TestVecBufferReceiver(Arc::new(Mutex::new(TestVecBufferInner::default())));
147        let buf = Self {
148            data: AlignedBuffer::default(),
149            range,
150            committed_len: 0,
151            offset: 0,
152            receiver: receiver.clone(),
153        };
154        (buf, receiver)
155    }
156}
157
158impl DataBuffer for TestVecBuffer {
159    fn range(&self) -> Range<u64> {
160        self.range.clone()
161    }
162
163    fn mut_ptr_slice(&mut self) -> MutPtrByteSlice<'_> {
164        let remaining = &mut self.data[self.committed_len..];
165        MutPtrByteSlice::from(remaining)
166    }
167
168    fn commit(&mut self, size: usize) -> Result<(), ChunkedArchiveError> {
169        let mut inner = self.receiver.0.lock();
170        inner.commits.push((self.offset, size));
171        inner.output = self.data.to_vec();
172        self.offset += size as u64;
173        self.committed_len += size;
174        Ok(())
175    }
176}
177
178impl PageRequest for TestVecBuffer {
179    fn prepare(&mut self, read_range: Range<u64>) -> Result<(), ChunkedArchiveError> {
180        let size = (read_range.end - read_range.start) as usize;
181        if self.data.len() < size {
182            self.data.resize(size, 0);
183        }
184        self.range = read_range.clone();
185        self.offset = read_range.start;
186        Ok(())
187    }
188}
189
190/// A [`DeliveryHandler`] test adapter that implements `get_page_request` via a closure.
191///
192/// The closure takes `(key: u64, range: Range<u64>)` where:
193/// - `key`: The pager port key identifying the mapped file.
194/// - `range`: The byte range requested to be paged in.
195///
196/// And returns `R: PageRequest` (any type implementing [`PageRequest`]) to receive the paged data.
197///
198/// [`DeliveryHandler::register_blob`] defaults to a no-op `Ok(())`.
199pub struct TestDeliveryHandler<F>(pub F);
200
201impl<F, R: PageRequest> DeliveryHandler for TestDeliveryHandler<F>
202where
203    F: Fn(u64, Range<u64>) -> R + Send + Sync + 'static,
204{
205    type Request = R;
206
207    fn get_page_request(self: &Arc<Self>, key: u64, range: Range<u64>) -> Self::Request {
208        (self.0)(key, range)
209    }
210}