Skip to main content

randomio/block/
block.rs

1/// Data block at a specific offset
2///
3/// The buffer type `B` is generic and can be any type that implements
4/// `AsRef<[u8]> + Send`, allowing for:
5/// - `bytes::Bytes` — zero-copy slices
6/// - `Vec<u8>` — owned buffers
7/// - `Box<[u8]>` — boxed slices
8/// - DMA buffers
9/// - Custom zero-copy types
10///
11/// The default buffer type is `bytes::Bytes`, which provides zero-copy
12/// slices for I/O operations.
13#[cfg(feature = "bytes")]
14pub struct Block<B = bytes::Bytes> {
15    /// Absolute byte offset where the block starts
16    pub offset: u64,
17    /// Buffer containing the block data
18    pub data: B,
19}
20
21/// Data block at a specific offset
22///
23/// The buffer type `B` is generic and can be any type that implements
24/// `AsRef<[u8]> + Send`, allowing for:
25/// - `Vec<u8>` — owned buffers
26/// - `Box<[u8]>` — boxed slices
27/// - DMA buffers
28/// - Custom zero-copy types
29#[cfg(not(feature = "bytes"))]
30pub struct Block<B> {
31    /// Absolute byte offset where the block starts
32    pub offset: u64,
33    /// Buffer containing the block data
34    pub data: B,
35}
36
37impl<B: AsRef<[u8]>> Block<B> {
38    /// Create a new block at the given offset with the given data
39    #[inline]
40    pub const fn new(offset: u64, data: B) -> Self {
41        Self { offset, data }
42    }
43
44    /// Returns the range covered by this block
45    #[inline]
46    pub fn range(&self) -> crate::Range {
47        let len = self.data.as_ref().len() as u64;
48        crate::Range::new(self.offset, self.offset.saturating_add(len))
49    }
50
51    /// Returns the length of the block data
52    #[inline]
53    pub fn len(&self) -> usize {
54        self.data.as_ref().len()
55    }
56
57    /// Returns true if the block has no data
58    #[inline]
59    pub fn is_empty(&self) -> bool {
60        self.data.as_ref().is_empty()
61    }
62}
63
64impl<B: AsRef<[u8]>> AsRef<[u8]> for Block<B> {
65    #[inline]
66    fn as_ref(&self) -> &[u8] {
67        self.data.as_ref()
68    }
69}
70
71impl<B: AsRef<[u8]> + Clone> Clone for Block<B> {
72    fn clone(&self) -> Self {
73        Self {
74            offset: self.offset,
75            data: self.data.clone(),
76        }
77    }
78}
79
80impl<B: AsRef<[u8]> + core::fmt::Debug> core::fmt::Debug for Block<B> {
81    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82        f.debug_struct("Block")
83            .field("offset", &self.offset)
84            .field("len", &self.len())
85            .field("data", &self.data)
86            .finish()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_block_basic() {
96        let data = alloc::vec![1, 2, 3, 4, 5];
97        let block = Block::new(100, data);
98
99        assert_eq!(block.offset, 100);
100        assert_eq!(block.len(), 5);
101        assert!(!block.is_empty());
102        assert_eq!(block.as_ref(), &[1, 2, 3, 4, 5]);
103    }
104
105    #[test]
106    fn test_block_range() {
107        let block = Block::new(100, alloc::vec![1, 2, 3, 4, 5]);
108        let range = block.range();
109
110        assert_eq!(range.start, 100);
111        assert_eq!(range.end, 105);
112    }
113
114    #[test]
115    fn test_block_empty() {
116        let block = Block::new(100, alloc::vec::Vec::<u8>::new());
117        assert!(block.is_empty());
118        assert_eq!(block.len(), 0);
119        assert_eq!(block.range().start, 100);
120        assert_eq!(block.range().end, 100);
121    }
122
123    #[test]
124    fn test_block_clone() {
125        let block = Block::new(50, alloc::vec![10, 20, 30]);
126        let cloned = block.clone();
127
128        assert_eq!(cloned.offset, block.offset);
129        assert_eq!(cloned.len(), block.len());
130        assert_eq!(cloned.as_ref(), block.as_ref());
131    }
132
133    #[test]
134    fn test_block_zero_offset() {
135        let block = Block::new(0, alloc::vec![1, 2, 3]);
136        assert_eq!(block.offset, 0);
137        assert_eq!(block.range().start, 0);
138        assert_eq!(block.range().end, 3);
139    }
140
141    #[test]
142    fn test_block_large_offset() {
143        let large_offset = u64::MAX - 100;
144        let block = Block::new(large_offset, alloc::vec![1, 2, 3]);
145        assert_eq!(block.offset, large_offset);
146        assert_eq!(block.range().start, large_offset);
147    }
148
149    #[test]
150    fn test_block_single_byte() {
151        let block = Block::new(1000, alloc::vec![42]);
152        assert_eq!(block.len(), 1);
153        assert_eq!(block.as_ref(), &[42]);
154        assert!(!block.is_empty());
155    }
156
157    #[test]
158    fn test_block_box_slice() {
159        let data: alloc::boxed::Box<[u8]> = alloc::vec![1, 2, 3, 4].into_boxed_slice();
160        let block = Block::new(500, data);
161
162        assert_eq!(block.offset, 500);
163        assert_eq!(block.len(), 4);
164        assert_eq!(block.as_ref(), &[1, 2, 3, 4]);
165    }
166
167    #[cfg(feature = "std")]
168    #[test]
169    fn test_block_debug() {
170        let block = Block::new(123, vec![1, 2, 3]);
171        let debug_str = format!("{:?}", block);
172        assert!(debug_str.contains("Block"));
173        assert!(debug_str.contains("123")); // offset
174        assert!(debug_str.contains("3")); // len
175    }
176
177    #[cfg(feature = "bytes")]
178    #[test]
179    fn test_block_with_bytes() {
180        use bytes::Bytes;
181
182        let data = Bytes::from_static(b"hello world");
183        let block = Block::new(2000, data);
184
185        assert_eq!(block.offset, 2000);
186        assert_eq!(block.len(), 11);
187        assert_eq!(block.as_ref(), b"hello world");
188        assert_eq!(block.range(), crate::Range::new(2000, 2011));
189    }
190
191    #[cfg(feature = "bytes")]
192    #[test]
193    fn test_block_bytes_clone() {
194        use bytes::Bytes;
195
196        let data = Bytes::from_static(b"test data");
197        let block = Block::new(100, data);
198        let cloned = block.clone();
199
200        // Bytes cloning is shallow (cheap)
201        assert_eq!(cloned.offset, block.offset);
202        assert_eq!(cloned.as_ref(), block.as_ref());
203    }
204}