├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── examples └── ex.rs ├── README.md ├── LICENSE └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "ring_buffer_no_std" 7 | version = "0.1.1" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ring_buffer_no_std" 3 | description = "A ring buffer supporting no_std" 4 | version = "0.1.1" 5 | edition = "2024" 6 | keywords = ["no_std"] 7 | license-file = "LICENSE" 8 | 9 | [dependencies] 10 | 11 | [[example]] 12 | name="ex" 13 | -------------------------------------------------------------------------------- /examples/ex.rs: -------------------------------------------------------------------------------- 1 | use ring_buffer_no_std::RingBuffer; 2 | 3 | fn main() { 4 | const SIZE: usize = 4096; // 4KB buffer 5 | let mut rb: RingBuffer = RingBuffer::new(); 6 | 7 | for i in 0..SIZE { 8 | rb.push(i as u32).unwrap(); 9 | } 10 | println!("len={}", rb.len()); 11 | 12 | let mut buffer = [0; 5]; 13 | let _ = rb.read(&mut buffer); 14 | println!("data={:?}", buffer); 15 | 16 | let _ = rb.read(&mut buffer); 17 | println!("data={:?}", buffer); 18 | println!("len={}", rb.len()); 19 | 20 | for _ in 0..rb.len() { 21 | rb.pop(); 22 | } 23 | 24 | println!("is empty={}", rb.is_empty()); 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ring_buffer_no_std 2 | 3 | example: 4 | ```rust 5 | use ring_buffer_no_std::RingBuffer; 6 | 7 | fn main() { 8 | const SIZE: usize = 4096; // 4KB buffer 9 | let mut rb: RingBuffer = RingBuffer::new(); 10 | 11 | for i in 0..SIZE { 12 | rb.push(i as u32).unwrap(); 13 | } 14 | println!("len={}", rb.len()); 15 | 16 | let mut buffer = [0; 5]; 17 | let _ = rb.read(&mut buffer); 18 | println!("data={:?}", buffer); 19 | 20 | let _ = rb.read(&mut buffer); 21 | println!("data={:?}", buffer); 22 | println!("len={}", rb.len()); 23 | 24 | for _ in 0..rb.len() { 25 | rb.pop(); 26 | } 27 | 28 | println!("is empty={}", rb.is_empty()); 29 | } 30 | 31 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 ThinkCode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | /// 4 | /// 5 | /// A simple ring buffer implementation in Rust. 6 | /// This ring buffer supports fixed-size storage and provides methods for pushing, popping, and reading data. 7 | /// It is designed to be efficient and easy to use, with a focus on performance and safety. 8 | /// 9 | /// # Example 10 | /// ``` 11 | /// use ring_buffer_no_std::RingBuffer; 12 | /// let mut rb: RingBuffer = RingBuffer::new(); 13 | /// rb.push(42).unwrap(); 14 | /// let item = rb.pop(); 15 | /// assert_eq!(item, Some(42)); 16 | /// ``` 17 | /// 18 | 19 | #[derive(Debug)] 20 | pub enum RingBufferError { 21 | Full, 22 | BeyondRange, 23 | BufferIncomplete, 24 | } 25 | 26 | pub struct RingBuffer 27 | where 28 | T: Default + Copy, 29 | { 30 | buffer: [T; S], 31 | head: usize, 32 | tail: usize, 33 | len: usize, 34 | } 35 | 36 | impl RingBuffer 37 | where 38 | T: Default + Copy, 39 | { 40 | /** 41 | * Creates a new instance of `RingBuffer` with a fixed size. 42 | * ``` 43 | * use ring_buffer_no_std::RingBuffer; 44 | * let mut rb: RingBuffer = RingBuffer::new(); 45 | * ``` 46 | */ 47 | pub fn new() -> Self { 48 | RingBuffer { 49 | buffer: [T::default(); S], 50 | head: 0, 51 | tail: 0, 52 | len: 0, 53 | } 54 | } 55 | 56 | /** 57 | * Pushes an item into the ring buffer. 58 | * Returns an error if the buffer is full. 59 | * ``` 60 | * use ring_buffer_no_std::RingBuffer; 61 | * let mut rb: RingBuffer = RingBuffer::new(); 62 | * rb.push(42).unwrap(); 63 | * ``` 64 | */ 65 | pub fn push(&mut self, item: T) -> Result<(), RingBufferError> { 66 | if self.len == S { 67 | return Err(RingBufferError::Full); 68 | } 69 | self.buffer[self.head] = item; 70 | self.head = (self.head + 1) % S; 71 | self.len += 1; 72 | Ok(()) 73 | } 74 | 75 | /** 76 | * Pops an item from the ring buffer. 77 | * Returns `None` if the buffer is empty. 78 | * ``` 79 | * use ring_buffer_no_std::RingBuffer; 80 | * let mut rb: RingBuffer = RingBuffer::new(); 81 | * rb.push(42).unwrap(); 82 | * let item = rb.pop(); 83 | * assert_eq!(item, Some(42)); 84 | * ``` 85 | */ 86 | pub fn pop(&mut self) -> Option { 87 | if self.len == 0 { 88 | return None; 89 | } 90 | let item = self.buffer[self.tail]; 91 | self.tail = (self.tail + 1) % S; 92 | self.len -= 1; 93 | Some(item) 94 | } 95 | 96 | /** 97 | * Clears the ring buffer, resetting its state. 98 | * ``` 99 | * use ring_buffer_no_std::RingBuffer; 100 | * let mut rb: RingBuffer = RingBuffer::new(); 101 | * rb.push(42).unwrap(); 102 | * rb.clear(); 103 | * assert!(rb.is_empty()); 104 | * ``` 105 | */ 106 | pub fn clear(&mut self) { 107 | self.head = 0; 108 | self.tail = 0; 109 | self.len = 0; 110 | } 111 | 112 | /** 113 | * Pops a specified number of items from the ring buffer. 114 | * Returns an error if the count exceeds the current length of the buffer. 115 | * ``` 116 | * use ring_buffer_no_std::RingBuffer; 117 | * let mut rb: RingBuffer = RingBuffer::new(); 118 | * rb.push(1).unwrap(); 119 | * rb.push(2).unwrap(); 120 | * let remaining_capacity = rb.pop_continuous(1).unwrap(); 121 | * assert_eq!(remaining_capacity, 4095); 122 | * ``` 123 | */ 124 | pub fn pop_continuous(&mut self, count: usize) -> Result { 125 | if count > self.len { 126 | return Result::Err(RingBufferError::BeyondRange); 127 | } 128 | self.tail = (self.tail + count) % S; 129 | self.len -= count; 130 | 131 | Ok(self.remaining_capacity()) 132 | } 133 | 134 | /** 135 | * Returns the capacity of the ring buffer. 136 | * ``` 137 | * use ring_buffer_no_std::RingBuffer; 138 | * let mut rb: RingBuffer = RingBuffer::new(); 139 | * assert_eq!(rb.capacity(), 4096); 140 | * ``` 141 | */ 142 | #[inline] 143 | pub fn capacity(&self) -> usize { 144 | S 145 | } 146 | 147 | /** 148 | * Returns the remaining capacity of the ring buffer. 149 | * ``` 150 | * use ring_buffer_no_std::RingBuffer; 151 | * let mut rb: RingBuffer = RingBuffer::new(); 152 | * assert_eq!(rb.remaining_capacity(), 4096); 153 | * rb.push(1).unwrap(); 154 | * assert_eq!(rb.remaining_capacity(), 4095); 155 | * ``` 156 | */ 157 | #[inline] 158 | pub fn remaining_capacity(&self) -> usize { 159 | S - self.len 160 | } 161 | 162 | /** 163 | * Checks if the ring buffer is empty. 164 | */ 165 | #[inline] 166 | pub fn is_empty(&self) -> bool { 167 | self.len == 0 168 | } 169 | /** 170 | * Checks if the ring buffer is full. 171 | */ 172 | #[inline] 173 | pub fn is_full(&self) -> bool { 174 | self.len == S 175 | } 176 | /** 177 | * Returns the current length of the ring buffer. 178 | */ 179 | #[inline] 180 | pub fn len(&self) -> usize { 181 | self.len 182 | } 183 | 184 | /** 185 | * Writes a slice of data into the ring buffer. 186 | * Returns an error if the buffer is full. 187 | * ``` 188 | * use ring_buffer_no_std::RingBuffer; 189 | * let mut rb: RingBuffer = RingBuffer::new(); 190 | * rb.write(&[1, 2, 3, 4]).unwrap(); 191 | * ``` 192 | */ 193 | pub fn write(&mut self, data: &[T]) -> Result<(), RingBufferError> { 194 | for &item in data { 195 | self.push(item)?; 196 | } 197 | Ok(()) 198 | } 199 | 200 | /** 201 | * Reads data from the ring buffer into a provided mutable slice. 202 | * Returns the number of items read. 203 | * If the buffer has fewer items than the slice, it fills as many as possible. 204 | * ``` 205 | * use ring_buffer_no_std::RingBuffer; 206 | * let mut rb: RingBuffer = RingBuffer::new(); 207 | * rb.push(1).unwrap(); 208 | * rb.push(2).unwrap(); 209 | * let mut buffer = [0; 5]; 210 | * let read_count = rb.read(&mut buffer); 211 | * assert_eq!(read_count, 2); 212 | * assert_eq!(&buffer[..read_count], &[1, 2]); 213 | * ``` 214 | */ 215 | pub fn read(&mut self, buffer: &mut [T]) -> usize { 216 | for i in 0..buffer.len() { 217 | if let Some(item) = self.pop() { 218 | buffer[i] = item; 219 | } else { 220 | return i; 221 | } 222 | } 223 | buffer.len() 224 | } 225 | 226 | 227 | /** 228 | * Reads a slice of data from the ring buffer. 229 | * Returns an error if the requested length exceeds the current length of the buffer. 230 | * If the data is contiguous, it returns a slice; otherwise, it returns an error. 231 | * ``` 232 | * use ring_buffer_no_std::RingBuffer; 233 | * let mut rb: RingBuffer = RingBuffer::new(); 234 | * rb.push(1).unwrap(); 235 | * rb.push(2).unwrap(); 236 | * let slice = rb.read_slice(2).unwrap(); 237 | * assert_eq!(slice, &[1, 2]); 238 | * ``` 239 | */ 240 | pub fn read_slice<'a>(&'a self, len: usize) -> Result<&'a [T], RingBufferError> { 241 | if len > self.len { 242 | return Err(RingBufferError::BeyondRange); 243 | } 244 | if self.tail < self.head { 245 | // Data is contiguous 246 | Ok(&self.buffer[self.tail..self.tail + len]) 247 | } else if self.tail + len <= S { 248 | // Data is contiguous from tail to end of buffer 249 | Ok(&self.buffer[self.tail..self.tail + len]) 250 | } else { 251 | // Data wraps around, cannot return as a single slice 252 | Err(RingBufferError::BufferIncomplete) 253 | } 254 | } 255 | } 256 | 257 | #[cfg(test)] 258 | mod tests { 259 | use super::*; 260 | 261 | #[test] 262 | fn it_works() { 263 | const SIZE: usize = 4096; // 4KB buffer 264 | let mut rb: RingBuffer = RingBuffer::new(); 265 | assert!(rb.is_empty()); 266 | assert!(!rb.is_full()); 267 | 268 | for i in 0..SIZE { 269 | rb.push(i as u32).unwrap(); 270 | } 271 | assert_eq!(rb.len(), SIZE); 272 | assert!(!rb.is_empty()); 273 | assert!(rb.is_full()); 274 | 275 | let mut buffer = [0; 5]; 276 | let read_count = rb.read(&mut buffer); 277 | assert_eq!(read_count, 5); 278 | assert_eq!(&buffer[..5], &[0, 1, 2, 3, 4]); 279 | 280 | let read_count = rb.read(&mut buffer); 281 | assert_eq!(read_count, 5); 282 | assert_eq!(&buffer[..5], &[5, 6, 7, 8, 9]); 283 | assert_eq!(rb.len(), SIZE - 10); 284 | assert!(!rb.is_full()); 285 | assert!(!rb.is_empty()); 286 | assert_eq!(rb.remaining_capacity(), SIZE - rb.len()); 287 | 288 | rb.clear(); 289 | assert!(rb.is_empty()); 290 | 291 | for i in 0..SIZE { 292 | rb.push(i as u32).unwrap(); 293 | } 294 | let slice = rb.read_slice(10).unwrap(); 295 | assert_eq!(rb.len(), SIZE); 296 | assert_eq!(slice, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 297 | let remaining_capacity = rb.pop_continuous(10).unwrap(); 298 | assert_eq!(remaining_capacity, 10); 299 | assert_eq!(rb.len(), SIZE - 10); 300 | let slice = rb.read_slice(10).unwrap(); 301 | assert_eq!(slice, &[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]); 302 | assert_eq!(rb.len(), SIZE - 10); 303 | 304 | 305 | for _ in 0..rb.len() { 306 | rb.pop(); 307 | } 308 | 309 | assert!(rb.is_empty()); 310 | 311 | assert_eq!(size_of::>(), 32); 312 | assert_eq!(size_of::>(), 32); 313 | assert_eq!(size_of::>(), 32); 314 | assert_eq!(size_of::>(), 32); 315 | assert_eq!(size_of::>(), 40); 316 | assert_eq!(size_of::>(), 56); 317 | assert_eq!(size_of::>(), 88); 318 | assert_eq!(size_of::>(), 152); 319 | assert_eq!(size_of::>(), 280); 320 | assert_eq!(size_of::>(), 536); 321 | assert_eq!(size_of::>(), 1048); 322 | assert_eq!(size_of::>(), 4120); 323 | assert_eq!(size_of::>(), 40); // 10 * 4 bytes for u8 + 3 * 4 bytes for usize 324 | } 325 | 326 | 327 | } 328 | --------------------------------------------------------------------------------