safer_ring/operation/building.rs
1//! Building state implementation and operation constructors.
2//!
3//! This module contains all the functionality for operations in the Building state,
4//! including constructors and configuration methods.
5
6use std::marker::PhantomData;
7use std::os::unix::io::RawFd;
8use std::pin::Pin;
9
10use super::core::{BufferType, FdType, Operation};
11use crate::operation::{Building, OperationType, Submitted};
12use crate::registry::{RegisteredBuffer, RegisteredFd};
13
14impl<'ring, 'buf> Default for Operation<'ring, 'buf, Building> {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl<'ring, 'buf> Operation<'ring, 'buf, Building> {
21 /// Create a new operation in the building state.
22 ///
23 /// The operation starts with default values and must be configured
24 /// before it can be submitted.
25 ///
26 /// # Example
27 ///
28 /// ```rust,no_run
29 /// # use safer_ring::operation::Operation;
30 /// let op = Operation::new()
31 /// .fd(0)
32 /// .offset(1024);
33 /// ```
34 pub fn new() -> Self {
35 Self::with_type(OperationType::Read) // Default to read for backwards compatibility
36 }
37
38 /// Create a new read operation.
39 ///
40 /// # Example
41 ///
42 /// ```rust,no_run
43 /// # use safer_ring::operation::Operation;
44 /// # use std::pin::Pin;
45 /// let mut buffer = vec![0u8; 1024];
46 /// let op = Operation::read()
47 /// .fd(0)
48 /// .buffer(Pin::new(buffer.as_mut_slice()));
49 /// ```
50 #[inline]
51 pub fn read() -> Self {
52 Self::with_type(OperationType::Read)
53 }
54
55 /// Create a new vectored read operation.
56 ///
57 /// # Example
58 ///
59 /// ```rust,no_run
60 /// # use safer_ring::operation::Operation;
61 /// # use std::pin::Pin;
62 /// let mut buffer1 = vec![0u8; 512];
63 /// let mut buffer2 = vec![0u8; 512];
64 /// let buffers = vec![
65 /// Pin::new(buffer1.as_mut_slice()),
66 /// Pin::new(buffer2.as_mut_slice()),
67 /// ];
68 /// let op = Operation::read_vectored()
69 /// .fd(0)
70 /// .buffers(buffers);
71 /// ```
72 #[inline]
73 pub fn read_vectored() -> Self {
74 Self::with_type(OperationType::ReadVectored)
75 }
76
77 /// Create a new write operation.
78 ///
79 /// # Example
80 ///
81 /// ```rust,no_run
82 /// # use safer_ring::operation::Operation;
83 /// # use std::pin::Pin;
84 /// let mut buffer = b"Hello, world!".to_vec();
85 /// let op = Operation::write()
86 /// .fd(1)
87 /// .buffer(Pin::new(buffer.as_mut_slice()));
88 /// ```
89 #[inline]
90 pub fn write() -> Self {
91 Self::with_type(OperationType::Write)
92 }
93
94 /// Create a new vectored write operation.
95 ///
96 /// # Example
97 ///
98 /// ```rust,no_run
99 /// # use safer_ring::operation::Operation;
100 /// # use std::pin::Pin;
101 /// let mut buffer1 = b"Hello, ".to_vec();
102 /// let mut buffer2 = b"world!".to_vec();
103 /// let buffers = vec![
104 /// Pin::new(buffer1.as_mut_slice()),
105 /// Pin::new(buffer2.as_mut_slice()),
106 /// ];
107 /// let op = Operation::write_vectored()
108 /// .fd(1)
109 /// .buffers(buffers);
110 /// ```
111 #[inline]
112 pub fn write_vectored() -> Self {
113 Self::with_type(OperationType::WriteVectored)
114 }
115
116 /// Create a new accept operation.
117 ///
118 /// # Example
119 ///
120 /// ```rust,no_run
121 /// # use safer_ring::operation::Operation;
122 /// let op = Operation::accept().fd(3); // listening socket fd
123 /// ```
124 #[inline]
125 pub fn accept() -> Self {
126 Self::with_type(OperationType::Accept)
127 }
128
129 /// Create a new send operation.
130 ///
131 /// # Example
132 ///
133 /// ```rust,no_run
134 /// # use safer_ring::operation::Operation;
135 /// # use std::pin::Pin;
136 /// let mut buffer = b"Hello, client!".to_vec();
137 /// let op = Operation::send()
138 /// .fd(4)
139 /// .buffer(Pin::new(buffer.as_mut_slice()));
140 /// ```
141 #[inline]
142 pub fn send() -> Self {
143 Self::with_type(OperationType::Send)
144 }
145
146 /// Create a new receive operation.
147 ///
148 /// # Example
149 ///
150 /// ```rust,no_run
151 /// # use safer_ring::operation::Operation;
152 /// # use std::pin::Pin;
153 /// let mut buffer = vec![0u8; 1024];
154 /// let op = Operation::recv()
155 /// .fd(4)
156 /// .buffer(Pin::new(buffer.as_mut_slice()));
157 /// ```
158 #[inline]
159 pub fn recv() -> Self {
160 Self::with_type(OperationType::Recv)
161 }
162
163 /// Create a new operation with the specified type.
164 ///
165 /// This is a helper method to reduce code duplication in the constructor methods.
166 #[inline]
167 fn with_type(op_type: OperationType) -> Self {
168 Self {
169 ring: PhantomData,
170 buffer: BufferType::None,
171 fd: FdType::Raw(-1), // Invalid fd that must be set before submission
172 offset: 0,
173 op_type,
174 state: Building,
175 }
176 }
177
178 /// Set the file descriptor for this operation.
179 ///
180 /// This is required for all operations and must be a valid file descriptor.
181 ///
182 /// # Arguments
183 ///
184 /// * `fd` - A valid file descriptor (>= 0)
185 ///
186 /// # Example
187 ///
188 /// ```rust,no_run
189 /// # use safer_ring::operation::Operation;
190 /// let op = Operation::read().fd(0); // stdin
191 /// ```
192 #[inline]
193 pub fn fd(mut self, fd: RawFd) -> Self {
194 self.fd = FdType::Raw(fd);
195 self
196 }
197
198 /// Set a registered file descriptor for this operation.
199 ///
200 /// Using registered file descriptors can improve performance for frequently
201 /// used file descriptors by avoiding kernel lookups.
202 ///
203 /// # Arguments
204 ///
205 /// * `registered_fd` - A registered file descriptor
206 ///
207 /// # Example
208 ///
209 /// ```rust,no_run
210 /// # use safer_ring::{operation::Operation, Registry};
211 /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
212 /// let mut registry = Registry::new();
213 /// let registered_fd = registry.register_fd(0)?;
214 /// let op = Operation::read().registered_fd(registered_fd);
215 /// # Ok(())
216 /// # }
217 /// ```
218 #[inline]
219 pub fn registered_fd(mut self, registered_fd: RegisteredFd) -> Self {
220 self.fd = FdType::Registered(registered_fd);
221 self
222 }
223
224 /// Set a fixed file for this operation.
225 ///
226 /// Fixed files provide the best performance for frequently used files
227 /// by avoiding both file descriptor lookups and translation overhead.
228 /// The file must be pre-registered with the registry.
229 ///
230 /// # Arguments
231 ///
232 /// * `fixed_file` - A fixed file from the registry
233 ///
234 /// # Example
235 ///
236 /// ```rust,no_run
237 /// # use safer_ring::{operation::Operation, Registry};
238 /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
239 /// let mut registry = Registry::new();
240 /// let fixed_files = registry.register_fixed_files(vec![0, 1])?;
241 /// let op = Operation::read().fixed_file(fixed_files[0].clone());
242 /// # Ok(())
243 /// # }
244 /// ```
245 #[inline]
246 pub fn fixed_file(mut self, fixed_file: crate::registry::FixedFile) -> Self {
247 self.fd = FdType::Fixed(fixed_file);
248 self
249 }
250
251 /// Set the buffer for this operation.
252 ///
253 /// The buffer lifetime must be at least as long as the ring lifetime
254 /// to ensure memory safety during the operation. The buffer must remain
255 /// pinned in memory until the operation completes.
256 ///
257 /// # Arguments
258 ///
259 /// * `buffer` - A pinned mutable slice that will be used for I/O
260 ///
261 /// # Example
262 ///
263 /// ```rust,no_run
264 /// # use safer_ring::operation::Operation;
265 /// # use std::pin::Pin;
266 /// let mut data = vec![0u8; 4096];
267 /// let op = Operation::read()
268 /// .fd(0)
269 /// .buffer(Pin::new(data.as_mut_slice()));
270 /// ```
271 #[inline]
272 pub fn buffer(mut self, buffer: Pin<&'buf mut [u8]>) -> Self {
273 self.buffer = BufferType::Pinned(buffer);
274 self
275 }
276
277 /// Set a registered buffer for this operation.
278 ///
279 /// Using registered buffers can improve performance by avoiding kernel
280 /// buffer validation and setup overhead.
281 ///
282 /// # Arguments
283 ///
284 /// * `registered_buffer` - A registered buffer
285 ///
286 /// # Example
287 ///
288 /// ```rust,no_run
289 /// # use safer_ring::{operation::Operation, Registry};
290 /// # use std::pin::Pin;
291 /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
292 /// let mut registry = Registry::new();
293 /// let buffer = Pin::new(Box::new([0u8; 1024]));
294 /// let registered_buffer = registry.register_buffer(buffer)?;
295 /// let op = Operation::read()
296 /// .fd(0)
297 /// .registered_buffer(registered_buffer);
298 /// # Ok(())
299 /// # }
300 /// ```
301 #[inline]
302 pub fn registered_buffer(mut self, registered_buffer: RegisteredBuffer) -> Self {
303 self.buffer = BufferType::Registered(registered_buffer);
304 self
305 }
306
307 /// Set multiple buffers for vectored I/O operations.
308 ///
309 /// This enables scatter-gather I/O where data can be read into or written
310 /// from multiple non-contiguous buffers in a single operation.
311 ///
312 /// # Arguments
313 ///
314 /// * `buffers` - A vector of pinned mutable slices
315 ///
316 /// # Example
317 ///
318 /// ```rust,no_run
319 /// # use safer_ring::operation::Operation;
320 /// # use std::pin::Pin;
321 /// let mut buffer1 = vec![0u8; 512];
322 /// let mut buffer2 = vec![0u8; 512];
323 /// let buffers = vec![
324 /// Pin::new(buffer1.as_mut_slice()),
325 /// Pin::new(buffer2.as_mut_slice()),
326 /// ];
327 /// let op = Operation::read_vectored()
328 /// .fd(0)
329 /// .buffers(buffers);
330 /// ```
331 #[inline]
332 pub fn buffers(mut self, buffers: Vec<Pin<&'buf mut [u8]>>) -> Self {
333 self.buffer = BufferType::Vectored(buffers);
334 self
335 }
336
337 /// Set the offset for this operation.
338 ///
339 /// This is used for file operations to specify the position in the file.
340 /// For socket operations, this parameter is typically ignored by the kernel.
341 ///
342 /// # Arguments
343 ///
344 /// * `offset` - Byte offset in the file (0-based)
345 ///
346 /// # Example
347 ///
348 /// ```rust,no_run
349 /// # use safer_ring::operation::Operation;
350 /// let op = Operation::read()
351 /// .fd(3)
352 /// .offset(1024); // Read starting at byte 1024
353 /// ```
354 #[inline]
355 pub fn offset(mut self, offset: u64) -> Self {
356 self.offset = offset;
357 self
358 }
359
360 /// Get the current offset.
361 ///
362 /// Returns the byte offset for file operations, or 0 if not set.
363 #[inline]
364 pub fn get_offset(&self) -> u64 {
365 self.offset
366 }
367
368 /// Validate that the operation is ready for submission.
369 ///
370 /// This checks that all required fields are set for the operation type.
371 /// Using the type system's knowledge about operation requirements for
372 /// more efficient validation.
373 ///
374 /// # Errors
375 ///
376 /// Returns an error if:
377 /// - File descriptor is not set (< 0)
378 /// - Buffer is required but not set
379 /// - Vectored operation has empty buffer list
380 ///
381 /// # Example
382 ///
383 /// ```rust,no_run
384 /// # use safer_ring::operation::Operation;
385 /// let op = Operation::read().fd(0);
386 /// assert!(op.validate().is_err()); // Missing buffer
387 /// ```
388 pub fn validate(&self) -> Result<(), &'static str> {
389 // Check file descriptor
390 match &self.fd {
391 FdType::Raw(fd) if *fd < 0 => return Err("File descriptor must be set"),
392 _ => {}
393 }
394
395 // Use the type system's knowledge about buffer requirements
396 if self.op_type.requires_buffer() {
397 match &self.buffer {
398 BufferType::None => return Err("Buffer must be set for I/O operations"),
399 BufferType::Vectored(buffers) if buffers.is_empty() => {
400 return Err("Vectored operations require at least one buffer")
401 }
402 _ => {}
403 }
404 }
405
406 // Validate operation type matches buffer type
407 if self.op_type.is_vectored() && !matches!(self.buffer, BufferType::Vectored(_)) {
408 return Err("Vectored operation types require vectored buffers");
409 }
410
411 if !self.op_type.is_vectored() && matches!(self.buffer, BufferType::Vectored(_)) {
412 return Err("Non-vectored operation types cannot use vectored buffers");
413 }
414
415 Ok(())
416 }
417
418 /// Convert this building operation to a submitted operation.
419 ///
420 /// This is typically called by the Ring when submitting the operation.
421 /// It validates the operation and transitions to the Submitted state.
422 ///
423 /// # Arguments
424 ///
425 /// * `id` - Unique operation ID assigned by the ring
426 ///
427 /// # Errors
428 ///
429 /// Returns an error if the operation is not properly configured.
430 #[allow(dead_code)]
431 pub(crate) fn submit_with_id(
432 self,
433 id: u64,
434 ) -> Result<Operation<'ring, 'buf, Submitted>, &'static str> {
435 self.validate()?;
436
437 // Zero-cost state transition - just change the type parameter
438 Ok(Operation {
439 ring: self.ring,
440 buffer: self.buffer,
441 fd: self.fd,
442 offset: self.offset,
443 op_type: self.op_type,
444 state: Submitted { id },
445 })
446 }
447}