1#![no_std]
64#![allow(async_fn_in_trait)]
65
66#[cfg(feature = "std")]
67extern crate std;
68
69#[cfg(not(feature = "std"))]
75mod error;
76#[cfg(not(feature = "std"))]
77pub use error::{Error, ErrorKind, Result};
78
79#[cfg(feature = "std")]
81pub use std::io::{Error, ErrorKind, Result};
82
83#[cfg(feature = "std")]
85pub use std::path::{Path, PathBuf};
86
87#[cfg(feature = "std")]
89pub use std::io::SeekFrom;
90
91#[cfg(not(feature = "std"))]
92mod traits;
93#[cfg(not(feature = "std"))]
94pub use traits::SeekFrom;
95
96#[macro_export]
121macro_rules! try_io_result_option {
122 ($expr:expr) => {
123 match $expr {
124 Ok(val) => val,
125 Err(err) => return Some(Err(err)),
126 }
127 };
128}
129
130#[derive(Debug, Clone)]
156pub struct Cursor<'a> {
157 data: &'a [u8],
158 cursor: usize,
159}
160
161impl<'a> Cursor<'a> {
162 pub fn new(data: &'a [u8]) -> Self {
173 Self { data, cursor: 0 }
174 }
175
176 pub fn position(&self) -> usize {
187 self.cursor
188 }
189
190 pub fn set_position(&mut self, pos: usize) {
200 self.cursor = pos;
201 }
202
203 pub fn get_ref(&self) -> &'a [u8] {
213 self.data
214 }
215
216 #[allow(dead_code)]
217 fn read_impl(&mut self, buf: &mut [u8]) -> Result<usize> {
218 let remaining = self.data.len().saturating_sub(self.cursor);
219 let to_read = buf.len().min(remaining);
220 if to_read > 0 {
221 buf[..to_read].copy_from_slice(&self.data[self.cursor..self.cursor + to_read]);
222 self.cursor += to_read;
223 }
224 Ok(to_read)
225 }
226
227 #[allow(dead_code)]
228 fn seek_impl(&mut self, pos: SeekFrom) -> Result<u64> {
229 let new_pos = match pos {
230 SeekFrom::Start(offset) => offset as i64,
231 SeekFrom::End(offset) => self.data.len() as i64 + offset,
232 SeekFrom::Current(offset) => self.cursor as i64 + offset,
233 };
234
235 if new_pos < 0 {
236 #[cfg(feature = "std")]
237 return Err(Error::new(
238 ErrorKind::InvalidInput,
239 "invalid seek to negative position",
240 ));
241 #[cfg(not(feature = "std"))]
242 return Err(Error::new(
243 ErrorKind::InvalidInput,
244 "invalid seek to negative position",
245 ));
246 }
247
248 self.cursor = new_pos as usize;
249 Ok(self.cursor as u64)
250 }
251}
252
253#[cfg(feature = "sync")]
258mod sync_api;
259
260#[cfg(feature = "sync")]
266pub mod sync {
267 pub use super::sync_api::*;
268}
269
270#[cfg(feature = "sync")]
272impl sync::Read for Cursor<'_> {
273 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
274 self.read_impl(buf)
275 }
276}
277
278#[cfg(all(feature = "sync", not(feature = "std")))]
279impl sync::Seek for Cursor<'_> {
280 fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
281 self.seek_impl(pos)
282 }
283}
284
285#[cfg(all(feature = "sync", feature = "std"))]
286impl std::io::Seek for Cursor<'_> {
287 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
288 let our_pos = match pos {
290 std::io::SeekFrom::Start(n) => SeekFrom::Start(n),
291 std::io::SeekFrom::End(n) => SeekFrom::End(n),
292 std::io::SeekFrom::Current(n) => SeekFrom::Current(n),
293 };
294 self.seek_impl(our_pos)
295 }
296}
297
298#[cfg(feature = "sync")]
300pub use sync::*;
301
302#[cfg(feature = "async")]
307mod async_api;
308
309#[cfg(feature = "async")]
315pub mod r#async {
316 pub use super::async_api::*;
317}
318
319#[cfg(feature = "async")]
321impl r#async::Read for Cursor<'_> {
322 async fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
323 self.read_impl(buf)
324 }
325}
326
327#[cfg(feature = "async")]
328impl r#async::Seek for Cursor<'_> {
329 async fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
330 self.seek_impl(pos)
331 }
332}
333
334#[cfg(all(test, feature = "sync"))]
335mod tests {
336 extern crate std;
337 use super::*;
338 use std::format;
339
340 #[test]
345 fn cursor_new_starts_at_zero() {
346 let data = [1, 2, 3, 4, 5];
347 let cursor = Cursor::new(&data);
348 assert_eq!(cursor.position(), 0);
349 assert_eq!(cursor.get_ref(), &data);
350 }
351
352 #[test]
353 fn cursor_set_position() {
354 let data = [0u8; 10];
355 let mut cursor = Cursor::new(&data);
356 cursor.set_position(5);
357 assert_eq!(cursor.position(), 5);
358 cursor.set_position(0);
359 assert_eq!(cursor.position(), 0);
360 }
361
362 #[test]
363 fn cursor_read_basic() {
364 let data = [10, 20, 30, 40, 50];
365 let mut cursor = Cursor::new(&data);
366 let mut buf = [0u8; 3];
367 let n = cursor.read_impl(&mut buf).unwrap();
368 assert_eq!(n, 3);
369 assert_eq!(buf, [10, 20, 30]);
370 assert_eq!(cursor.position(), 3);
371 }
372
373 #[test]
374 fn cursor_read_past_end() {
375 let data = [1, 2];
376 let mut cursor = Cursor::new(&data);
377 let mut buf = [0u8; 5];
378 let n = cursor.read_impl(&mut buf).unwrap();
379 assert_eq!(n, 2);
380 assert_eq!(&buf[..2], &[1, 2]);
381 assert_eq!(cursor.position(), 2);
382
383 let n = cursor.read_impl(&mut buf).unwrap();
385 assert_eq!(n, 0);
386 }
387
388 #[test]
389 fn cursor_read_empty_buffer() {
390 let data = [1, 2, 3];
391 let mut cursor = Cursor::new(&data);
392 let mut buf = [0u8; 0];
393 let n = cursor.read_impl(&mut buf).unwrap();
394 assert_eq!(n, 0);
395 assert_eq!(cursor.position(), 0);
396 }
397
398 #[test]
399 fn cursor_seek_start() {
400 let data = [0u8; 20];
401 let mut cursor = Cursor::new(&data);
402 let pos = cursor.seek_impl(SeekFrom::Start(10)).unwrap();
403 assert_eq!(pos, 10);
404 assert_eq!(cursor.position(), 10);
405 }
406
407 #[test]
408 fn cursor_seek_end() {
409 let data = [0u8; 20];
410 let mut cursor = Cursor::new(&data);
411 let pos = cursor.seek_impl(SeekFrom::End(-5)).unwrap();
412 assert_eq!(pos, 15);
413 assert_eq!(cursor.position(), 15);
414 }
415
416 #[test]
417 fn cursor_seek_current() {
418 let data = [0u8; 20];
419 let mut cursor = Cursor::new(&data);
420 cursor.set_position(10);
421 let pos = cursor.seek_impl(SeekFrom::Current(3)).unwrap();
422 assert_eq!(pos, 13);
423 let pos = cursor.seek_impl(SeekFrom::Current(-5)).unwrap();
424 assert_eq!(pos, 8);
425 }
426
427 #[test]
428 fn cursor_seek_negative_position_errors() {
429 let data = [0u8; 10];
430 let mut cursor = Cursor::new(&data);
431 let result = cursor.seek_impl(SeekFrom::End(-20));
432 assert!(result.is_err());
433 let err = result.unwrap_err();
434 assert_eq!(err.kind(), ErrorKind::InvalidInput);
435 }
436
437 #[test]
438 fn cursor_seek_to_start_of_stream() {
439 let data = [0u8; 10];
440 let mut cursor = Cursor::new(&data);
441 cursor.set_position(5);
442 let pos = cursor.seek_impl(SeekFrom::Start(0)).unwrap();
443 assert_eq!(pos, 0);
444 }
445
446 #[test]
447 fn cursor_clone() {
448 let data = [1, 2, 3, 4, 5];
449 let mut cursor = Cursor::new(&data);
450 cursor.set_position(3);
451 let clone = cursor.clone();
452 assert_eq!(clone.position(), 3);
453 assert_eq!(clone.get_ref(), cursor.get_ref());
454 }
455
456 #[test]
457 fn cursor_debug_format() {
458 let data = [1, 2, 3];
459 let cursor = Cursor::new(&data);
460 let debug = format!("{:?}", cursor);
461 assert!(debug.contains("Cursor"));
462 }
463
464 #[test]
469 fn sync_read_trait() {
470 use sync::Read;
471 let data = [10, 20, 30, 40, 50];
472 let mut cursor = Cursor::new(&data);
473 let mut buf = [0u8; 3];
474 let n = cursor.read(&mut buf).unwrap();
475 assert_eq!(n, 3);
476 assert_eq!(buf, [10, 20, 30]);
477 }
478
479 #[test]
480 fn sync_read_exact_success() {
481 use sync::Read;
482 let data = [1, 2, 3, 4, 5];
483 let mut cursor = Cursor::new(&data);
484 let mut buf = [0u8; 5];
485 cursor.read_exact(&mut buf).unwrap();
486 assert_eq!(buf, [1, 2, 3, 4, 5]);
487 }
488
489 #[test]
490 fn sync_read_exact_eof() {
491 use sync::Read;
492 let data = [1, 2];
493 let mut cursor = Cursor::new(&data);
494 let mut buf = [0u8; 5];
495 let result = cursor.read_exact(&mut buf);
496 assert!(result.is_err());
497 }
498
499 #[test]
500 fn sync_seek_trait() {
501 use sync::Seek;
502 let data = [0u8; 20];
503 let mut cursor = Cursor::new(&data);
504 let pos = cursor.seek(SeekFrom::Start(10)).unwrap();
505 assert_eq!(pos, 10);
506 let pos = cursor.stream_position().unwrap();
507 assert_eq!(pos, 10);
508 }
509
510 #[test]
511 fn sync_seek_relative() {
512 use sync::Seek;
513 let data = [0u8; 20];
514 let mut cursor = Cursor::new(&data);
515 cursor.seek(SeekFrom::Start(5)).unwrap();
516 cursor.seek_relative(3).unwrap();
517 assert_eq!(cursor.stream_position().unwrap(), 8);
518 cursor.seek_relative(-2).unwrap();
519 assert_eq!(cursor.stream_position().unwrap(), 6);
520 }
521
522 #[test]
527 fn read_ext_read_struct() {
528 use sync::ReadExt;
529 let data = [0x78, 0x56, 0x34, 0x12]; let mut cursor = Cursor::new(&data);
531 let val: u32 = cursor.read_struct().unwrap();
532 assert_eq!(val, u32::from_ne_bytes([0x78, 0x56, 0x34, 0x12]));
533 }
534
535 #[test]
536 fn read_ext_read_struct_eof() {
537 use sync::ReadExt;
538 let data = [0x78, 0x56]; let mut cursor = Cursor::new(&data);
540 let result: Result<u32> = cursor.read_struct();
541 assert!(result.is_err());
542 }
543
544 #[test]
549 fn try_io_result_option_ok() {
550 fn test_fn() -> Option<Result<u32>> {
551 let val: Result<u32> = Ok(42);
552 let v = try_io_result_option!(val);
553 Some(Ok(v))
554 }
555 let result = test_fn();
556 assert!(matches!(result, Some(Ok(42))));
557 }
558
559 #[test]
560 fn try_io_result_option_err() {
561 fn test_fn() -> Option<Result<u32>> {
562 let val: Result<u32> = Err(Error::new(ErrorKind::NotFound, "not found"));
563 let _v = try_io_result_option!(val);
564 Some(Ok(0)) }
566 let result = test_fn();
567 assert!(matches!(result, Some(Err(_))));
568 }
569}