twizzler_rt_abi/
io.rs

1//! Runtime interface for IO-like operations.
2
3#![allow(unused_variables)]
4use core::{mem::MaybeUninit, sync::atomic::AtomicU64};
5
6use crate::{
7    bindings::wait_kind,
8    error::RawTwzError,
9    fd::{RawFd, SocketAddress},
10    nk, Result,
11};
12
13bitflags::bitflags! {
14    /// Possible flags for IO operations.
15    #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16    pub struct IoFlags : crate::bindings::io_flags {
17        /// This operation should have non-blocking semantics, regardless of fd status.
18        const NONBLOCKING = crate::bindings::IO_NONBLOCKING;
19        /// This operation should peek at the data without removing it from the buffer.
20        const PEEK = crate::bindings::IO_PEEK;
21        /// This operation should wait for all data to be read before returning (not guaranteed).
22        const WAITALL = crate::bindings::IO_WAITALL;
23        /// This operation should read out-of-band data.
24        const OOB = crate::bindings::IO_OOB;
25    }
26}
27
28/// Possible seek start points and offset.
29pub enum SeekFrom {
30    Start(u64),
31    End(i64),
32    Current(i64),
33}
34
35fn optoff(off: Option<u64>) -> crate::bindings::optional_offset {
36    match off {
37        Some(o) => o.try_into().unwrap_or(crate::bindings::FD_POS),
38        None => crate::bindings::FD_POS,
39    }
40}
41
42impl Into<Result<usize>> for crate::bindings::io_result {
43    fn into(self) -> Result<usize> {
44        let raw = RawTwzError::new(self.err);
45        if raw.is_success() {
46            Ok(self.val)
47        } else {
48            Err(raw.error())
49        }
50    }
51}
52
53impl From<Result<usize>> for crate::bindings::io_result {
54    fn from(value: Result<usize>) -> Self {
55        match value {
56            Ok(v) => Self {
57                val: v,
58                err: RawTwzError::success().raw(),
59            },
60            Err(e) => Self {
61                val: 0,
62                err: e.raw(),
63            },
64        }
65    }
66}
67
68#[derive(Clone, Copy)]
69#[repr(transparent)]
70pub struct IoCtx(crate::bindings::io_ctx);
71
72impl Default for IoCtx {
73    fn default() -> Self {
74        Self::new(None, IoFlags::empty(), None)
75    }
76}
77
78impl IoCtx {
79    pub fn new(pos: Option<u64>, flags: IoFlags, timeout: Option<core::time::Duration>) -> Self {
80        Self(crate::bindings::io_ctx {
81            offset: optoff(pos),
82            flags: flags.bits(),
83            timeout: timeout.into(),
84        })
85    }
86
87    pub fn offset(mut self, offset: Option<u64>) -> Self {
88        self.0.offset = optoff(offset);
89        self
90    }
91
92    pub fn flags(mut self, flags: IoFlags) -> Self {
93        self.0.flags = flags.bits();
94        self
95    }
96
97    pub fn timeout(mut self, timeout: Option<core::time::Duration>) -> Self {
98        self.0.timeout = timeout.into();
99        self
100    }
101
102    pub fn nonblocking(mut self, val: bool) -> Self {
103        if val {
104            self.0.flags |= IoFlags::NONBLOCKING.bits();
105        } else {
106            self.0.flags &= !IoFlags::NONBLOCKING.bits();
107        }
108        self
109    }
110}
111
112/// Read a file descriptor into a buffer, up to buf.len() bytes. On success, returns the number of
113/// bytes actually read, which may be fewer than requested.
114pub fn twz_rt_fd_pread(fd: RawFd, buf: &mut [u8], ctx: &mut IoCtx) -> Result<usize> {
115    unsafe {
116        nk!(
117            crate::bindings::twz_rt_fd_pread(fd, buf.as_mut_ptr().cast(), buf.len(), &mut ctx.0)
118                .into()
119        )
120    }
121}
122
123/// Write bytes from a buffer into a file descriptor, up to buf.len() bytes. On success, returns the
124/// number of bytes actually written, which may be fewer than requested.
125pub fn twz_rt_fd_pwrite(fd: RawFd, buf: &[u8], ctx: &mut IoCtx) -> Result<usize> {
126    unsafe {
127        nk!(
128            crate::bindings::twz_rt_fd_pwrite(fd, buf.as_ptr().cast(), buf.len(), &mut ctx.0)
129                .into()
130        )
131    }
132}
133
134/// Seek a file descriptor, changing the internal position.
135pub fn twz_rt_fd_seek(fd: RawFd, seek: SeekFrom) -> Result<usize> {
136    let (whence, off) = match seek {
137        SeekFrom::Start(s) => (crate::bindings::WHENCE_START, s as i64),
138        SeekFrom::End(s) => (crate::bindings::WHENCE_END, s),
139        SeekFrom::Current(s) => (crate::bindings::WHENCE_CURRENT, s),
140    };
141    unsafe { nk!(crate::bindings::twz_rt_fd_seek(fd, whence, off).into()) }
142}
143
144#[derive(Copy, Clone)]
145#[repr(transparent)]
146pub struct Endpoint(crate::bindings::endpoint);
147
148impl Endpoint {
149    fn new_socket(sock: super::fd::SocketAddress) -> Self {
150        Self(crate::bindings::endpoint {
151            kind: crate::bindings::endpoint_kind_Endpoint_Socket,
152            addr: crate::bindings::endpoint_addrs {
153                socket_addr: sock.0,
154            },
155        })
156    }
157}
158
159#[repr(u32)]
160pub enum EndpointKind {
161    Unspecified = crate::bindings::endpoint_kind_Endpoint_Unspecified,
162    Socket = crate::bindings::endpoint_kind_Endpoint_Socket,
163}
164
165impl From<crate::bindings::endpoint> for Endpoint {
166    fn from(value: crate::bindings::endpoint) -> Self {
167        Self(value)
168    }
169}
170
171impl From<SocketAddress> for Endpoint {
172    fn from(value: SocketAddress) -> Self {
173        Self::new_socket(value)
174    }
175}
176
177impl TryFrom<Endpoint> for SocketAddress {
178    type Error = crate::error::TwzError;
179
180    fn try_from(value: Endpoint) -> Result<Self> {
181        match value.0.kind {
182            crate::bindings::endpoint_kind_Endpoint_Socket => {
183                let addr = unsafe { value.0.addr.socket_addr };
184                Ok(SocketAddress(addr))
185            }
186            _ => Err(crate::error::TwzError::INVALID_ARGUMENT),
187        }
188    }
189}
190
191/// Read a file descriptor into a buffer, up to buf.len() bytes. On success, returns the number of
192/// bytes actually read, which may be fewer than requested.
193pub fn twz_rt_fd_pread_from(
194    fd: RawFd,
195    buf: &mut [u8],
196    ctx: &mut IoCtx,
197) -> Result<(usize, Endpoint)> {
198    let mut endpoint = core::mem::MaybeUninit::uninit();
199    unsafe {
200        let len: Result<_> = nk!(crate::bindings::twz_rt_fd_pread_from(
201            fd,
202            buf.as_mut_ptr().cast(),
203            buf.len(),
204            &mut ctx.0,
205            endpoint.as_mut_ptr(),
206        ))
207        .into();
208        let len = len?;
209        Ok((len, endpoint.assume_init().into()))
210    }
211}
212
213/// Write bytes from a buffer into a file descriptor, up to buf.len() bytes. On success, returns the
214/// number of bytes actually written, which may be fewer than requested.
215pub fn twz_rt_fd_pwrite_to(
216    fd: RawFd,
217    buf: &[u8],
218    ctx: &mut IoCtx,
219    mut ep: Endpoint,
220) -> Result<usize> {
221    unsafe {
222        nk!(crate::bindings::twz_rt_fd_pwrite_to(
223            fd,
224            buf.as_ptr().cast(),
225            buf.len(),
226            &mut ctx.0,
227            &mut ep.0,
228        ))
229        .into()
230    }
231}
232
233/// Type of an IO vec buffer and length.
234pub type IoSlice = crate::bindings::iovec;
235
236/// Read a file descriptor into a multiple buffers. On success, returns the number of bytes actually
237/// read, which may be fewer than requested. If offset is None, use the file descriptor's internal
238/// position. If the file descriptor refers to a non-seekable file, and offset is Some, this
239/// function returns an error.
240pub fn twz_rt_fd_preadv(fd: RawFd, ios: &[IoSlice], ctx: &mut IoCtx) -> Result<usize> {
241    unsafe {
242        nk!(crate::bindings::twz_rt_fd_pwritev(fd, ios.as_ptr(), ios.len(), &mut ctx.0).into())
243    }
244}
245
246/// Write multiple buffers into a file descriptor. On success, returns the number of bytes actually
247/// written, which may be fewer than requested. If offset is None, use the file descriptor's
248/// internal position. If the file descriptor refers to a non-seekable file, and offset is Some,
249/// this function returns an error.
250pub fn twz_rt_fd_pwritev(fd: RawFd, ios: &[IoSlice], ctx: &mut IoCtx) -> Result<usize> {
251    unsafe {
252        nk!(crate::bindings::twz_rt_fd_pwritev(fd, ios.as_ptr(), ios.len(), &mut ctx.0).into())
253    }
254}
255
256pub fn twz_rt_fd_get_config<T>(fd: RawFd, reg: u32) -> Result<T> {
257    let mut val = core::mem::MaybeUninit::<T>::uninit();
258    let e = unsafe {
259        nk!(crate::bindings::twz_rt_fd_get_config(
260            fd,
261            reg,
262            val.as_mut_ptr().cast(),
263            core::mem::size_of::<T>(),
264        ))
265    };
266    let raw = RawTwzError::new(e);
267    if !raw.is_success() {
268        return Err(raw.error());
269    }
270    Ok(unsafe { val.assume_init() })
271}
272
273pub fn twz_rt_fd_set_config<T>(fd: RawFd, reg: u32, val: T) -> Result<()> {
274    let e = unsafe {
275        nk!(crate::bindings::twz_rt_fd_set_config(
276            fd,
277            reg,
278            ((&val) as *const T).cast(),
279            core::mem::size_of::<T>(),
280        ))
281    };
282    let raw = RawTwzError::new(e);
283    if !raw.is_success() {
284        return Err(raw.error());
285    }
286    Ok(())
287}
288
289pub fn twz_rt_fd_waitpoint(fd: RawFd, kind: wait_kind) -> Result<(*const AtomicU64, u64, bool)> {
290    let mut pt = MaybeUninit::uninit();
291    let mut val = MaybeUninit::uninit();
292    let mut ready = MaybeUninit::uninit();
293    let e = unsafe {
294        nk!(crate::bindings::twz_rt_fd_waitpoint(
295            fd,
296            kind,
297            pt.as_mut_ptr(),
298            val.as_mut_ptr(),
299            ready.as_mut_ptr()
300        ))
301    };
302    let raw = RawTwzError::new(e);
303    if !raw.is_success() {
304        return Err(raw.error());
305    }
306    Ok((
307        unsafe { pt.assume_init().cast() },
308        unsafe { val.assume_init() },
309        unsafe { ready.assume_init() },
310    ))
311}