safer_ring/operation/
submitted.rs

1//! Submitted state implementation for in-flight operations.
2//!
3//! This module contains functionality for operations that have been submitted
4//! to the kernel and are currently in flight.
5
6use std::os::unix::io::RawFd;
7
8use super::core::{BufferType, FdType, Operation};
9use crate::operation::{Completed, OperationType, Submitted};
10
11impl<'ring, 'buf> Operation<'ring, 'buf, Submitted> {
12    /// Get the operation ID.
13    ///
14    /// This ID is used to track the operation in the completion queue
15    /// and match completions to their corresponding operations.
16    #[inline]
17    pub fn id(&self) -> u64 {
18        self.state.id
19    }
20
21    /// Get the file descriptor for this operation.
22    #[inline]
23    pub fn fd(&self) -> RawFd {
24        match &self.fd {
25            FdType::Raw(fd) => *fd,
26            FdType::Registered(reg_fd) => reg_fd.raw_fd(),
27            FdType::Fixed(fixed_file) => fixed_file.raw_fd(),
28        }
29    }
30
31    /// Get the offset for this operation.
32    #[inline]
33    pub fn offset(&self) -> u64 {
34        self.offset
35    }
36
37    /// Get the operation type.
38    #[inline]
39    pub fn op_type(&self) -> OperationType {
40        self.op_type
41    }
42
43    /// Get buffer information for kernel submission.
44    ///
45    /// Returns a tuple of (pointer, length) for the buffer if present.
46    /// This is used internally by the Ring for kernel submission.
47    ///
48    /// # Safety
49    ///
50    /// The returned pointer is only valid while the buffer remains pinned
51    /// and the operation is in flight. The caller must ensure the buffer
52    /// is not moved or dropped until the operation completes.
53    #[allow(dead_code)] // Used by ring submission logic
54    pub(crate) fn buffer_info(&self) -> Option<(*mut u8, usize)> {
55        match &self.buffer {
56            BufferType::None => None,
57            BufferType::Pinned(buf) => {
58                let slice = buf.as_ref();
59                Some((slice.as_ptr() as *mut u8, slice.len()))
60            }
61            BufferType::Registered(_) => {
62                // For registered buffers, we need to get the buffer info from the registry
63                // This will be handled by the ring during submission
64                None
65            }
66            BufferType::Vectored(_) => {
67                // For vectored operations, buffer info is handled differently
68                // This will be handled by the ring during submission
69                None
70            }
71        }
72    }
73
74    /// Get vectored buffer information for kernel submission.
75    ///
76    /// Returns a vector of (pointer, length) tuples for vectored operations.
77    /// This is used internally by the Ring for vectored operation submission.
78    ///
79    /// # Safety
80    ///
81    /// The returned pointers are only valid while the buffers remain pinned
82    /// and the operation is in flight.
83    #[allow(dead_code)] // Used by ring submission logic
84    pub(crate) fn vectored_buffer_info(&self) -> Option<Vec<(*mut u8, usize)>> {
85        match &self.buffer {
86            BufferType::Vectored(buffers) => {
87                let info: Vec<_> = buffers
88                    .iter()
89                    .map(|buf| {
90                        let slice = buf.as_ref();
91                        (slice.as_ptr() as *mut u8, slice.len())
92                    })
93                    .collect();
94                Some(info)
95            }
96            _ => None,
97        }
98    }
99
100    /// Check if this operation uses a registered buffer.
101    #[inline]
102    pub fn uses_registered_buffer(&self) -> bool {
103        matches!(self.buffer, BufferType::Registered(_))
104    }
105
106    /// Check if this operation uses a registered file descriptor.
107    #[inline]
108    pub fn uses_registered_fd(&self) -> bool {
109        matches!(self.fd, FdType::Registered(_))
110    }
111
112    /// Check if this operation uses a fixed file.
113    #[inline]
114    pub fn uses_fixed_file(&self) -> bool {
115        matches!(self.fd, FdType::Fixed(_))
116    }
117
118    /// Check if this operation is vectored.
119    #[inline]
120    pub fn is_vectored(&self) -> bool {
121        matches!(self.buffer, BufferType::Vectored(_))
122    }
123
124    /// Convert this submitted operation to a completed operation.
125    ///
126    /// This is typically called by the Ring when processing completions.
127    /// The state transition is zero-cost at runtime.
128    ///
129    /// # Arguments
130    ///
131    /// * `result` - The result of the completed operation
132    #[allow(dead_code)]
133    pub(crate) fn complete_with_result<T>(self, result: T) -> Operation<'ring, 'buf, Completed<T>> {
134        // Zero-cost state transition - just change the type parameter
135        Operation {
136            ring: self.ring,
137            buffer: self.buffer,
138            fd: self.fd,
139            offset: self.offset,
140            op_type: self.op_type,
141            state: Completed { result },
142        }
143    }
144}