1use std::fmt;
4
5pub trait Source {
11 fn len(&self) -> u64;
13
14 fn is_empty(&self) -> bool {
16 self.len() == 0
17 }
18
19 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SourceError>;
23}
24
25impl Source for [u8] {
26 fn len(&self) -> u64 {
27 self.len() as u64
29 }
30
31 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SourceError> {
32 let Ok(start) = usize::try_from(offset) else {
33 return Ok(0);
34 };
35 let Some(available) = self.get(start..) else {
36 return Ok(0);
37 };
38 let n = available.len().min(buf.len());
39 if let (Some(dst), Some(src)) = (buf.get_mut(..n), available.get(..n)) {
40 dst.copy_from_slice(src);
41 }
42 Ok(n)
43 }
44}
45
46impl Source for Vec<u8> {
47 fn len(&self) -> u64 {
48 self.as_slice().len() as u64
49 }
50
51 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SourceError> {
52 self.as_slice().read_at(offset, buf)
53 }
54}
55
56impl<S: Source + ?Sized> Source for &S {
57 fn len(&self) -> u64 {
58 (**self).len()
59 }
60
61 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize, SourceError> {
62 (**self).read_at(offset, buf)
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct SourceError {
69 message: String,
70}
71
72impl SourceError {
73 pub fn new(message: impl Into<String>) -> Self {
75 Self {
76 message: message.into(),
77 }
78 }
79
80 pub fn message(&self) -> &str {
82 &self.message
83 }
84}
85
86impl fmt::Display for SourceError {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(f, "source read failed: {}", self.message)
89 }
90}
91
92impl std::error::Error for SourceError {}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn reads_a_range() {
100 let bytes: &[u8] = b"hello world";
101 let mut buf = [0u8; 5];
102 assert_eq!(bytes.read_at(6, &mut buf), Ok(5));
103 assert_eq!(&buf, b"world");
104 }
105
106 #[test]
107 fn short_read_at_end() {
108 let bytes: &[u8] = b"abc";
109 let mut buf = [0u8; 8];
110 assert_eq!(bytes.read_at(1, &mut buf), Ok(2));
111 assert_eq!(&buf[..2], b"bc");
112 }
113
114 #[test]
115 fn offset_past_end_reads_nothing() {
116 let bytes: &[u8] = b"abc";
117 let mut buf = [0u8; 4];
118 assert_eq!(bytes.read_at(3, &mut buf), Ok(0));
119 assert_eq!(bytes.read_at(u64::MAX, &mut buf), Ok(0));
120 }
121
122 #[test]
123 fn empty_buffer_reads_nothing() {
124 let bytes: &[u8] = b"abc";
125 assert_eq!(bytes.read_at(0, &mut []), Ok(0));
126 }
127
128 #[test]
129 fn vec_and_reference_delegate() {
130 let bytes = b"xyz".to_vec();
131 let by_ref = &bytes;
132 let mut buf = [0u8; 3];
133 assert_eq!(Source::len(&by_ref), 3);
134 assert!(!Source::is_empty(&by_ref));
135 assert_eq!(by_ref.read_at(0, &mut buf), Ok(3));
136 assert_eq!(&buf, b"xyz");
137 assert!(Source::is_empty(&Vec::new()));
138 }
139
140 #[test]
141 fn error_displays_message() {
142 let err = SourceError::new("disk on fire");
143 assert_eq!(err.message(), "disk on fire");
144 assert_eq!(err.to_string(), "source read failed: disk on fire");
145 }
146}