use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use tokio::runtime::Handle;
use tracing::warn;
use crate::device::Device;
pub struct DeviceGuard {
device: Option<Device>,
}
impl DeviceGuard {
pub fn new(device: Device) -> Self {
Self {
device: Some(device),
}
}
pub fn into_inner(mut self) -> Device {
self.device
.take()
.expect("DeviceGuard invariant violated: device is None outside of Drop")
}
fn device(&self) -> &Device {
self.device
.as_ref()
.expect("DeviceGuard invariant violated: device is None outside of Drop")
}
fn device_mut(&mut self) -> &mut Device {
self.device
.as_mut()
.expect("DeviceGuard invariant violated: device is None outside of Drop")
}
}
impl Deref for DeviceGuard {
type Target = Device;
fn deref(&self) -> &Self::Target {
self.device()
}
}
impl DerefMut for DeviceGuard {
fn deref_mut(&mut self) -> &mut Self::Target {
self.device_mut()
}
}
impl Drop for DeviceGuard {
fn drop(&mut self) {
if let Some(device) = self.device.take() {
if let Ok(handle) = Handle::try_current() {
handle.spawn(async move {
match tokio::time::timeout(
std::time::Duration::from_secs(5),
device.disconnect(),
)
.await
{
Ok(Ok(())) => {}
Ok(Err(e)) => {
warn!("Failed to disconnect device in guard drop: {}", e);
}
Err(_) => {
warn!("Timeout disconnecting device in guard drop");
}
}
});
} else {
warn!("No tokio runtime available for device disconnect in guard drop");
}
}
}
}
pub struct SharedDeviceGuard {
device: Arc<Device>,
}
impl SharedDeviceGuard {
pub fn new(device: Arc<Device>) -> Self {
Self { device }
}
pub fn into_inner(self) -> Arc<Device> {
let guard = std::mem::ManuallyDrop::new(self);
Arc::clone(&guard.device)
}
}
impl Deref for SharedDeviceGuard {
type Target = Device;
fn deref(&self) -> &Self::Target {
&self.device
}
}
impl Drop for SharedDeviceGuard {
fn drop(&mut self) {
let device = Arc::clone(&self.device);
if let Ok(handle) = Handle::try_current() {
handle.spawn(async move {
if let Err(e) = device.disconnect().await {
warn!("Failed to disconnect shared device in guard drop: {}", e);
}
});
}
}
}