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