ranged_mmap/file/allocator/
sequential.rs1use super::{align_up, RangeAllocator};
6use crate::file::range::AllocatedRange;
7use std::num::NonZeroU64;
8
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Allocator {
49 next_pos: u64,
53
54 total_size: NonZeroU64,
58}
59
60impl Allocator {
61 #[inline]
82 pub fn allocate(&mut self, size: NonZeroU64) -> Option<AllocatedRange> {
83 let remaining = self.total_size.get().saturating_sub(self.next_pos);
84 if remaining == 0 {
85 return None;
86 }
87
88 let start = self.next_pos;
89 let aligned_size = align_up(size.get());
92 let actual_size = aligned_size.min(remaining);
94 let end = start + actual_size;
95 self.next_pos = end;
96
97 Some(AllocatedRange::from_range_unchecked(start, end))
98 }
99
100 #[inline]
104 pub fn remaining(&self) -> u64 {
105 self.total_size.get().saturating_sub(self.next_pos)
106 }
107
108 #[inline]
112 pub fn next_pos(&self) -> u64 {
113 self.next_pos
114 }
115}
116
117impl RangeAllocator for Allocator {
118 #[inline]
119 fn new(total_size: NonZeroU64) -> Self {
120 Self {
121 next_pos: 0,
122 total_size,
123 }
124 }
125
126 #[inline]
127 fn total_size(&self) -> NonZeroU64 {
128 self.total_size
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use crate::allocator::ALIGNMENT;
135 use super::*;
136
137 fn non_zero(val: u64) -> NonZeroU64 {
138 NonZeroU64::new(val).unwrap()
139 }
140
141 #[test]
142 fn test_sequential_basic_allocation() {
143 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10)); let range1 = allocator.allocate(non_zero(100)).unwrap();
148 assert_eq!(range1.start(), 0);
149 assert_eq!(range1.end(), ALIGNMENT); assert_eq!(range1.len(), ALIGNMENT);
151 }
152
153 #[test]
154 fn test_sequential_multiple_allocations() {
155 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10)); let range1 = allocator.allocate(non_zero(100)).unwrap();
159 assert_eq!(range1.start(), 0);
160 assert_eq!(range1.end(), ALIGNMENT);
161
162 let range2 = allocator.allocate(non_zero(150)).unwrap();
164 assert_eq!(range2.start(), ALIGNMENT);
165 assert_eq!(range2.end(), ALIGNMENT * 2);
166
167 let range3 = allocator.allocate(non_zero(200)).unwrap();
169 assert_eq!(range3.start(), ALIGNMENT * 2);
170 assert_eq!(range3.end(), ALIGNMENT * 3);
171 }
172
173 #[test]
174 fn test_sequential_exact_alignment() {
175 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10));
176
177 let range = allocator.allocate(non_zero(ALIGNMENT)).unwrap();
179 assert_eq!(range.start(), 0);
180 assert_eq!(range.end(), ALIGNMENT);
181 assert_eq!(range.len(), ALIGNMENT);
182
183 let range2 = allocator.allocate(non_zero(ALIGNMENT + 1)).unwrap();
185 assert_eq!(range2.start(), ALIGNMENT);
186 assert_eq!(range2.end(), ALIGNMENT * 3);
187 assert_eq!(range2.len(), ALIGNMENT * 2);
188 }
189
190 #[test]
191 fn test_sequential_partial_allocation() {
192 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 3));
194
195 allocator.allocate(non_zero(ALIGNMENT)).unwrap(); allocator.allocate(non_zero(ALIGNMENT)).unwrap(); let range = allocator.allocate(non_zero(ALIGNMENT * 2)).unwrap();
201 assert_eq!(range.start(), ALIGNMENT * 2);
202 assert_eq!(range.end(), ALIGNMENT * 3);
203 assert_eq!(range.len(), ALIGNMENT);
204 }
205
206 #[test]
207 fn test_sequential_exhausted() {
208 let mut allocator = Allocator::new(non_zero(ALIGNMENT));
209
210 let range = allocator.allocate(non_zero(100)).unwrap();
212 assert_eq!(range.len(), ALIGNMENT);
213
214 assert!(allocator.allocate(non_zero(1)).is_none());
216 }
217
218 #[test]
219 fn test_sequential_remaining() {
220 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 3)); assert_eq!(allocator.remaining(), ALIGNMENT * 3);
223 allocator.allocate(non_zero(100)).unwrap(); assert_eq!(allocator.remaining(), ALIGNMENT * 2);
225 allocator.allocate(non_zero(ALIGNMENT * 2)).unwrap(); assert_eq!(allocator.remaining(), 0);
227 }
228
229 #[test]
230 fn test_sequential_next_pos() {
231 let mut allocator = Allocator::new(non_zero(ALIGNMENT * 10));
232
233 assert_eq!(allocator.next_pos(), 0);
234 allocator.allocate(non_zero(100)).unwrap(); assert_eq!(allocator.next_pos(), ALIGNMENT);
236 allocator.allocate(non_zero(250)).unwrap(); assert_eq!(allocator.next_pos(), ALIGNMENT * 2);
238 }
239
240 #[test]
241 fn test_sequential_total_size() {
242 let allocator = Allocator::new(non_zero(12345));
243 assert_eq!(allocator.total_size().get(), 12345);
244 }
245}