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
67impl<'a, const N: usize> super::Vectored<'a, N> {
68 pub fn contiguous(&self) -> Option<transfer::View<'a>> {
70 let [iovec] = self.iovs else {
71 return None;
72 };
73 let bytes = unsafe { buffer::bytes::bounded::raw::Input::new(iovec.slice()) };
75 Some(transfer::View::from_prefix(
76 buffer::bytes::Prefix::from_raw(bytes),
77 ))
78 }
79}
80
81#[derive(Clone, Copy)]
83pub struct Cursor<'a> {
84 iovecs: &'a [msg::Iovec],
85 index: u32,
86 local: u32,
87 remaining: transfer::Len,
88}
89
90impl<'a> Cursor<'a> {
91 pub const fn bytes(&self) -> transfer::Len {
92 self.remaining
93 }
94
95 fn start<const N: usize>(source: &super::Vectored<'a, N>) -> Self {
96 Self {
97 iovecs: source.iovs,
98 index: 0,
99 local: 0,
100 remaining: source.bytes(),
101 }
102 }
103
104 fn new<const N: usize>(source: &super::Vectored<'a, N>, mut offset: usize) -> Option<Self> {
105 let len = source.bytes().into_raw();
106 if offset > len {
107 return None;
108 }
109 let left = transfer::Len::prefix(len - offset, source.bytes());
110 let iovecs: &'a [msg::Iovec] = source.iovs;
111 let mut index = 0;
112 let mut local = 0_usize;
113 while let Some(iovec) = iovecs.get(index as usize) {
114 if offset < iovec.len() {
115 local = offset;
116 break;
117 }
118 offset -= iovec.len();
119 index += 1;
120 }
121 Some(Self {
122 iovecs,
123 index,
124 local: local as u32,
125 remaining: left,
126 })
127 }
128}
129
130unsafe impl<'a: 'b, 'b> buffer::raw::Scatter<'b> for Cursor<'a> {
133 fn remaining(&self) -> usize {
134 self.remaining.into_raw()
135 }
136
137 unsafe fn advance<const MAX: usize>(
138 &mut self,
139 cap: NonZero<usize>,
140 ) -> buffer::raw::Chunk<'b, MAX> {
141 loop {
142 let iovec = unsafe { self.iovecs.get_unchecked(self.index as usize) };
144 if iovec.len() == self.local as usize {
145 self.index += 1;
146 self.local = 0;
147 continue;
148 }
149 let bytes = unsafe { iovec.slice().get_unchecked(self.local as usize..) };
152 let len = bytes.len().min(cap.get());
153 self.local += len as u32;
154 let consumed = transfer::Len::prefix(len, self.remaining);
155 self.remaining = self.remaining.abs_diff(consumed);
156 if self.local as usize == iovec.len() {
157 self.index += 1;
158 self.local = 0;
159 }
160 return unsafe { buffer::raw::Chunk::new(&bytes[..len]) };
163 }
164 }
165}
166
167unsafe impl<'a, const N: usize> buffer::raw::Chunks for super::Vectored<'a, N> {
170 type Cursor<'data>
171 = Cursor<'a>
172 where
173 Self: 'data;
174
175 fn len(&self) -> usize {
176 self.bytes().into_raw()
177 }
178
179 fn chunks(&self) -> Self::Cursor<'_> {
180 Cursor::start(self)
181 }
182
183 fn cursor(&self, offset: usize) -> Option<Self::Cursor<'_>> {
184 Cursor::new(self, offset)
185 }
186}
187
188const _: () = {
189 let state = mem::size_of::<&[msg::Iovec]>() + 3 * mem::size_of::<u32>();
190 let align = mem::align_of::<Cursor<'_>>();
191 let exact = state.div_ceil(align) * align;
192 assert!(mem::size_of::<Cursor<'_>>() == exact);
193};