Skip to main content

user_copy/
user_iovec.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use crate::user_ptr::{UserInOutPtr, UserInPtr, UserOutPtr};
8use zerocopy::{FromBytes, Immutable, IntoBytes};
9use zx_status::Status;
10use zx_types::zx_iovec_t;
11
12#[repr(C)]
13#[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, Default)]
14struct RawIovec {
15    buffer: usize,
16    capacity: usize,
17}
18
19/// A wrapper around a userspace array of `zx_iovec_t` for read operations.
20#[derive(Debug, Copy, Clone)]
21pub struct UserInIovec {
22    vector: UserInPtr<zx_iovec_t>,
23    count: usize,
24}
25
26impl UserInIovec {
27    /// Constructs a new `UserInIovec`.
28    pub const fn new(vector: UserInPtr<zx_iovec_t>, count: usize) -> Self {
29        Self { vector, count }
30    }
31
32    /// Returns true if the underlying pointer is null.
33    pub fn is_null(&self) -> bool {
34        self.vector.is_null()
35    }
36
37    /// Calculates the total capacity across all iovecs.
38    pub fn get_total_capacity(&self) -> Result<usize, Status> {
39        let mut total = 0usize;
40        let raw_vec = self.vector.reinterpret::<RawIovec>();
41        for i in 0..self.count {
42            let elem = raw_vec.element_offset(i).read()?;
43            total = total.checked_add(elem.capacity).ok_or(Status::INVALID_ARGS)?;
44        }
45        Ok(total)
46    }
47
48    /// Iterates through the iovecs and invokes the callback for each user pointer and capacity.
49    pub fn for_each<F>(&self, mut cb: F) -> Result<(), Status>
50    where
51        F: FnMut(UserInPtr<u8>, usize) -> Result<(), Status>,
52    {
53        let raw_vec = self.vector.reinterpret::<RawIovec>();
54        for i in 0..self.count {
55            let elem = raw_vec.element_offset(i).read()?;
56            let ptr = UserInPtr::new(elem.buffer as *const u8);
57            cb(ptr, elem.capacity)?;
58        }
59        Ok(())
60    }
61}
62
63/// A wrapper around a userspace array of `zx_iovec_t` for write operations.
64#[derive(Debug, Copy, Clone)]
65pub struct UserOutIovec {
66    vector: UserInPtr<zx_iovec_t>,
67    count: usize,
68}
69
70impl UserOutIovec {
71    /// Constructs a new `UserOutIovec`.
72    pub const fn new(vector: UserInPtr<zx_iovec_t>, count: usize) -> Self {
73        Self { vector, count }
74    }
75
76    /// Returns true if the underlying pointer is null.
77    pub fn is_null(&self) -> bool {
78        self.vector.is_null()
79    }
80
81    /// Calculates the total capacity across all iovecs.
82    pub fn get_total_capacity(&self) -> Result<usize, Status> {
83        let mut total = 0usize;
84        let raw_vec = self.vector.reinterpret::<RawIovec>();
85        for i in 0..self.count {
86            let elem = raw_vec.element_offset(i).read()?;
87            total = total.checked_add(elem.capacity).ok_or(Status::INVALID_ARGS)?;
88        }
89        Ok(total)
90    }
91
92    /// Iterates through the iovecs and invokes the callback for each user pointer and capacity.
93    pub fn for_each<F>(&self, mut cb: F) -> Result<(), Status>
94    where
95        F: FnMut(UserOutPtr<u8>, usize) -> Result<(), Status>,
96    {
97        let raw_vec = self.vector.reinterpret::<RawIovec>();
98        for i in 0..self.count {
99            let elem = raw_vec.element_offset(i).read()?;
100            let ptr = UserOutPtr::new(elem.buffer as *mut u8);
101            cb(ptr, elem.capacity)?;
102        }
103        Ok(())
104    }
105}
106
107/// A wrapper around a userspace array of `zx_iovec_t` for read-write operations.
108#[derive(Debug, Copy, Clone)]
109pub struct UserInOutIovec {
110    vector: UserInPtr<zx_iovec_t>,
111    count: usize,
112}
113
114impl UserInOutIovec {
115    /// Constructs a new `UserInOutIovec`.
116    pub const fn new(vector: UserInPtr<zx_iovec_t>, count: usize) -> Self {
117        Self { vector, count }
118    }
119
120    /// Returns true if the underlying pointer is null.
121    pub fn is_null(&self) -> bool {
122        self.vector.is_null()
123    }
124
125    /// Calculates the total capacity across all iovecs.
126    pub fn get_total_capacity(&self) -> Result<usize, Status> {
127        let mut total = 0usize;
128        let raw_vec = self.vector.reinterpret::<RawIovec>();
129        for i in 0..self.count {
130            let elem = raw_vec.element_offset(i).read()?;
131            total = total.checked_add(elem.capacity).ok_or(Status::INVALID_ARGS)?;
132        }
133        Ok(total)
134    }
135
136    /// Iterates through the iovecs and invokes the callback for each user pointer and capacity.
137    pub fn for_each<F>(&self, mut cb: F) -> Result<(), Status>
138    where
139        F: FnMut(UserInOutPtr<u8>, usize) -> Result<(), Status>,
140    {
141        let raw_vec = self.vector.reinterpret::<RawIovec>();
142        for i in 0..self.count {
143            let elem = raw_vec.element_offset(i).read()?;
144            let ptr = UserInOutPtr::new(elem.buffer as *mut u8);
145            cb(ptr, elem.capacity)?;
146        }
147        Ok(())
148    }
149}