1#![no_std]
69#![deny(missing_docs)]
70#![allow(async_fn_in_trait)]
71
72#[cfg(feature = "std")]
73extern crate std;
74
75mod error;
80pub use error::{Error, ErrorKind, Result};
81
82#[cfg(feature = "std")]
84pub use std::path::{Path, PathBuf};
85
86pub use embedded_io::SeekFrom;
88
89pub trait IoError: embedded_io::Error {}
91impl<T: embedded_io::Error + ?Sized> IoError for T {}
92
93#[macro_export]
118macro_rules! try_io_result_option {
119 ($expr:expr) => {
120 match $expr {
121 Ok(val) => val,
122 Err(err) => return Some(Err(err.erase())),
123 }
124 };
125}
126
127#[derive(Debug, Clone)]
153pub struct Cursor<'a> {
154 data: &'a [u8],
155 cursor: usize,
156}
157
158impl<'a> Cursor<'a> {
159 pub fn new(data: &'a [u8]) -> Self {
170 Self { data, cursor: 0 }
171 }
172
173 pub fn position(&self) -> usize {
184 self.cursor
185 }
186
187 pub fn set_position(&mut self, pos: usize) {
197 self.cursor = pos;
198 }
199
200 pub fn get_ref(&self) -> &'a [u8] {
210 self.data
211 }
212
213 #[cfg(any(feature = "sync", feature = "async", test))]
214 fn read_impl(&mut self, buf: &mut [u8]) -> core::result::Result<usize, ErrorKind> {
215 let remaining = self.data.len().saturating_sub(self.cursor);
216 let to_read = buf.len().min(remaining);
217 if to_read > 0 {
218 buf[..to_read].copy_from_slice(&self.data[self.cursor..self.cursor + to_read]);
219 self.cursor += to_read;
220 }
221 Ok(to_read)
222 }
223
224 #[cfg(any(feature = "sync", feature = "async", test))]
225 fn seek_impl(&mut self, pos: SeekFrom) -> core::result::Result<u64, ErrorKind> {
226 let new_pos = match pos {
227 SeekFrom::Start(offset) => Some(offset),
228 SeekFrom::End(offset) => (self.data.len() as u64).checked_add_signed(offset),
229 SeekFrom::Current(offset) => (self.cursor as u64).checked_add_signed(offset),
230 }
231 .ok_or(ErrorKind::InvalidInput)?;
232
233 self.cursor = usize::try_from(new_pos).map_err(|_| ErrorKind::InvalidInput)?;
234 Ok(self.cursor as u64)
235 }
236}
237
238#[cfg(feature = "sync")]
243mod sync_api;
244
245#[cfg(feature = "sync")]
251pub mod sync {
252 pub use super::sync_api::*;
253}
254
255#[cfg(feature = "sync")]
257impl sync::Read for Cursor<'_> {
258 type Error = ErrorKind;
259
260 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
261 self.read_impl(buf).map_err(Error::from_source)
262 }
263}
264
265#[cfg(feature = "sync")]
266impl sync::Seek for Cursor<'_> {
267 type Error = ErrorKind;
268
269 fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
270 self.seek_impl(pos).map_err(Error::from_source)
271 }
272}
273
274#[cfg(feature = "sync")]
276pub use sync::*;
277
278#[cfg(feature = "async")]
283mod async_api;
284
285#[cfg(feature = "async")]
290pub mod r#async {
291 pub use super::async_api::*;
292}
293
294#[cfg(feature = "async")]
296impl r#async::Read for Cursor<'_> {
297 type Error = ErrorKind;
298
299 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
300 self.read_impl(buf).map_err(Error::from_source)
301 }
302}
303
304#[cfg(feature = "async")]
305impl r#async::Seek for Cursor<'_> {
306 type Error = ErrorKind;
307
308 async fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
309 self.seek_impl(pos).map_err(Error::from_source)
310 }
311}
312
313#[cfg(all(test, feature = "sync"))]
314mod tests {
315 extern crate std;
316 use super::*;
317 use std::format;
318
319 #[test]
324 fn cursor_new_starts_at_zero() {
325 let data = [1, 2, 3, 4, 5];
326 let cursor = Cursor::new(&data);
327 assert_eq!(cursor.position(), 0);
328 assert_eq!(cursor.get_ref(), &data);
329 }
330
331 #[test]
332 fn cursor_set_position() {
333 let data = [0u8; 10];
334 let mut cursor = Cursor::new(&data);
335 cursor.set_position(5);
336 assert_eq!(cursor.position(), 5);
337 cursor.set_position(0);
338 assert_eq!(cursor.position(), 0);
339 }
340
341 #[test]
342 fn cursor_read_basic() {
343 let data = [10, 20, 30, 40, 50];
344 let mut cursor = Cursor::new(&data);
345 let mut buf = [0u8; 3];
346 let n = cursor.read_impl(&mut buf).unwrap();
347 assert_eq!(n, 3);
348 assert_eq!(buf, [10, 20, 30]);
349 assert_eq!(cursor.position(), 3);
350 }
351
352 #[test]
353 fn cursor_read_past_end() {
354 let data = [1, 2];
355 let mut cursor = Cursor::new(&data);
356 let mut buf = [0u8; 5];
357 let n = cursor.read_impl(&mut buf).unwrap();
358 assert_eq!(n, 2);
359 assert_eq!(&buf[..2], &[1, 2]);
360 assert_eq!(cursor.position(), 2);
361
362 let n = cursor.read_impl(&mut buf).unwrap();
364 assert_eq!(n, 0);
365 }
366
367 #[test]
368 fn cursor_read_empty_buffer() {
369 let data = [1, 2, 3];
370 let mut cursor = Cursor::new(&data);
371 let mut buf = [0u8; 0];
372 let n = cursor.read_impl(&mut buf).unwrap();
373 assert_eq!(n, 0);
374 assert_eq!(cursor.position(), 0);
375 }
376
377 #[test]
378 fn cursor_seek_start() {
379 let data = [0u8; 20];
380 let mut cursor = Cursor::new(&data);
381 let pos = cursor.seek_impl(SeekFrom::Start(10)).unwrap();
382 assert_eq!(pos, 10);
383 assert_eq!(cursor.position(), 10);
384 }
385
386 #[test]
387 fn cursor_seek_end() {
388 let data = [0u8; 20];
389 let mut cursor = Cursor::new(&data);
390 let pos = cursor.seek_impl(SeekFrom::End(-5)).unwrap();
391 assert_eq!(pos, 15);
392 assert_eq!(cursor.position(), 15);
393 }
394
395 #[test]
396 fn cursor_seek_current() {
397 let data = [0u8; 20];
398 let mut cursor = Cursor::new(&data);
399 cursor.set_position(10);
400 let pos = cursor.seek_impl(SeekFrom::Current(3)).unwrap();
401 assert_eq!(pos, 13);
402 let pos = cursor.seek_impl(SeekFrom::Current(-5)).unwrap();
403 assert_eq!(pos, 8);
404 }
405
406 #[test]
407 fn cursor_seek_negative_position_errors() {
408 let data = [0u8; 10];
409 let mut cursor = Cursor::new(&data);
410 let result = cursor.seek_impl(SeekFrom::End(-20));
411 assert!(result.is_err());
412 let err = result.unwrap_err();
413 assert_eq!(err.kind(), ErrorKind::InvalidInput);
414 }
415
416 #[test]
417 fn cursor_seek_end_large_offset_does_not_panic() {
418 let data = [0u8; 5];
419 let mut cursor = Cursor::new(&data);
420 let result = cursor.seek_impl(SeekFrom::End(i64::MAX));
421 match result {
422 Ok(pos) => assert_eq!(pos, 5 + i64::MAX as u64),
423 Err(err) => assert_eq!(err.kind(), ErrorKind::InvalidInput),
424 }
425 }
426
427 #[test]
428 fn cursor_seek_current_overflow_errors() {
429 let data = [0u8; 5];
430 let mut cursor = Cursor::new(&data);
431 cursor.set_position(usize::MAX);
432 let result = cursor.seek_impl(SeekFrom::Current(i64::MAX));
433 assert!(result.is_err());
434 assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidInput);
435 }
436
437 #[test]
438 fn cursor_seek_start_u64_max_accepted() {
439 let data = [1u8, 2, 3];
440 let mut cursor = Cursor::new(&data);
441 match cursor.seek_impl(SeekFrom::Start(u64::MAX)) {
442 Ok(pos) => {
443 assert!(usize::try_from(u64::MAX).is_ok());
444 assert_eq!(pos, u64::MAX);
445 let mut buf = [0u8; 4];
446 let n = cursor.read_impl(&mut buf).unwrap();
447 assert_eq!(n, 0);
448 }
449 Err(err) => {
450 assert!(usize::try_from(u64::MAX).is_err());
451 assert_eq!(err.kind(), ErrorKind::InvalidInput);
452 }
453 }
454 }
455
456 #[test]
457 fn cursor_seek_to_start_of_stream() {
458 let data = [0u8; 10];
459 let mut cursor = Cursor::new(&data);
460 cursor.set_position(5);
461 let pos = cursor.seek_impl(SeekFrom::Start(0)).unwrap();
462 assert_eq!(pos, 0);
463 }
464
465 #[test]
466 fn cursor_clone() {
467 let data = [1, 2, 3, 4, 5];
468 let mut cursor = Cursor::new(&data);
469 cursor.set_position(3);
470 let clone = cursor.clone();
471 assert_eq!(clone.position(), 3);
472 assert_eq!(clone.get_ref(), cursor.get_ref());
473 }
474
475 #[test]
476 fn cursor_debug_format() {
477 let data = [1, 2, 3];
478 let cursor = Cursor::new(&data);
479 let debug = format!("{cursor:?}");
480 assert!(debug.contains("Cursor"));
481 }
482
483 #[test]
488 fn sync_read_trait() {
489 use sync::Read;
490 let data = [10, 20, 30, 40, 50];
491 let mut cursor = Cursor::new(&data);
492 let mut buf = [0u8; 3];
493 let n = cursor.read(&mut buf).unwrap();
494 assert_eq!(n, 3);
495 assert_eq!(buf, [10, 20, 30]);
496 }
497
498 #[test]
499 fn sync_read_exact_success() {
500 use sync::Read;
501 let data = [1, 2, 3, 4, 5];
502 let mut cursor = Cursor::new(&data);
503 let mut buf = [0u8; 5];
504 cursor.read_exact(&mut buf).unwrap();
505 assert_eq!(buf, [1, 2, 3, 4, 5]);
506 }
507
508 #[test]
509 fn sync_read_exact_eof() {
510 use sync::Read;
511 let data = [1, 2];
512 let mut cursor = Cursor::new(&data);
513 let mut buf = [0u8; 5];
514 let result = cursor.read_exact(&mut buf);
515 assert!(result.is_err());
516 }
517
518 #[test]
519 fn sync_seek_trait() {
520 use sync::Seek;
521 let data = [0u8; 20];
522 let mut cursor = Cursor::new(&data);
523 let pos = cursor.seek(SeekFrom::Start(10)).unwrap();
524 assert_eq!(pos, 10);
525 let pos = cursor.stream_position().unwrap();
526 assert_eq!(pos, 10);
527 }
528
529 #[test]
530 fn sync_seek_relative() {
531 use sync::Seek;
532 let data = [0u8; 20];
533 let mut cursor = Cursor::new(&data);
534 cursor.seek(SeekFrom::Start(5)).unwrap();
535 cursor.seek_relative(3).unwrap();
536 assert_eq!(cursor.stream_position().unwrap(), 8);
537 cursor.seek_relative(-2).unwrap();
538 assert_eq!(cursor.stream_position().unwrap(), 6);
539 }
540
541 #[test]
546 fn read_ext_read_struct() {
547 use sync::ReadExt;
548 let data = [0x78, 0x56, 0x34, 0x12]; let mut cursor = Cursor::new(&data);
550 let val: u32 = cursor.read_struct().unwrap();
551 assert_eq!(val, u32::from_ne_bytes([0x78, 0x56, 0x34, 0x12]));
552 }
553
554 #[test]
555 fn read_ext_read_struct_eof() {
556 use sync::ReadExt;
557 let data = [0x78, 0x56]; let mut cursor = Cursor::new(&data);
559 let result: Result<u32> = cursor.read_struct();
560 assert!(result.is_err());
561 }
562
563 #[test]
568 fn try_io_result_option_ok() {
569 fn test_fn() -> Option<Result<u32>> {
570 let val: Result<u32> = Ok(42);
571 let v = try_io_result_option!(val);
572 Some(Ok(v))
573 }
574 let result = test_fn();
575 assert!(matches!(result, Some(Ok(42))));
576 }
577
578 #[test]
579 fn try_io_result_option_err() {
580 fn test_fn() -> Option<Result<u32>> {
581 let val: Result<u32> = Err(Error::new(ErrorKind::NotFound, "not found"));
582 let _v = try_io_result_option!(val);
583 Some(Ok(0)) }
585 let result = test_fn();
586 assert!(matches!(result, Some(Err(_))));
587 }
588}