Skip to content

feat: accept FnMut closures in enumerate_directory#383

Open
revmischa wants to merge 4 commits into
masterfrom
feat/enumerate-directory-fnmut
Open

feat: accept FnMut closures in enumerate_directory#383
revmischa wants to merge 4 commits into
masterfrom
feat/enumerate-directory-fnmut

Conversation

@revmischa

@revmischa revmischa commented May 11, 2026

Copy link
Copy Markdown
Member

SDL_EnumerateDirectory is synchronous, so the callback only needs to live for the duration of the call. Switching from fn(&Path, &Path) -> EnumerationResult to a generic FnMut(&Path, &Path) -> EnumerationResult lets callers capture state (collect entries into a Vec, count matches, close over a regex, etc.) with zero allocation. userdata is just &mut F.

Also catches panics from the user callback so they don't unwind through SDL's extern "C" frames (UB).

Removes the EnumerateCallback type alias. Existing callers passing function names or non-capturing closures (including examples/filesystem.rs) keep working unchanged.

revmischa added 4 commits May 10, 2026 21:38
SDL_EnumerateDirectory is synchronous, so the callback only needs to live
for the duration of the call. Switching from a bare fn pointer to a
generic FnMut lets callers capture state (push into a Vec, increment a
counter, etc.) without any allocation - userdata is just &mut F.

Removes the EnumerateCallback type alias; existing callers passing
function names or non-capturing closures keep working unchanged.
A panic from the user callback unwinds through SDL's extern "C" frames,
which is UB. Catch it in the trampoline, stash it, and resume_unwind
after SDL_EnumerateDirectory returns. Pre-existing issue on the old
fn-pointer signature too, but worth fixing now that closures make it
easier to hit.
- Drop crate::sdl::init(); SDL_EnumerateDirectory is pure filesystem.
- RAII TempDir guard so failed asserts don't leak temp directories.
- Atomic counter for uniqueness instead of nanos timestamps.
- Panic test now panics mid-iteration to exercise the
  state.panic.is_some() short-circuit in c_enumerate_directory.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the filesystem::enumerate_directory wrapper to accept capturing callbacks and to prevent Rust panics from unwinding through SDL’s extern "C" callback boundary.

Changes:

  • Replace the fn(&Path, &Path) -> EnumerationResult callback with a generic F: FnMut(&Path, &Path) -> EnumerationResult.
  • Add catch_unwind + deferred resume_unwind to avoid unwinding across FFI while still propagating user panics.
  • Add unit tests covering state capture, early stop behavior, panic propagation, and nonexistent paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/sdl3/filesystem.rs
Comment on lines 97 to +101
pub use sys::filesystem::SDL_EnumerationResult as EnumerationResult;

pub type EnumerateCallback = fn(&Path, &Path) -> EnumerationResult;
struct EnumerateState<F> {
callback: F,
panic: Option<Box<dyn std::any::Any + Send + 'static>>,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants