1use super::{
5 Any, Buffer, MemoryDescriptor, Result, StorageError, StorageKind, nixl::NixlDescriptor,
6};
7
8#[derive(Clone)]
11pub struct OffsetBuffer {
12 base: Buffer,
13 offset: usize,
14 size: usize,
15}
16
17impl std::fmt::Debug for OffsetBuffer {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 f.debug_struct("OffsetBuffer")
20 .field("base", &self.base)
21 .field("offset", &self.offset)
22 .field("size", &self.size)
23 .finish()
24 }
25}
26
27impl OffsetBuffer {
28 pub fn new(base: Buffer, offset: usize, size: usize) -> Result<Self> {
32 let end = offset
33 .checked_add(size)
34 .ok_or_else(|| StorageError::Unsupported("offset overflow".into()))?;
35 if end > base.size() {
36 return Err(StorageError::Unsupported(
37 "offset region exceeds base allocation bounds".into(),
38 ));
39 }
40 Ok(Self { base, offset, size })
41 }
42
43 pub fn from_inner_address(base: Buffer, address: usize, size: usize) -> Result<Self> {
45 let end = address
47 .checked_add(size)
48 .ok_or_else(|| StorageError::Unsupported("address + size overflow".into()))?;
49 let base_end = base
50 .addr()
51 .checked_add(base.size())
52 .ok_or_else(|| StorageError::Unsupported("base address + size overflow".into()))?;
53
54 if address < base.addr() || end > base_end {
56 return Err(StorageError::Unsupported("address out of bounds".into()));
57 }
58
59 let offset = address - base.addr();
60 Self::new(base, offset, size)
61 }
62
63 pub fn offset(&self) -> usize {
65 self.offset
66 }
67
68 pub fn base(&self) -> &Buffer {
70 &self.base
71 }
72}
73
74impl MemoryDescriptor for OffsetBuffer {
75 fn addr(&self) -> usize {
76 self.base.addr() + self.offset
77 }
78
79 fn size(&self) -> usize {
80 self.size
81 }
82
83 fn storage_kind(&self) -> StorageKind {
84 self.base.storage_kind()
85 }
86
87 fn as_any(&self) -> &dyn Any {
88 self
89 }
90
91 fn nixl_descriptor(&self) -> Option<NixlDescriptor> {
92 let mut descriptor = self.base.nixl_descriptor()?;
93 descriptor.addr = self.addr() as u64;
94 descriptor.size = self.size();
95 Some(descriptor)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::SystemStorage;
103
104 fn create_test_buffer(size: usize) -> Buffer {
105 Buffer::new(SystemStorage::new(size).expect("allocation failed"))
106 }
107
108 #[test]
109 fn test_offset_buffer_new_valid() {
110 let base = create_test_buffer(1024);
111 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
112 assert_eq!(offset_buf.offset(), 100);
113 assert_eq!(offset_buf.size(), 200);
114 }
115
116 #[test]
117 fn test_offset_buffer_new_zero_offset() {
118 let base = create_test_buffer(1024);
119 let offset_buf = OffsetBuffer::new(base.clone(), 0, 1024).expect("should succeed");
120 assert_eq!(offset_buf.offset(), 0);
121 assert_eq!(offset_buf.size(), 1024);
122 assert_eq!(offset_buf.addr(), base.addr());
123 }
124
125 #[test]
126 fn test_offset_buffer_new_at_end() {
127 let base = create_test_buffer(1024);
128 let offset_buf = OffsetBuffer::new(base, 1024, 0).expect("should succeed");
130 assert_eq!(offset_buf.offset(), 1024);
131 assert_eq!(offset_buf.size(), 0);
132 }
133
134 #[test]
135 fn test_offset_buffer_new_invalid_offset() {
136 let base = create_test_buffer(1024);
137 let result = OffsetBuffer::new(base, 1025, 0);
139 assert!(result.is_err());
140 }
141
142 #[test]
143 fn test_offset_buffer_new_invalid_size() {
144 let base = create_test_buffer(1024);
145 let result = OffsetBuffer::new(base, 100, 1000);
147 assert!(result.is_err());
148 }
149
150 #[test]
151 fn test_offset_buffer_new_size_overflow() {
152 let base = create_test_buffer(1024);
153 let result = OffsetBuffer::new(base, usize::MAX, 1);
155 assert!(result.is_err());
156 }
157
158 #[test]
159 fn test_offset_buffer_from_inner_address_valid() {
160 let base = create_test_buffer(1024);
161 let base_addr = base.addr();
162 let offset_buf =
163 OffsetBuffer::from_inner_address(base, base_addr + 100, 200).expect("should succeed");
164 assert_eq!(offset_buf.offset(), 100);
165 assert_eq!(offset_buf.size(), 200);
166 }
167
168 #[test]
169 fn test_offset_buffer_from_inner_address_at_start() {
170 let base = create_test_buffer(1024);
171 let base_addr = base.addr();
172 let offset_buf = OffsetBuffer::from_inner_address(base.clone(), base_addr, 1024)
173 .expect("should succeed");
174 assert_eq!(offset_buf.offset(), 0);
175 assert_eq!(offset_buf.addr(), base.addr());
176 }
177
178 #[test]
179 fn test_offset_buffer_from_inner_address_overflow() {
180 let base = create_test_buffer(1024);
181 let result = OffsetBuffer::from_inner_address(base, usize::MAX, 1);
183 assert!(result.is_err());
184 }
185
186 #[test]
187 fn test_offset_buffer_from_inner_address_out_of_bounds_before() {
188 let base = create_test_buffer(1024);
189 let base_addr = base.addr();
190 let result = OffsetBuffer::from_inner_address(base, base_addr.saturating_sub(1), 100);
192 assert!(result.is_err());
193 }
194
195 #[test]
196 fn test_offset_buffer_from_inner_address_out_of_bounds_after() {
197 let base = create_test_buffer(1024);
198 let base_addr = base.addr();
199 let result = OffsetBuffer::from_inner_address(base, base_addr + 900, 200);
201 assert!(result.is_err());
202 }
203
204 #[test]
205 fn test_offset_buffer_accessors() {
206 let base = create_test_buffer(1024);
207 let base_addr = base.addr();
208 let offset_buf = OffsetBuffer::new(base, 256, 512).expect("should succeed");
209
210 assert_eq!(offset_buf.offset(), 256);
211 assert_eq!(offset_buf.base().addr(), base_addr);
212 assert_eq!(offset_buf.base().size(), 1024);
213 }
214
215 #[test]
216 fn test_offset_buffer_memory_descriptor_addr() {
217 let base = create_test_buffer(1024);
218 let base_addr = base.addr();
219 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
220
221 assert_eq!(offset_buf.addr(), base_addr + 100);
223 }
224
225 #[test]
226 fn test_offset_buffer_memory_descriptor_size() {
227 let base = create_test_buffer(1024);
228 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
229 assert_eq!(offset_buf.size(), 200);
230 }
231
232 #[test]
233 fn test_offset_buffer_memory_descriptor_storage_kind() {
234 let base = create_test_buffer(1024);
235 let base_kind = base.storage_kind();
236 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
237
238 assert_eq!(offset_buf.storage_kind(), base_kind);
240 }
241
242 #[test]
243 fn test_offset_buffer_as_any() {
244 let base = create_test_buffer(1024);
245 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
246
247 let any_ref = offset_buf.as_any();
249 assert!(any_ref.downcast_ref::<OffsetBuffer>().is_some());
250 }
251
252 #[test]
253 fn test_offset_buffer_clone() {
254 let base = create_test_buffer(1024);
255 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
256 let cloned = offset_buf.clone();
257
258 assert_eq!(offset_buf.addr(), cloned.addr());
259 assert_eq!(offset_buf.size(), cloned.size());
260 assert_eq!(offset_buf.offset(), cloned.offset());
261 }
262
263 #[test]
264 fn test_offset_buffer_debug() {
265 let base = create_test_buffer(1024);
266 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
267 let debug_str = format!("{:?}", offset_buf);
268
269 assert!(debug_str.contains("OffsetBuffer"));
270 assert!(debug_str.contains("offset"));
271 assert!(debug_str.contains("size"));
272 }
273
274 #[test]
275 fn test_offset_buffer_nixl_descriptor_none() {
276 let base = create_test_buffer(1024);
278 let offset_buf = OffsetBuffer::new(base, 100, 200).expect("should succeed");
279
280 assert!(offset_buf.nixl_descriptor().is_none());
282 }
283}