wlancfg_lib/util/
future_with_metadata.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use futures::future::LocalBoxFuture;
6use futures::prelude::*;
7use futures::task::Poll;
8
9/// Wraps a future in order to allow reading/writing of "metadata" while
10/// the future is pending. When the future finishes, it will resolve with
11/// a tuple: (inner_fut::Output, metadata).
12pub struct FutureWithMetadata<F, M> {
13    inner_fut: LocalBoxFuture<'static, F>,
14    pub metadata: M,
15}
16
17impl<F, M> FutureWithMetadata<F, M>
18where
19    M: Unpin + Clone,
20{
21    pub fn new(metadata: M, future: LocalBoxFuture<'static, F>) -> Self {
22        Self { metadata, inner_fut: future }
23    }
24}
25
26impl<F, M> Future for FutureWithMetadata<F, M>
27where
28    M: Unpin + Clone,
29{
30    type Output = (F, M);
31    fn poll(
32        mut self: std::pin::Pin<&mut Self>,
33        cx: &mut std::task::Context<'_>,
34    ) -> std::task::Poll<<Self as Future>::Output> {
35        match self.inner_fut.poll_unpin(cx) {
36            Poll::Pending => Poll::Pending,
37            Poll::Ready(val) => Poll::Ready((val, self.metadata.clone())),
38        }
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use assert_matches::assert_matches;
46    use fuchsia_async as fasync;
47    use std::pin::pin;
48
49    #[fuchsia::test]
50    fn assign_and_read_metadata_in_future_output() {
51        let mut exec = fasync::TestExecutor::new();
52
53        #[derive(Debug, Clone)]
54        struct TestMetadata {
55            has_been_written: bool,
56        }
57
58        // Create a future
59        let test_future = FutureWithMetadata::new(
60            TestMetadata { has_been_written: false },
61            future::ready("future result").boxed(),
62        );
63        let mut test_future = pin!(test_future);
64
65        // Ensure the initial value is as expected
66        assert!(!test_future.metadata.has_been_written);
67
68        // Mutate the metadata
69        test_future.metadata.has_been_written = true;
70
71        // The future should resolve with the metadata
72        assert_matches!(exec.run_until_stalled(&mut test_future), Poll::Ready((fut_result, metadata)) => {
73            assert!(metadata.has_been_written);
74            assert_eq!(fut_result, "future result");
75        });
76    }
77}