From 3c49859a76e2837a9c91d18d34a1902eb7d765af Mon Sep 17 00:00:00 2001 From: Be Date: Wed, 12 Feb 2025 17:01:18 -0600 Subject: [PATCH] impl Drop for async File & Volume with embassy_futures::block_on --- Cargo.toml | 4 +++- src/inner/filesystem/files.rs | 23 +++++++++++++++++++---- src/inner/mod.rs | 23 +++++++++++++++++++---- src/lib.rs | 4 ++++ 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 120bfc3..ed3c244 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ rust-version = "1.76" bisync = "0.3.0" byteorder = {version = "1", default-features = false} defmt = {version = "0.3", optional = true} +embassy-futures = {version = "0.1.1", optional = true} embedded-hal = "1.0.0" embedded-hal-async = "1.0.0" embedded-io = "0.6.1" @@ -33,6 +34,7 @@ hex-literal = "0.4.1" sha2 = "0.10" [features] -default = ["log"] +default = ["log", "async-drop"] defmt-log = ["dep:defmt"] log = ["dep:log"] +async-drop = ["dep:embassy-futures"] diff --git a/src/inner/filesystem/files.rs b/src/inner/filesystem/files.rs index 594e417..be84f40 100644 --- a/src/inner/filesystem/files.rs +++ b/src/inner/filesystem/files.rs @@ -1,4 +1,4 @@ -use super::super::super::{bisync, only_sync}; +use super::super::super::{bisync, only_sync, only_async}; use super::super::super::{ErrorType, Read, Seek, SeekFrom, Write}; use super::super::{ filesystem::{ClusterId, DirEntry, Handle}, @@ -49,8 +49,11 @@ impl RawFile { /// error that may occur will be ignored. To handle potential errors, use /// the [`File::close`] method. /// -/// For async Files, async drop does not exist in Rust, so you *must* call -/// [`File::close`] when you are done with a File. +/// For async Files, the implementation of [`Drop`] blocks with [`embassy_futures::block_on`] +/// because there is no way to `.await` inside [`Drop::drop`]. If you would prefer +/// to call [`File::close`] manually instead and rely on the async executor you are already +/// using, you can do that by disabling the `async-drop` Cargo feature, which is enabled by +/// default. pub struct File<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> where D: BlockDevice, @@ -150,7 +153,6 @@ where } } -// async drop does not yet exist :( #[only_sync] impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> @@ -163,6 +165,19 @@ where } } +#[cfg(feature = "async-drop")] +#[only_async] +impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop + for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> +where + D: BlockDevice, + T: TimeSource, +{ + fn drop(&mut self) { + _ = embassy_futures::block_on(self.volume_mgr.close_file(self.raw_file)); + } +} + impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> core::fmt::Debug for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> where diff --git a/src/inner/mod.rs b/src/inner/mod.rs index 3cf4631..84a66e8 100644 --- a/src/inner/mod.rs +++ b/src/inner/mod.rs @@ -19,7 +19,7 @@ use core::fmt::Debug; use embedded_io::ErrorKind; use filesystem::Handle; -use super::{bisync, only_sync}; +use super::{bisync, only_sync, only_async}; #[doc(inline)] pub use blockdevice::{Block, BlockCache, BlockCount, BlockDevice, BlockIdx}; @@ -210,8 +210,11 @@ impl RawVolume { /// any error that may occur will be ignored. To handle potential errors, use /// the [`Volume::close`] method. /// -/// For async Volumes, async drop does not exist in Rust, so you *must* call -/// [`Volume::close`] when you are done with a Volume. +/// For async Volumes, the implementation of [`Drop`] blocks with [`embassy_futures::block_on`] +/// because there is no way to `.await` inside [`Drop::drop`]. If you would prefer +/// to call [`File::close`] manually instead and rely on the async executor you are already +/// using, you can do that by disabling the `async-drop` Cargo feature, which is enabled by +/// default. pub struct Volume<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> where D: BlockDevice, @@ -268,7 +271,6 @@ where } } -// async drop does not yet exist :( #[only_sync] impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop for Volume<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> @@ -281,6 +283,19 @@ where } } +#[cfg(feature = "async-drop")] +#[only_async] +impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop + for Volume<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> +where + D: BlockDevice, + T: TimeSource, +{ + fn drop(&mut self) { + _ = embassy_futures::block_on(self.volume_mgr.close_volume(self.raw_volume)); + } +} + impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> core::fmt::Debug for Volume<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> where diff --git a/src/lib.rs b/src/lib.rs index 4dd6296..6261458 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,6 +70,10 @@ //! //! ## Features //! +//! * `async-drop`: Enabled by default. Implements [`Drop`] for [`asynchronous::File`] +//! and [`asynchronous::Volume`] using [`embassy_futures::block_on`]. Disable if +//! you would prefer to call [`asynchronous::File::close`] and [`asynchronous::Volume::close`] +//! manually using the async executor you are already using. //! * `log`: Enabled by default. Generates log messages using the `log` crate. //! * `defmt-log`: By turning off the default features and enabling the //! `defmt-log` feature you can configure this crate to log messages over defmt