1use std::ops::Range;
7
8use bytes::Bytes;
9use vortex_buffer::Buffer;
10use vortex_buffer::ConstByteBuffer;
11use vortex_error::VortexExpect;
12
13pub unsafe trait IoBuf: Unpin + Send + 'static {
18 fn read_ptr(&self) -> *const u8;
20
21 fn bytes_init(&self) -> usize;
23
24 fn as_slice(&self) -> &[u8];
26
27 #[inline]
29 fn slice_owned(self, range: Range<usize>) -> OwnedSlice<Self>
30 where
31 Self: Sized,
32 {
33 assert!(
35 range.start <= range.end,
36 "Invalid range: start ({}) must be <= end ({})",
37 range.start,
38 range.end
39 );
40 assert!(
41 range.end <= self.bytes_init(),
42 "Range end ({}) exceeds buffer length ({})",
43 range.end,
44 self.bytes_init()
45 );
46
47 OwnedSlice {
48 buf: self,
49 begin: range.start,
50 end: range.end,
51 }
52 }
53}
54
55pub struct OwnedSlice<T> {
57 buf: T,
58 begin: usize,
59 end: usize,
60}
61
62impl<T> OwnedSlice<T> {
63 pub fn into_inner(self) -> T {
65 self.buf
66 }
67}
68
69unsafe impl IoBuf for &'static [u8] {
70 #[inline]
71 fn read_ptr(&self) -> *const u8 {
72 self.as_ptr()
73 }
74
75 #[inline]
76 fn bytes_init(&self) -> usize {
77 self.len()
78 }
79
80 #[inline]
81 fn as_slice(&self) -> &[u8] {
82 self
83 }
84}
85
86unsafe impl<const N: usize> IoBuf for [u8; N] {
87 #[inline]
88 fn read_ptr(&self) -> *const u8 {
89 self.as_ptr()
90 }
91
92 #[inline]
93 fn bytes_init(&self) -> usize {
94 N
95 }
96
97 #[inline]
98 fn as_slice(&self) -> &[u8] {
99 self.as_ref()
100 }
101}
102
103unsafe impl IoBuf for Vec<u8> {
104 #[inline]
105 fn read_ptr(&self) -> *const u8 {
106 self.as_ptr()
107 }
108
109 #[inline]
110 fn bytes_init(&self) -> usize {
111 self.len()
112 }
113
114 #[inline]
115 fn as_slice(&self) -> &[u8] {
116 self.as_ref()
117 }
118}
119
120unsafe impl<T: IoBuf> IoBuf for OwnedSlice<T> {
121 #[inline]
122 fn read_ptr(&self) -> *const u8 {
123 debug_assert!(self.begin <= self.end, "Invalid slice bounds");
124 debug_assert!(
125 self.end <= self.buf.bytes_init(),
126 "Slice end exceeds buffer bounds"
127 );
128
129 let base_ptr = self.buf.read_ptr();
130 debug_assert!(!base_ptr.is_null(), "Base pointer is null");
131
132 #[cfg(debug_assertions)]
134 {
135 let max_offset = isize::MAX as usize;
136 assert!(
137 self.begin <= max_offset,
138 "Offset too large for pointer arithmetic"
139 );
140 }
141
142 unsafe { base_ptr.add(self.begin) }
143 }
144
145 #[inline]
146 fn bytes_init(&self) -> usize {
147 debug_assert!(self.begin <= self.end, "Invalid slice bounds");
148 self.end - self.begin
149 }
150
151 #[inline]
152 fn as_slice(&self) -> &[u8] {
153 let ptr = self.read_ptr();
154 let len = self.bytes_init();
155
156 debug_assert!(
157 !ptr.is_null() || len == 0,
158 "Null pointer with non-zero length"
159 );
160
161 unsafe { std::slice::from_raw_parts(ptr, len) }
162 }
163}
164
165unsafe impl IoBuf for Bytes {
166 fn read_ptr(&self) -> *const u8 {
167 self.as_ptr()
168 }
169
170 fn bytes_init(&self) -> usize {
171 self.len()
172 }
173
174 fn as_slice(&self) -> &[u8] {
175 self.as_ref()
176 }
177}
178
179unsafe impl<const A: usize> IoBuf for ConstByteBuffer<A> {
180 fn read_ptr(&self) -> *const u8 {
181 self.as_ptr()
182 }
183
184 fn bytes_init(&self) -> usize {
185 self.len()
186 }
187
188 fn as_slice(&self) -> &[u8] {
189 self.as_ref()
190 }
191}
192
193unsafe impl<T: Unpin + Send + 'static> IoBuf for Buffer<T> {
194 fn read_ptr(&self) -> *const u8 {
195 self.as_ptr().cast()
196 }
197
198 fn bytes_init(&self) -> usize {
199 self.len()
200 .checked_mul(size_of::<T>())
201 .vortex_expect("Buffer size calculation overflow")
202 }
203
204 fn as_slice(&self) -> &[u8] {
205 unsafe { std::slice::from_raw_parts(self.read_ptr(), self.bytes_init()) }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use rstest::rstest;
212
213 use super::*;
214
215 #[test]
216 fn test_static_slice_io_buf() {
217 let data: &'static [u8] = b"hello world";
218
219 assert_eq!(data.read_ptr(), data.as_ptr());
220 assert_eq!(data.bytes_init(), 11);
221 assert_eq!(IoBuf::as_slice(&data), b"hello world");
222 }
223
224 #[test]
225 fn test_static_empty_slice() {
226 let data: &'static [u8] = b"";
227
228 assert_eq!(data.bytes_init(), 0);
229 assert_eq!(IoBuf::as_slice(&data), b"");
230 }
231
232 #[rstest]
233 #[case([1u8, 2, 3, 4, 5], 5)]
234 #[case([0u8; 256], 256)]
235 #[case([255u8; 1], 1)]
236 fn test_array_io_buf<const N: usize>(#[case] array: [u8; N], #[case] expected_len: usize) {
237 assert_eq!(array.bytes_init(), expected_len);
238 assert_eq!(IoBuf::as_slice(&array), array.as_slice());
239 assert_eq!(array.read_ptr(), array.as_ptr());
240 }
241
242 #[test]
243 fn test_vec_io_buf() {
244 let vec = vec![1u8, 2, 3, 4, 5];
245
246 assert_eq!(vec.read_ptr(), vec.as_ptr());
247 assert_eq!(vec.bytes_init(), 5);
248 assert_eq!(IoBuf::as_slice(&vec), &[1, 2, 3, 4, 5]);
249 }
250
251 #[rstest]
252 #[case(vec![], 0)]
253 #[case(vec![42u8], 1)]
254 #[case(vec![1u8, 2, 3], 3)]
255 #[case(vec![0u8; 1024], 1024)]
256 fn test_vec_various_sizes(#[case] vec: Vec<u8>, #[case] expected_len: usize) {
257 assert_eq!(vec.bytes_init(), expected_len);
258 assert_eq!(IoBuf::as_slice(&vec).len(), expected_len);
259 }
260
261 #[rstest]
262 #[case(vec![1u8, 2, 3, 4, 5], 0..5, vec![1, 2, 3, 4, 5])]
263 #[case(vec![1u8, 2, 3, 4, 5], 1..4, vec![2, 3, 4])]
264 #[case(vec![1u8, 2, 3, 4, 5], 2..3, vec![3])]
265 #[case(vec![1u8, 2, 3, 4, 5], 0..0, vec![])]
266 #[case(vec![1u8, 2, 3, 4, 5], 5..5, vec![])]
267 fn test_owned_slice_ranges(
268 #[case] data: Vec<u8>,
269 #[case] range: Range<usize>,
270 #[case] expected: Vec<u8>,
271 ) {
272 let slice = data.slice_owned(range.clone());
273 assert_eq!(slice.bytes_init(), range.end - range.start);
274 assert_eq!(slice.as_slice(), &expected[..]);
275 }
276
277 #[test]
278 fn test_nested_owned_slice() {
279 let data = vec![1u8, 2, 3, 4, 5, 6, 7, 8];
280 let slice1 = data.slice_owned(1..7); let slice2 = slice1.slice_owned(1..4); assert_eq!(slice2.bytes_init(), 3);
284 assert_eq!(slice2.as_slice(), &[3, 4, 5]);
285 }
286
287 #[test]
288 fn test_bytes_io_buf() {
289 let bytes = Bytes::from_static(b"test data");
290
291 assert_eq!(bytes.read_ptr(), bytes.as_ptr());
292 assert_eq!(bytes.bytes_init(), 9);
293 assert_eq!(bytes.as_slice(), b"test data");
294 }
295
296 #[test]
297 fn test_bytes_empty() {
298 let bytes = Bytes::new();
299
300 assert_eq!(bytes.bytes_init(), 0);
301 assert_eq!(bytes.as_slice(), b"");
302 }
303
304 #[test]
305 fn test_const_byte_buffer() {
306 const ALIGNMENT: usize = 64;
307 let data = b"aligned data".to_vec();
308 let buffer = ConstByteBuffer::<ALIGNMENT>::copy_from(&data);
309
310 assert_eq!(buffer.bytes_init(), 12);
311 assert_eq!(IoBuf::as_slice(&buffer), b"aligned data");
312
313 let ptr_addr = buffer.read_ptr() as usize;
315 assert_eq!(ptr_addr % ALIGNMENT, 0);
316 }
317
318 macro_rules! test_const_buffer_alignment {
319 ($name:ident, $alignment:literal) => {
320 #[test]
321 fn $name() {
322 let data = b"test".to_vec();
323 let buffer = ConstByteBuffer::<$alignment>::copy_from(&data);
324 let ptr_addr = buffer.read_ptr() as usize;
325 assert_eq!(ptr_addr % $alignment, 0);
326 assert_eq!(buffer.bytes_init(), 4);
327 }
328 };
329 }
330
331 test_const_buffer_alignment!(test_const_byte_buffer_alignment_8, 8);
332 test_const_buffer_alignment!(test_const_byte_buffer_alignment_16, 16);
333 test_const_buffer_alignment!(test_const_byte_buffer_alignment_32, 32);
334 test_const_buffer_alignment!(test_const_byte_buffer_alignment_128, 128);
335 test_const_buffer_alignment!(test_const_byte_buffer_alignment_256, 256);
336
337 #[test]
338 fn test_buffer_u32() {
339 let data = vec![1u32, 2, 3, 4];
340 let mut buf_mut = vortex_buffer::BufferMut::<u32>::with_capacity(4);
341 buf_mut.extend_from_slice(&data);
342 let buffer: Buffer<u32> = buf_mut.freeze();
343
344 assert_eq!(buffer.len(), 4); assert_eq!(buffer.bytes_init(), 16); }
348
349 #[test]
350 fn test_buffer_empty() {
351 let buffer: Buffer<u8> = Buffer::from(vec![]);
352
353 assert_eq!(buffer.bytes_init(), 0);
354 assert_eq!(IoBuf::as_slice(&buffer), &[] as &[u8]);
355 }
356
357 #[test]
358 fn test_buffer_various_types() {
359 let buffer = Buffer::from(vec![1u8, 2, 3]);
361 assert_eq!(buffer.bytes_init(), 3);
362
363 let mut buf_mut = vortex_buffer::BufferMut::<u16>::with_capacity(3);
365 buf_mut.extend_from_slice(&[1u16, 2, 3]);
366 let buffer: Buffer<u16> = buf_mut.freeze();
367 assert_eq!(buffer.bytes_init(), 6);
368
369 let mut buf_mut = vortex_buffer::BufferMut::<u32>::with_capacity(3);
371 buf_mut.extend_from_slice(&[1u32, 2, 3]);
372 let buffer: Buffer<u32> = buf_mut.freeze();
373 assert_eq!(buffer.bytes_init(), 12);
374
375 let mut buf_mut = vortex_buffer::BufferMut::<u64>::with_capacity(3);
377 buf_mut.extend_from_slice(&[1u64, 2, 3]);
378 let buffer: Buffer<u64> = buf_mut.freeze();
379 assert_eq!(buffer.bytes_init(), 24);
380 }
381
382 #[test]
383 fn test_slice_owned_preserves_data() {
384 let original = vec![10u8, 20, 30, 40, 50];
385 let slice = original.clone().slice_owned(1..4);
386
387 assert_eq!(slice.as_slice(), &[20, 30, 40]);
389
390 let recovered = slice.into_inner();
392 assert_eq!(recovered, original);
393 }
394
395 #[test]
397 #[should_panic(expected = "Invalid range")]
398 fn test_owned_slice_invalid_range() {
399 let data = vec![1, 2, 3];
400 #[expect(
401 clippy::reversed_empty_ranges,
402 reason = "intentionally testing invalid range"
403 )]
404 data.slice_owned(5..3); }
406
407 #[test]
408 #[should_panic(expected = "exceeds buffer length")]
409 fn test_owned_slice_out_of_bounds() {
410 let data = vec![1, 2, 3];
411 data.slice_owned(1..10); }
413
414 #[test]
415 #[should_panic(expected = "exceeds buffer length")]
416 fn test_owned_slice_start_out_of_bounds() {
417 let data = vec![1, 2, 3];
418 data.slice_owned(10..11); }
420
421 #[test]
423 fn test_buffer_size_calculation_large_type() {
424 use vortex_buffer::BufferMut;
425
426 #[repr(C)]
428 struct LargeType {
429 _data: [u8; 1024],
430 }
431
432 let mut buf = BufferMut::<LargeType>::with_capacity(10);
433 for _ in 0..10 {
435 buf.push(LargeType { _data: [0u8; 1024] });
436 }
437 let buffer = buf.freeze();
438
439 let size = buffer.bytes_init();
441 assert_eq!(size, 10 * 1024);
442 }
443
444 #[test]
445 fn test_buffer_size_near_max() {
446 let large_size = 1_000_000;
448 let buffer: Buffer<u8> = Buffer::from(vec![0u8; large_size]);
449 assert_eq!(buffer.bytes_init(), large_size);
450 }
451}