dope_core/io/socket/msg/
raw.rs1use core::{mem, num::NonZero};
2
3use dope_sys::io::socket::{self, msg, msg::Header};
4use o3::{
5 buffer,
6 depot::array::{self, copy},
7};
8
9use crate::io::transfer;
10
11pub trait Iovec {
12 unsafe fn retain(self) -> msg::Iovec;
16}
17
18impl Iovec for &[u8] {
19 unsafe fn retain(self) -> msg::Iovec {
20 msg::Iovec::from_slice(self)
21 }
22}
23
24pub trait Vectored<'a, const N: usize = { super::MAX_IOVECS }> {
25 unsafe fn retain(self) -> super::Vectored<'a, N>;
29}
30
31impl<'a, const N: usize> Vectored<'a, N>
32 for (&'a mut Header, &'a copy::Vec<msg::Iovec, N>, transfer::Len)
33{
34 unsafe fn retain(self) -> super::Vectored<'a, N> {
35 const { assert!(N <= super::MAX_IOVECS) };
36 let (header, iovecs, bytes) = self;
37 super::Vectored::from_parts(header, iovecs.as_slice(), bytes)
38 }
39}
40
41impl<'a, const N: usize> Vectored<'a, N>
42 for (
43 &'a mut Header,
44 &'a [msg::Iovec; N],
45 array::Len<N>,
46 transfer::Len,
47 )
48{
49 unsafe fn retain(self) -> super::Vectored<'a, N> {
50 const { assert!(N <= super::MAX_IOVECS) };
51 let (header, iovecs, count, bytes) = self;
52 super::Vectored::from_parts(header, count.prefix(iovecs), bytes)
53 }
54}
55
56pub(super) trait Project<'a> {
57 fn slice(self) -> &'a [u8];
58}
59
60impl<'a> Project<'a> for &'a msg::Iovec {
61 fn slice(self) -> &'a [u8] {
62 unsafe { socket::raw::Iovec::as_slice(self) }
64 }
65}
66
67#[derive(Clone, Copy)]
69pub struct Cursor<'a> {
70 iovecs: &'a [msg::Iovec],
71 index: u32,
72 local: u32,
73 remaining: transfer::Len,
74}
75
76impl<'a> Cursor<'a> {
77 pub const fn bytes(&self) -> transfer::Len {
78 self.remaining
79 }
80
81 fn start<const N: usize>(source: &super::Vectored<'a, N>) -> Self {
82 Self {
83 iovecs: source.iovs,
84 index: 0,
85 local: 0,
86 remaining: source.bytes(),
87 }
88 }
89
90 fn new<const N: usize>(source: &super::Vectored<'a, N>, mut offset: usize) -> Option<Self> {
91 let len = source.bytes().into_raw();
92 if offset > len {
93 return None;
94 }
95 let left = transfer::Len::prefix(len - offset, source.bytes());
96 let iovecs: &'a [msg::Iovec] = source.iovs;
97 let mut index = 0;
98 let mut local = 0_usize;
99 while let Some(iovec) = iovecs.get(index as usize) {
100 if offset < iovec.len() {
101 local = offset;
102 break;
103 }
104 offset -= iovec.len();
105 index += 1;
106 }
107 Some(Self {
108 iovecs,
109 index,
110 local: local as u32,
111 remaining: left,
112 })
113 }
114}
115
116unsafe impl<'a: 'b, 'b> buffer::raw::Scatter<'b> for Cursor<'a> {
119 fn remaining(&self) -> usize {
120 self.remaining.into_raw()
121 }
122
123 unsafe fn advance<const MAX: usize>(
124 &mut self,
125 cap: NonZero<usize>,
126 _left: NonZero<usize>,
127 ) -> buffer::raw::Chunk<'b, MAX> {
128 loop {
129 let iovec = unsafe { self.iovecs.get_unchecked(self.index as usize) };
132 if iovec.len() == self.local as usize {
133 self.index += 1;
134 self.local = 0;
135 continue;
136 }
137 let bytes = unsafe { iovec.slice().get_unchecked(self.local as usize..) };
140 let len = bytes.len().min(cap.get());
141 self.local += len as u32;
142 let consumed = transfer::Len::prefix(len, self.remaining);
143 self.remaining = self.remaining.abs_diff(consumed);
144 if self.local as usize == iovec.len() {
145 self.index += 1;
146 self.local = 0;
147 }
148 return unsafe { buffer::raw::Chunk::new(&bytes[..len]) };
151 }
152 }
153}
154
155unsafe impl<'a, const N: usize> buffer::raw::Chunks for super::Vectored<'a, N> {
158 type Cursor<'data>
159 = Cursor<'a>
160 where
161 Self: 'data;
162
163 fn len(&self) -> usize {
164 self.bytes().into_raw()
165 }
166
167 fn start(&self) -> Self::Cursor<'_> {
168 Cursor::start(self)
169 }
170
171 fn cursor(&self, offset: usize) -> Option<Self::Cursor<'_>> {
172 Cursor::new(self, offset)
173 }
174}
175
176const _: () = {
177 let state = mem::size_of::<&[msg::Iovec]>() + 3 * mem::size_of::<u32>();
178 let align = mem::align_of::<Cursor<'_>>();
179 let exact = state.div_ceil(align) * align;
180 assert!(mem::size_of::<Cursor<'_>>() == exact);
181};