1use crate::buffer::{BufferFuture, BufferRef, MutableBufferRef};
15use anyhow::{Error, bail};
16use async_trait::async_trait;
17pub use block_protocol::{InlineCryptoOptions, ReadOptions, WriteOptions};
19use futures::channel::oneshot::{Sender, channel};
20use std::future::Future;
21use std::mem::ManuallyDrop;
22use std::ops::{Deref, Range};
23use std::pin::Pin;
24use std::sync::{Arc, OnceLock};
25
26pub mod buffer;
27pub mod buffer_allocator;
28pub mod splittable_buffer;
29
30pub use splittable_buffer::SplittableBuffer;
31
32#[cfg(target_os = "fuchsia")]
33pub mod block_device;
34
35#[cfg(target_family = "unix")]
36pub mod file_backed_device;
37
38pub mod fake_device;
39
40pub mod ranged_device;
41
42#[async_trait]
43pub trait Device: Send + Sync {
45 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_>;
49
50 fn clean_transfer_buffer(&self) {}
52
53 fn block_size(&self) -> u32;
55
56 fn block_count(&self) -> u64;
58
59 fn size(&self) -> u64 {
61 self.block_size() as u64 * self.block_count()
62 }
63
64 fn read<'a>(
66 &'a self,
67 offset: u64,
68 buffer: MutableBufferRef<'a>,
69 ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
70 self.read_with_opts(offset, buffer, ReadOptions::default())
71 }
72
73 async fn read_with_opts(
75 &self,
76 offset: u64,
77 buffer: MutableBufferRef<'_>,
78 read_opts: ReadOptions,
79 ) -> Result<(), Error>;
80
81 fn write<'a>(
83 &'a self,
84 offset: u64,
85 buffer: BufferRef<'a>,
86 ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
87 self.write_with_opts(offset, buffer, WriteOptions::default())
88 }
89
90 async fn write_with_opts(
92 &self,
93 offset: u64,
94 buffer: BufferRef<'_>,
95 write_opts: WriteOptions,
96 ) -> Result<(), Error>;
97
98 async fn trim(&self, range: Range<u64>) -> Result<(), Error>;
100
101 async fn close(&self) -> Result<(), Error>;
104
105 async fn flush(&self) -> Result<(), Error>;
107
108 fn barrier(&self);
110
111 fn reopen(&self, _read_only: bool) {
113 unreachable!();
114 }
115 fn is_read_only(&self) -> bool;
117
118 fn supports_trim(&self) -> bool;
120
121 fn snapshot(&self) -> Result<DeviceHolder, Error> {
123 bail!("Not supported");
124 }
125
126 fn discard_random_since_last_flush(&self) -> Result<(), Error> {
128 bail!("Not supported");
129 }
130
131 fn poison(&self) -> Result<(), Error> {
133 bail!("Not supported");
134 }
135}
136
137pub struct DeviceHolder {
144 device: ManuallyDrop<Arc<dyn Device>>,
145 on_drop: OnceLock<Sender<DeviceHolder>>,
146}
147
148impl DeviceHolder {
149 pub fn new(device: impl Device + 'static) -> Self {
150 DeviceHolder { device: ManuallyDrop::new(Arc::new(device)), on_drop: OnceLock::new() }
151 }
152
153 pub fn ensure_unique(&self) {
156 assert_eq!(Arc::strong_count(&self.device), 1);
157 }
158
159 pub fn take_when_dropped(&self) -> impl Future<Output = DeviceHolder> + use<> {
160 let (sender, receiver) = channel::<DeviceHolder>();
161 self.on_drop
162 .set(sender)
163 .unwrap_or_else(|_| panic!("take_when_dropped should only be called once"));
164 async { receiver.await.unwrap() }
165 }
166}
167
168impl Drop for DeviceHolder {
169 fn drop(&mut self) {
170 if let Some(sender) = self.on_drop.take() {
171 let device = ManuallyDrop::new(unsafe { ManuallyDrop::take(&mut self.device) });
173 let _ = sender.send(DeviceHolder { device, on_drop: OnceLock::new() });
175 } else {
176 unsafe { ManuallyDrop::drop(&mut self.device) }
178 }
179 }
180}
181
182impl Deref for DeviceHolder {
183 type Target = Arc<dyn Device>;
184
185 fn deref(&self) -> &Self::Target {
186 &self.device
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::DeviceHolder;
193 use crate::fake_device::FakeDevice;
194
195 #[fuchsia::test]
196 async fn test_take_when_dropped() {
197 let holder = DeviceHolder::new(FakeDevice::new(1, 512));
198 let fut = holder.take_when_dropped();
199 std::mem::drop(holder);
200 fut.await.ensure_unique();
201 }
202}