1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Traits required by `audio_streams` to perform async operations.
//!
//! Consumers must provide an implementation of `AudioStreamsExecutor` to allow the
//! async `audio_streams` interface to do async io on the Executor provided by the consumer.
//!
//! These traits follow the interface of `cros_async`, since it is used by both crosvm and libcras
//! to implement them.
//!
//! The implementation is provided in `cros_async::audio_streams_async`.

use std::io::Result;
#[cfg(any(target_os = "android", target_os = "linux"))]
use std::os::unix::io::RawFd as RawDescriptor;
#[cfg(any(target_os = "android", target_os = "linux"))]
use std::os::unix::net::UnixStream;
#[cfg(windows)]
use std::os::windows::io::RawHandle;
use std::time::Duration;

use async_trait::async_trait;

#[async_trait(?Send)]
pub trait ReadAsync {
    /// Read asynchronously into the provided Vec.
    ///
    /// The ownership of the Vec is returned after the operation completes, along with the number of
    /// bytes read.
    async fn read_to_vec<'a>(
        &'a self,
        file_offset: Option<u64>,
        vec: Vec<u8>,
    ) -> Result<(usize, Vec<u8>)>;
}

#[async_trait(?Send)]
pub trait WriteAsync {
    /// Write asynchronously from the provided Vec.
    ///
    /// The ownership of the Vec is returned after the operation completes, along with the number of
    /// bytes written.
    async fn write_from_vec<'a>(
        &'a self,
        file_offset: Option<u64>,
        vec: Vec<u8>,
    ) -> Result<(usize, Vec<u8>)>;
}

/// Trait to wrap around EventAsync, because audio_streams can't depend on anything in `base` or
/// `cros_async`.
#[async_trait(?Send)]
pub trait EventAsyncWrapper {
    async fn wait(&self) -> Result<u64>;
}

pub trait ReadWriteAsync: ReadAsync + WriteAsync {}

pub type AsyncStream = Box<dyn ReadWriteAsync + Send>;

/// Trait of Executor functionality used by `audio_streams`.
#[async_trait(?Send)]
pub trait AudioStreamsExecutor {
    /// Create an object to allow async reads/writes from the specified UnixStream.
    #[cfg(any(target_os = "android", target_os = "linux"))]
    fn async_unix_stream(&self, f: UnixStream) -> Result<AsyncStream>;

    /// Wraps an event that will be triggered when the audio backend is ready to read more audio
    /// data.
    ///
    /// # Safety
    /// Callers needs to make sure the `RawHandle` is an Event, or at least a valid Handle for
    /// their use case.
    #[cfg(windows)]
    unsafe fn async_event(&self, event: RawHandle) -> Result<Box<dyn EventAsyncWrapper>>;

    /// Returns a future that resolves after the specified time.
    async fn delay(&self, dur: Duration) -> Result<()>;

    // Returns a future that resolves after the provided descriptor is readable.
    #[cfg(any(target_os = "android", target_os = "linux"))]
    async fn wait_fd_readable(&self, _fd: RawDescriptor) -> Result<()> {
        Ok(())
    }
}

#[cfg(test)]
pub mod test {
    use super::*;

    /// Stub implementation of the AudioStreamsExecutor to use in unit tests.
    pub struct TestExecutor {}

    #[async_trait(?Send)]
    impl AudioStreamsExecutor for TestExecutor {
        #[cfg(any(target_os = "android", target_os = "linux"))]
        fn async_unix_stream(&self, _f: UnixStream) -> Result<AsyncStream> {
            panic!("Not Implemented");
        }

        async fn delay(&self, dur: Duration) -> Result<()> {
            // Simulates the delay by blocking to satisfy behavior expected in unit tests.
            std::thread::sleep(dur);
            return Ok(());
        }

        #[cfg(windows)]
        unsafe fn async_event(&self, _event: RawHandle) -> Result<Box<dyn EventAsyncWrapper>> {
            unimplemented!("async_event is not yet implemented on windows");
        }
    }
}