[rust][vfs] Reduce monomorphization of test functions

Test: no behavioral change
Change-Id: I479a2d06b3b25522b74540981b5fdf4692c96f37
diff --git a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/common.rs b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/common.rs
index efe6d54..76415fa 100644
--- a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/common.rs
+++ b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/common.rs
@@ -11,8 +11,13 @@
         OPEN_FLAG_NODE_REFERENCE, OPEN_RIGHT_ADMIN, OPEN_RIGHT_READABLE, OPEN_RIGHT_WRITABLE,
     },
     fuchsia_zircon::Status,
+    std::{future::Future, pin::Pin},
 };
 
+/// A dynamically-dispatched asynchronous function.
+pub(crate) type AsyncFnOnce<'a, ArgTy, OutputTy> =
+    Box<dyn FnOnce(ArgTy) -> Pin<Box<dyn Future<Output = OutputTy> + 'a>> + 'a>;
+
 /// Set of known rights.
 const FS_RIGHTS: u32 = OPEN_RIGHT_READABLE | OPEN_RIGHT_WRITABLE | OPEN_RIGHT_ADMIN;
 
diff --git a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/directory/test_utils.rs b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/directory/test_utils.rs
index 52e85ee..e6d5ab88 100644
--- a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/directory/test_utils.rs
+++ b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/directory/test_utils.rs
@@ -22,7 +22,7 @@
 }
 
 use {
-    crate::directory::entry::DirectoryEntry,
+    crate::{common::AsyncFnOnce, directory::entry::DirectoryEntry},
     byteorder::{LittleEndian, WriteBytesExt},
     fidl::endpoints::{create_proxy, ServerEnd},
     fidl_fuchsia_io::{DirectoryMarker, DirectoryProxy, MAX_FILENAME},
@@ -96,13 +96,32 @@
 pub fn run_server_client_with_mode_and_executor<GetClientRes>(
     flags: u32,
     mode: u32,
-    mut exec: Executor,
-    mut server: impl DirectoryEntry,
+    exec: Executor,
+    server: impl DirectoryEntry,
     get_client: impl FnOnce(DirectoryProxy) -> GetClientRes,
-    executor: impl FnOnce(&mut FnMut(bool) -> ()),
+    executor: impl FnOnce(&mut dyn FnMut(bool)),
 ) where
     GetClientRes: Future<Output = ()>,
 {
+    run_server_client_with_mode_and_executor_dyn(
+        flags,
+        mode,
+        exec,
+        Box::new(server),
+        Box::new(|proxy| Box::pin(get_client(proxy))),
+        Box::new(executor),
+    )
+}
+
+// helper to prevent unnecessary monomorphization
+fn run_server_client_with_mode_and_executor_dyn<'a>(
+    flags: u32,
+    mode: u32,
+    mut exec: Executor,
+    mut server: Box<dyn DirectoryEntry + 'a>,
+    get_client: AsyncFnOnce<'a, DirectoryProxy, ()>,
+    executor: Box<dyn FnOnce(&mut dyn FnMut(bool)) + 'a>,
+) {
     let (client_proxy, server_end) =
         create_proxy::<DirectoryMarker>().expect("Failed to create connection endpoints");
 
@@ -152,6 +171,9 @@
 pub type OpenRequestArgs<'path> =
     (u32, u32, Box<Iterator<Item = &'path str>>, ServerEnd<DirectoryMarker>);
 
+/// The sender end of a channel to proxy open requests.
+pub type OpenRequestSender<'path> = mpsc::Sender<OpenRequestArgs<'path>>;
+
 /// Similar to [`run_server_client()`] but does not automatically connect the server and the client
 /// code.  Instead the client receives a sender end of an [`OpenRequestArgs`] queue, capable of
 /// receiving arguments for the `open()` calls on the server.  This way the client can control when
@@ -160,7 +182,7 @@
 /// server is to `clone()` the existing one, which might be undesirable for a particular test.
 pub fn run_server_client_with_open_requests_channel<'path, GetClientRes>(
     server: impl DirectoryEntry,
-    get_client: impl FnOnce(mpsc::Sender<OpenRequestArgs<'path>>) -> GetClientRes,
+    get_client: impl FnOnce(OpenRequestSender<'path>) -> GetClientRes,
 ) where
     GetClientRes: Future<Output = ()>,
 {
@@ -191,13 +213,28 @@
 /// The server is wrapped in an async block that returns if it's `is_terminated` method returns
 /// true.
 pub fn run_server_client_with_open_requests_channel_and_executor<'path, GetClientRes>(
-    mut exec: Executor,
-    mut server: impl DirectoryEntry,
-    get_client: impl FnOnce(mpsc::Sender<OpenRequestArgs<'path>>) -> GetClientRes,
-    executor: impl FnOnce(&mut FnMut(bool) -> ()),
+    exec: Executor,
+    server: impl DirectoryEntry,
+    get_client: impl FnOnce(OpenRequestSender<'path>) -> GetClientRes,
+    executor: impl FnOnce(&mut dyn FnMut(bool)),
 ) where
     GetClientRes: Future<Output = ()>,
 {
+    run_server_client_with_open_requests_channel_and_executor_dyn(
+        exec,
+        Box::new(server),
+        Box::new(|sender| Box::pin(get_client(sender))),
+        Box::new(executor),
+    )
+}
+
+// helper to prevent monomorphization
+fn run_server_client_with_open_requests_channel_and_executor_dyn<'a, 'path: 'a>(
+    mut exec: Executor,
+    mut server: Box<dyn DirectoryEntry + 'a>,
+    get_client: AsyncFnOnce<'a, OpenRequestSender<'path>, ()>,
+    executor: Box<dyn FnOnce(&mut dyn FnMut(bool)) + 'a>,
+) {
     let (open_requests_tx, open_requests_rx) = mpsc::channel::<OpenRequestArgs<'path>>(0);
 
     let server_wrapper = async move {
diff --git a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/file/test_utils.rs b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/file/test_utils.rs
index 6182acc..a0ad611 100644
--- a/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/file/test_utils.rs
+++ b/garnet/public/rust/fuchsia-vfs/pseudo-fs/src/file/test_utils.rs
@@ -9,7 +9,7 @@
 //! instead of `await!(assert_something(arg))`.
 
 use {
-    crate::directory::entry::DirectoryEntry,
+    crate::{common::AsyncFnOnce, directory::entry::DirectoryEntry},
     fidl::endpoints::{create_proxy, ServerEnd},
     fidl_fuchsia_io::{FileMarker, FileProxy},
     fuchsia_async::Executor,
@@ -82,13 +82,32 @@
 pub fn run_server_client_with_mode_and_executor<GetClientRes>(
     flags: u32,
     mode: u32,
-    mut exec: Executor,
-    mut server: impl DirectoryEntry,
+    exec: Executor,
+    server: impl DirectoryEntry,
     get_client: impl FnOnce(FileProxy) -> GetClientRes,
-    executor: impl FnOnce(&mut FnMut(bool) -> ()),
+    executor: impl FnOnce(&mut dyn FnMut(bool)),
 ) where
     GetClientRes: Future<Output = ()>,
 {
+    run_server_client_with_mode_and_executor_dyn(
+        flags,
+        mode,
+        exec,
+        Box::new(server),
+        Box::new(|proxy| Box::pin(get_client(proxy))),
+        Box::new(executor),
+    )
+}
+
+// helper to avoid monomorphization
+fn run_server_client_with_mode_and_executor_dyn<'a>(
+    flags: u32,
+    mode: u32,
+    mut exec: Executor,
+    mut server: Box<dyn DirectoryEntry + 'a>,
+    get_client: AsyncFnOnce<'a, FileProxy, ()>,
+    executor: Box<dyn FnOnce(&mut dyn FnMut(bool)) + 'a>,
+) {
     let (client_proxy, server_end) =
         create_proxy::<FileMarker>().expect("Failed to create connection endpoints");
 
@@ -137,6 +156,9 @@
 /// Holds arguments for a [`DirectoryEntry::open()`] call, assuming empty path.
 pub type OpenRequestArgs = (u32, u32, ServerEnd<FileMarker>);
 
+/// The sender end of a channel to proxy open requests.
+pub type OpenRequestSender = mpsc::Sender<OpenRequestArgs>;
+
 /// Similar to [`run_server_client()`] but does not automatically connect the server and the client
 /// code.  Instead the client receives a sender end of an [`OpenRequestArgs`] queue, capable of
 /// receiving arguments for the `open()` calls on the server.  This way the client can control when
@@ -145,7 +167,7 @@
 /// server is to `clone()` the existing one, which might be undesirable for a particular test.
 pub fn run_server_client_with_open_requests_channel<GetClientRes>(
     server: impl DirectoryEntry,
-    get_client: impl FnOnce(mpsc::Sender<OpenRequestArgs>) -> GetClientRes,
+    get_client: impl FnOnce(OpenRequestSender) -> GetClientRes,
 ) where
     GetClientRes: Future<Output = ()>,
 {
@@ -177,13 +199,28 @@
 ///
 /// See [`file::simple::mock_directory_with_one_file_and_two_connections`] for a usage example.
 pub fn run_server_client_with_open_requests_channel_and_executor<GetClientRes>(
-    mut exec: Executor,
-    mut server: impl DirectoryEntry,
-    get_client: impl FnOnce(mpsc::Sender<OpenRequestArgs>) -> GetClientRes,
-    executor: impl FnOnce(&mut FnMut(bool) -> ()),
+    exec: Executor,
+    server: impl DirectoryEntry,
+    get_client: impl FnOnce(OpenRequestSender) -> GetClientRes,
+    executor: impl FnOnce(&mut FnMut(bool)),
 ) where
     GetClientRes: Future<Output = ()>,
 {
+    run_server_client_with_open_requests_channel_and_executor_dyn(
+        exec,
+        Box::new(server),
+        Box::new(|sender| Box::pin(get_client(sender))),
+        Box::new(executor),
+    )
+}
+
+// helper to avoid monomorphization
+fn run_server_client_with_open_requests_channel_and_executor_dyn<'a>(
+    mut exec: Executor,
+    mut server: Box<dyn DirectoryEntry + 'a>,
+    get_client: AsyncFnOnce<'a, OpenRequestSender, ()>,
+    executor: Box<dyn FnOnce(&mut dyn FnMut(bool)) + 'a>,
+) {
     let (open_requests_tx, open_requests_rx) = mpsc::channel::<OpenRequestArgs>(0);
 
     let server_wrapper = async move {