1#![no_std]
64#![deny(missing_docs)]
65#![allow(async_fn_in_trait)]
66
67#[cfg(feature = "std")]
68extern crate std;
69
70mod error;
75pub use error::{Error, ErrorKind, Result};
76
77#[cfg(feature = "std")]
79pub use std::path::{Path, PathBuf};
80
81pub use embedded_io::SeekFrom;
83
84pub trait IoError: embedded_io::Error {}
86impl<T: embedded_io::Error + ?Sized> IoError for T {}
87
88#[macro_export]
113macro_rules! try_io_result_option {
114 ($expr:expr) => {
115 match $expr {
116 Ok(val) => val,
117 Err(err) => return Some(Err(err.erase())),
118 }
119 };
120}
121
122#[derive(Debug, Clone)]
148pub struct Cursor<'a> {
149 data: &'a [u8],
150 cursor: usize,
151}
152
153impl<'a> Cursor<'a> {
154 pub fn new(data: &'a [u8]) -> Self {
165 Self { data, cursor: 0 }
166 }
167
168 pub fn position(&self) -> usize {
179 self.cursor
180 }
181
182 pub fn set_position(&mut self, pos: usize) {
192 self.cursor = pos;
193 }
194
195 pub fn get_ref(&self) -> &'a [u8] {
205 self.data
206 }
207
208 #[cfg(any(feature = "sync", feature = "async", test))]
209 fn read_impl(&mut self, buf: &mut [u8]) -> core::result::Result<usize, ErrorKind> {
210 let remaining = self.data.len().saturating_sub(self.cursor);
211 let to_read = buf.len().min(remaining);
212 if to_read > 0 {
213 buf[..to_read].copy_from_slice(&self.data[self.cursor..self.cursor + to_read]);
214 self.cursor += to_read;
215 }
216 Ok(to_read)
217 }
218
219 #[cfg(any(feature = "sync", feature = "async", test))]
220 fn seek_impl(&mut self, pos: SeekFrom) -> core::result::Result<u64, ErrorKind> {
221 let new_pos = match pos {
222 SeekFrom::Start(offset) => offset as i64,
223 SeekFrom::End(offset) => self.data.len() as i64 + offset,
224 SeekFrom::Current(offset) => self.cursor as i64 + offset,
225 };
226
227 if new_pos < 0 {
228 return Err(ErrorKind::InvalidInput);
229 }
230
231 self.cursor = new_pos as usize;
232 Ok(self.cursor as u64)
233 }
234}
235
236#[cfg(feature = "sync")]
241mod sync_api;
242
243#[cfg(feature = "sync")]
249pub mod sync {
250 pub use super::sync_api::*;
251}
252
253#[cfg(feature = "sync")]
255impl sync::Read for Cursor<'_> {
256 type Error = ErrorKind;
257
258 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
259 self.read_impl(buf).map_err(Error::from_source)
260 }
261}
262
263#[cfg(feature = "sync")]
264impl sync::Seek for Cursor<'_> {
265 type Error = ErrorKind;
266
267 fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
268 self.seek_impl(pos).map_err(Error::from_source)
269 }
270}
271
272#[cfg(feature = "sync")]
274pub use sync::*;
275
276#[cfg(feature = "async")]
281mod async_api;
282
283#[cfg(feature = "async")]
288pub mod r#async {
289 pub use super::async_api::*;
290}
291
292#[cfg(feature = "async")]
294impl r#async::Read for Cursor<'_> {
295 type Error = ErrorKind;
296
297 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
298 self.read_impl(buf).map_err(Error::from_source)
299 }
300}
301
302#[cfg(feature = "async")]
303impl r#async::Seek for Cursor<'_> {
304 type Error = ErrorKind;
305
306 async fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
307 self.seek_impl(pos).map_err(Error::from_source)
308 }
309}
310
311#[cfg(all(test, feature = "sync"))]
312mod tests {
313 extern crate std;
314 use super::*;
315 use std::format;
316
317 #[test]
322 fn cursor_new_starts_at_zero() {
323 let data = [1, 2, 3, 4, 5];
324 let cursor = Cursor::new(&data);
325 assert_eq!(cursor.position(), 0);
326 assert_eq!(cursor.get_ref(), &data);
327 }
328
329 #[test]
330 fn cursor_set_position() {
331 let data = [0u8; 10];
332 let mut cursor = Cursor::new(&data);
333 cursor.set_position(5);
334 assert_eq!(cursor.position(), 5);
335 cursor.set_position(0);
336 assert_eq!(cursor.position(), 0);
337 }
338
339 #[test]
340 fn cursor_read_basic() {
341 let data = [10, 20, 30, 40, 50];
342 let mut cursor = Cursor::new(&data);
343 let mut buf = [0u8; 3];
344 let n = cursor.read_impl(&mut buf).unwrap();
345 assert_eq!(n, 3);
346 assert_eq!(buf, [10, 20, 30]);
347 assert_eq!(cursor.position(), 3);
348 }
349
350 #[test]
351 fn cursor_read_past_end() {
352 let data = [1, 2];
353 let mut cursor = Cursor::new(&data);
354 let mut buf = [0u8; 5];
355 let n = cursor.read_impl(&mut buf).unwrap();
356 assert_eq!(n, 2);
357 assert_eq!(&buf[..2], &[1, 2]);
358 assert_eq!(cursor.position(), 2);
359
360 let n = cursor.read_impl(&mut buf).unwrap();
362 assert_eq!(n, 0);
363 }
364
365 #[test]
366 fn cursor_read_empty_buffer() {
367 let data = [1, 2, 3];
368 let mut cursor = Cursor::new(&data);
369 let mut buf = [0u8; 0];
370 let n = cursor.read_impl(&mut buf).unwrap();
371 assert_eq!(n, 0);
372 assert_eq!(cursor.position(), 0);
373 }
374
375 #[test]
376 fn cursor_seek_start() {
377 let data = [0u8; 20];
378 let mut cursor = Cursor::new(&data);
379 let pos = cursor.seek_impl(SeekFrom::Start(10)).unwrap();
380 assert_eq!(pos, 10);
381 assert_eq!(cursor.position(), 10);
382 }
383
384 #[test]
385 fn cursor_seek_end() {
386 let data = [0u8; 20];
387 let mut cursor = Cursor::new(&data);
388 let pos = cursor.seek_impl(SeekFrom::End(-5)).unwrap();
389 assert_eq!(pos, 15);
390 assert_eq!(cursor.position(), 15);
391 }
392
393 #[test]
394 fn cursor_seek_current() {
395 let data = [0u8; 20];
396 let mut cursor = Cursor::new(&data);
397 cursor.set_position(10);
398 let pos = cursor.seek_impl(SeekFrom::Current(3)).unwrap();
399 assert_eq!(pos, 13);
400 let pos = cursor.seek_impl(SeekFrom::Current(-5)).unwrap();
401 assert_eq!(pos, 8);
402 }
403
404 #[test]
405 fn cursor_seek_negative_position_errors() {
406 let data = [0u8; 10];
407 let mut cursor = Cursor::new(&data);
408 let result = cursor.seek_impl(SeekFrom::End(-20));
409 assert!(result.is_err());
410 let err = result.unwrap_err();
411 assert_eq!(err.kind(), ErrorKind::InvalidInput);
412 }
413
414 #[test]
415 fn cursor_seek_to_start_of_stream() {
416 let data = [0u8; 10];
417 let mut cursor = Cursor::new(&data);
418 cursor.set_position(5);
419 let pos = cursor.seek_impl(SeekFrom::Start(0)).unwrap();
420 assert_eq!(pos, 0);
421 }
422
423 #[test]
424 fn cursor_clone() {
425 let data = [1, 2, 3, 4, 5];
426 let mut cursor = Cursor::new(&data);
427 cursor.set_position(3);
428 let clone = cursor.clone();
429 assert_eq!(clone.position(), 3);
430 assert_eq!(clone.get_ref(), cursor.get_ref());
431 }
432
433 #[test]
434 fn cursor_debug_format() {
435 let data = [1, 2, 3];
436 let cursor = Cursor::new(&data);
437 let debug = format!("{cursor:?}");
438 assert!(debug.contains("Cursor"));
439 }
440
441 #[test]
446 fn sync_read_trait() {
447 use sync::Read;
448 let data = [10, 20, 30, 40, 50];
449 let mut cursor = Cursor::new(&data);
450 let mut buf = [0u8; 3];
451 let n = cursor.read(&mut buf).unwrap();
452 assert_eq!(n, 3);
453 assert_eq!(buf, [10, 20, 30]);
454 }
455
456 #[test]
457 fn sync_read_exact_success() {
458 use sync::Read;
459 let data = [1, 2, 3, 4, 5];
460 let mut cursor = Cursor::new(&data);
461 let mut buf = [0u8; 5];
462 cursor.read_exact(&mut buf).unwrap();
463 assert_eq!(buf, [1, 2, 3, 4, 5]);
464 }
465
466 #[test]
467 fn sync_read_exact_eof() {
468 use sync::Read;
469 let data = [1, 2];
470 let mut cursor = Cursor::new(&data);
471 let mut buf = [0u8; 5];
472 let result = cursor.read_exact(&mut buf);
473 assert!(result.is_err());
474 }
475
476 #[test]
477 fn sync_seek_trait() {
478 use sync::Seek;
479 let data = [0u8; 20];
480 let mut cursor = Cursor::new(&data);
481 let pos = cursor.seek(SeekFrom::Start(10)).unwrap();
482 assert_eq!(pos, 10);
483 let pos = cursor.stream_position().unwrap();
484 assert_eq!(pos, 10);
485 }
486
487 #[test]
488 fn sync_seek_relative() {
489 use sync::Seek;
490 let data = [0u8; 20];
491 let mut cursor = Cursor::new(&data);
492 cursor.seek(SeekFrom::Start(5)).unwrap();
493 cursor.seek_relative(3).unwrap();
494 assert_eq!(cursor.stream_position().unwrap(), 8);
495 cursor.seek_relative(-2).unwrap();
496 assert_eq!(cursor.stream_position().unwrap(), 6);
497 }
498
499 #[test]
504 fn read_ext_read_struct() {
505 use sync::ReadExt;
506 let data = [0x78, 0x56, 0x34, 0x12]; let mut cursor = Cursor::new(&data);
508 let val: u32 = cursor.read_struct().unwrap();
509 assert_eq!(val, u32::from_ne_bytes([0x78, 0x56, 0x34, 0x12]));
510 }
511
512 #[test]
513 fn read_ext_read_struct_eof() {
514 use sync::ReadExt;
515 let data = [0x78, 0x56]; let mut cursor = Cursor::new(&data);
517 let result: Result<u32> = cursor.read_struct();
518 assert!(result.is_err());
519 }
520
521 #[test]
526 fn try_io_result_option_ok() {
527 fn test_fn() -> Option<Result<u32>> {
528 let val: Result<u32> = Ok(42);
529 let v = try_io_result_option!(val);
530 Some(Ok(v))
531 }
532 let result = test_fn();
533 assert!(matches!(result, Some(Ok(42))));
534 }
535
536 #[test]
537 fn try_io_result_option_err() {
538 fn test_fn() -> Option<Result<u32>> {
539 let val: Result<u32> = Err(Error::new(ErrorKind::NotFound, "not found"));
540 let _v = try_io_result_option!(val);
541 Some(Ok(0)) }
543 let result = test_fn();
544 assert!(matches!(result, Some(Err(_))));
545 }
546}