Skip to main content

async_fuser/ll/reply_async/
read.rs

1//! Response data implementation of [`crate::AsyncFilesystem::read`] operation to
2//! send to the kernel
3
4use std::io::IoSlice;
5use std::sync::Arc;
6
7use crate::ll::{ioslice_concat::IosliceConcat, reply::Response};
8
9/// Internal representation of the response data, which
10/// can be either owned or shared.
11#[derive(Debug)]
12enum ReadResponseData {
13    Owned(Vec<u8>),
14    Shared {
15        data: Arc<[u8]>,
16        start: usize,
17        end: usize,
18    },
19}
20
21/// Response data from [`crate::AsyncFilesystem::read`] operation
22#[derive(Debug)]
23pub struct ReadResponse {
24    data: ReadResponseData,
25}
26
27impl ReadResponse {
28    /// Creates a new [`ReadResponse`] with a specified buffer.
29    pub fn new(data: Vec<u8>) -> ReadResponse {
30        ReadResponse {
31            data: ReadResponseData::Owned(data),
32        }
33    }
34
35    /// Creates a [`ReadResponse`] backed by a slice of shared data without copying it.
36    ///
37    /// The requested range is clamped to the bounds of `data`.
38    pub fn from_shared_slice(data: Arc<[u8]>, offset: usize, size: usize) -> ReadResponse {
39        let start = offset.min(data.len());
40        let end = start.saturating_add(size).min(data.len());
41        ReadResponse {
42            data: ReadResponseData::Shared { data, start, end },
43        }
44    }
45
46    fn bytes(&self) -> &[u8] {
47        match &self.data {
48            ReadResponseData::Owned(data) => data.as_slice(),
49            ReadResponseData::Shared { data, start, end } => &data[*start..*end],
50        }
51    }
52}
53
54impl Response for ReadResponse {
55    fn payload(&self) -> impl IosliceConcat {
56        [IoSlice::new(self.bytes())]
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::ReadResponse;
63    use std::sync::Arc;
64
65    #[test]
66    fn shared_slice_clamps_to_bounds() {
67        let response = ReadResponse::from_shared_slice(Arc::from(&b"abcdef"[..]), 2, 99);
68        assert_eq!(response.bytes(), b"cdef");
69    }
70
71    #[test]
72    fn shared_slice_handles_offset_past_end() {
73        let response = ReadResponse::from_shared_slice(Arc::from(&b"abcdef"[..]), 99, 4);
74        assert_eq!(response.bytes(), b"");
75    }
76}