1use crate::block::{BlockDevice, BlockRead};
15use crate::error::Result;
16
17pub struct ReadOnlyDevice<T> {
19 inner: T,
20}
21
22impl<T> ReadOnlyDevice<T> {
23 pub fn new(inner: T) -> Self {
24 Self { inner }
25 }
26
27 pub fn inner(&self) -> &T {
29 &self.inner
30 }
31
32 pub fn into_inner(self) -> T {
34 self.inner
35 }
36}
37
38impl<T: BlockRead> BlockRead for ReadOnlyDevice<T> {
39 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
40 self.inner.read_at(offset, buf)
41 }
42
43 fn size_bytes(&self) -> u64 {
44 self.inner.size_bytes()
45 }
46}
47
48impl<T: BlockRead> BlockDevice for ReadOnlyDevice<T> {}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use crate::error::Error;
57 use std::sync::Mutex;
58
59 struct WritableBytes(Mutex<Vec<u8>>);
61 impl BlockRead for WritableBytes {
62 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
63 let b = self.0.lock().unwrap();
64 let s = offset as usize;
65 buf.copy_from_slice(&b[s..s + buf.len()]);
66 Ok(())
67 }
68 fn size_bytes(&self) -> u64 {
69 self.0.lock().unwrap().len() as u64
70 }
71 }
72 impl BlockDevice for WritableBytes {
73 fn write_at(&self, offset: u64, buf: &[u8]) -> Result<()> {
74 let mut b = self.0.lock().unwrap();
75 let s = offset as usize;
76 b[s..s + buf.len()].copy_from_slice(buf);
77 Ok(())
78 }
79 fn is_writable(&self) -> bool {
80 true
81 }
82 }
83
84 #[test]
85 fn read_through_works() {
86 let mut v = vec![0u8; 16];
87 v[4..8].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]);
88 let wrapped = ReadOnlyDevice::new(WritableBytes(Mutex::new(v)));
89
90 let mut buf = [0u8; 4];
91 wrapped.read_at(4, &mut buf).unwrap();
92 assert_eq!(buf, [0xAA, 0xBB, 0xCC, 0xDD]);
93 }
94
95 #[test]
96 fn writes_rejected_even_though_inner_is_writable() {
97 let wrapped = ReadOnlyDevice::new(WritableBytes(Mutex::new(vec![0u8; 16])));
98 assert!(!BlockDevice::is_writable(&wrapped));
99
100 match BlockDevice::write_at(&wrapped, 0, &[0xFFu8; 4]) {
101 Err(Error::ReadOnly) => {}
102 other => panic!("expected ReadOnly, got {other:?}"),
103 }
104 }
105
106 #[test]
107 fn into_inner_returns_unchanged() {
108 let inner = WritableBytes(Mutex::new(vec![0u8; 8]));
109 let wrapped = ReadOnlyDevice::new(inner);
110 let back = wrapped.into_inner();
111 assert!(BlockDevice::is_writable(&back));
113 back.write_at(0, &[0x42; 4]).unwrap();
115 let mut buf = [0u8; 4];
116 back.read_at(0, &mut buf).unwrap();
117 assert_eq!(buf, [0x42; 4]);
118 }
119
120 #[test]
121 fn inner_borrows_without_consuming() {
122 let mut v = vec![0u8; 8];
123 v[0..2].copy_from_slice(&[0x9A, 0xBC]);
124 let wrapped = ReadOnlyDevice::new(WritableBytes(Mutex::new(v)));
125
126 assert!(BlockDevice::is_writable(wrapped.inner()));
129 assert_eq!(wrapped.inner().size_bytes(), 8);
130
131 let mut buf = [0u8; 2];
133 wrapped.read_at(0, &mut buf).unwrap();
134 assert_eq!(buf, [0x9A, 0xBC]);
135 }
136}