playdate_device/mount/
mod.rs1use std::borrow::Cow;
2use std::ops::Deref;
3use std::ops::DerefMut;
4use std::path::Path;
5
6use crate::device::Device;
7use crate::error::Error;
8
9#[cfg(any(all(target_os = "macos", target_os = "linux"),
10 all(target_os = "linux", target_os = "windows"),
11 all(target_os = "windows", target_os = "macos")))]
12compile_error!("cfg.target_os conflict");
13
14#[cfg_attr(target_os = "macos", path = "mac.rs")]
15#[cfg_attr(target_os = "linux", path = "linux.rs")]
16#[cfg_attr(target_os = "windows", path = "win.rs")]
17pub mod volume;
18
19mod methods;
20pub use methods::*;
21
22
23pub trait Volume {
27 fn path(&self) -> Cow<'_, Path>;
29}
30
31pub trait Unmount {
32 fn unmount_blocking(&self) -> Result<(), Error>;
34}
35
36pub trait UnmountAsync {
37 fn unmount(&self) -> impl std::future::Future<Output = Result<(), Error>>;
39}
40
41pub trait Mount {
42 fn mount_blocking(&self) -> Result<(), Error>;
44}
45
46pub trait MountAsync {
47 fn mount(&self) -> impl std::future::Future<Output = Result<(), Error>>;
48}
49
50
51impl Mount for Device {
52 fn mount_blocking(&self) -> Result<(), Error> {
53 use crate::interface::blocking::Out;
54 use crate::device::command::Command;
55
56 self.interface()?.send_cmd(Command::Datadisk)?;
57 Ok(())
58 }
59}
60
61impl MountAsync for Device {
62 async fn mount(&self) -> Result<(), Error> { self.interface()?.mount().await }
63}
64
65
66impl<T> MountAsync for T where T: crate::interface::r#async::Out {
67 async fn mount(&self) -> Result<(), Error> {
68 self.send_cmd(crate::device::command::Command::Datadisk).await?;
69 Ok(())
70 }
71}
72
73impl<T> Mount for T where T: crate::interface::blocking::Out {
74 fn mount_blocking(&self) -> Result<(), Error> {
75 self.send_cmd(crate::device::command::Command::Datadisk)?;
76 Ok(())
77 }
78}
79
80
81impl<T> UnmountAsync for T where T: crate::interface::r#async::Out {
82 async fn unmount(&self) -> Result<(), Error> {
83 self.send_cmd(crate::device::command::Command::Datadisk).await?;
84 Ok(())
85 }
86}
87
88impl<T> Unmount for T where T: crate::interface::blocking::Out {
89 fn unmount_blocking(&self) -> Result<(), Error> {
90 self.send_cmd(crate::device::command::Command::Datadisk)?;
91 Ok(())
92 }
93}
94
95
96pub struct MountedDevice {
97 pub device: Device,
98 pub handle: MountHandle,
99}
100
101impl Unmount for MountedDevice {
102 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), fields(dev = self.info().serial_number(), mount = self.handle.volume().path().as_ref().display().to_string())))]
103 fn unmount_blocking(&self) -> Result<(), Error> {
104 <volume::Volume as Unmount>::unmount_blocking(&self.handle.volume)
105 }
106}
107
108impl UnmountAsync for MountedDevice where volume::Volume: UnmountAsync {
109 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self), fields(dev = self.info().serial_number(), mount = self.handle.volume().path().as_ref().display().to_string())))]
110 fn unmount(&self) -> impl std::future::Future<Output = Result<(), Error>> {
111 <volume::Volume as UnmountAsync>::unmount(&self.handle.volume)
112 }
113}
114
115impl MountedDevice {
116 pub fn new(device: Device, handle: MountHandle) -> Self { Self { device, handle } }
117}
118
119impl Deref for MountedDevice {
120 type Target = Device;
121 fn deref(&self) -> &Self::Target { &self.device }
122}
123
124impl DerefMut for MountedDevice {
125 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.device }
126}
127
128
129pub struct MountHandle {
130 volume: volume::Volume,
131 pub unmount_on_drop: bool,
132}
133
134impl MountHandle {
135 pub fn new(volume: volume::Volume, unmount_on_drop: bool) -> Self {
136 Self { volume,
137 unmount_on_drop }
138 }
139
140 pub fn path(&self) -> Cow<'_, Path> { self.volume.path() }
141 pub fn volume(&self) -> &volume::Volume { &self.volume }
142
143 pub fn unmount(mut self) {
144 self.unmount_on_drop = true;
145 drop(self)
146 }
147}
148
149impl Drop for MountHandle {
150 fn drop(&mut self) {
151 if self.unmount_on_drop {
152 trace!("Unmounting {} by drop", self.volume);
153 let _ = self.volume
154 .unmount_blocking()
155 .map_err(|err| {
156 error!("{err}");
157 info!("Please press 'A' on the Playdate to exit Data Disk mode.");
158 })
159 .ok();
160 }
161 }
162}