1use alloc::format;
7use alloc::string::ToString;
8
9use crate::error::{ProtocolError, Result};
10use crate::header::MessageHeader;
11use crate::magic::HEADER_SIZE;
12use crate::request::Request;
13use crate::shm::ShmView;
14use crate::types::{Priority, RequestId, TraceId};
15
16#[derive(Debug, Clone)]
17pub struct ZeroCopyRequest<'a> {
18 pub header: MessageHeader,
19 pub module_name: &'a str,
20 pub method_name: &'a str,
21 pub args: &'a [u8],
22 pub trace_id: TraceId,
23 pub deadline_ns: Option<u64>,
24}
25
26impl<'a> ZeroCopyRequest<'a> {
27 pub fn parse(shm: &'a ShmView<'a>) -> Result<Self> {
28 let header = shm.read_header()?;
29
30 let mut offset = HEADER_SIZE;
31 let data = shm.as_slice();
32
33 if offset + 4 > data.len() {
34 return Err(ProtocolError::InvalidHeader(
35 "insufficient data for module_name length".to_string(),
36 ));
37 }
38 let module_len =
39 u32::from_le_bytes([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]])
40 as usize;
41 offset += 4;
42
43 if offset + module_len > data.len() {
44 return Err(ProtocolError::InvalidHeader(
45 "insufficient data for module_name".to_string(),
46 ));
47 }
48 let module_bytes = &data[offset..offset + module_len];
49 let module_name = core::str::from_utf8(module_bytes).map_err(|_| {
50 ProtocolError::InvalidHeader("module_name is not valid UTF-8".to_string())
51 })?;
52 offset += module_len;
53
54 if offset + 4 > data.len() {
55 return Err(ProtocolError::InvalidHeader(
56 "insufficient data for method_name length".to_string(),
57 ));
58 }
59 let method_len =
60 u32::from_le_bytes([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]])
61 as usize;
62 offset += 4;
63
64 if offset + method_len > data.len() {
65 return Err(ProtocolError::InvalidHeader(
66 "insufficient data for method_name".to_string(),
67 ));
68 }
69 let method_bytes = &data[offset..offset + method_len];
70 let method_name = core::str::from_utf8(method_bytes).map_err(|_| {
71 ProtocolError::InvalidHeader("method_name is not valid UTF-8".to_string())
72 })?;
73 offset += method_len;
74
75 if offset + 4 > data.len() {
76 return Err(ProtocolError::InvalidHeader(
77 "insufficient data for args length".to_string(),
78 ));
79 }
80 let args_len =
81 u32::from_le_bytes([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]])
82 as usize;
83 offset += 4;
84
85 if offset + args_len > data.len() {
86 return Err(ProtocolError::InvalidHeader(
87 "insufficient data for args".to_string(),
88 ));
89 }
90 let args = &data[offset..offset + args_len];
91 offset += args_len;
92
93 if offset + 16 > data.len() {
94 return Err(ProtocolError::InvalidHeader(
95 "insufficient data for trace_id".to_string(),
96 ));
97 }
98 let trace_id = u128::from_le_bytes([
99 data[offset],
100 data[offset + 1],
101 data[offset + 2],
102 data[offset + 3],
103 data[offset + 4],
104 data[offset + 5],
105 data[offset + 6],
106 data[offset + 7],
107 data[offset + 8],
108 data[offset + 9],
109 data[offset + 10],
110 data[offset + 11],
111 data[offset + 12],
112 data[offset + 13],
113 data[offset + 14],
114 data[offset + 15],
115 ]);
116 offset += 16;
117
118 if offset + 8 > data.len() {
119 return Err(ProtocolError::InvalidHeader(
120 "insufficient data for deadline_ns".to_string(),
121 ));
122 }
123 let deadline = u64::from_le_bytes([
124 data[offset],
125 data[offset + 1],
126 data[offset + 2],
127 data[offset + 3],
128 data[offset + 4],
129 data[offset + 5],
130 data[offset + 6],
131 data[offset + 7],
132 ]);
133 let deadline_ns = if deadline == 0 { None } else { Some(deadline) };
134
135 Ok(Self {
136 header,
137 module_name,
138 method_name,
139 args,
140 trace_id,
141 deadline_ns,
142 })
143 }
144
145 pub fn to_owned(&self) -> Request {
146 use crate::request::Request;
147
148 let mut req = Request::new(
149 self.header.request_id(),
150 Priority::Normal,
151 self.module_name,
152 self.method_name,
153 self.args.to_vec(),
154 )
155 .with_trace_id(self.trace_id);
156
157 if let Some(deadline) = self.deadline_ns {
158 req = req.with_deadline_ns(Some(deadline));
159 }
160
161 req
162 }
163
164 pub fn request_id(&self) -> RequestId {
165 self.header.request_id()
166 }
167
168 pub fn priority(&self) -> Priority {
169 Priority::Normal
170 }
171
172 pub fn serialized_size(&self) -> usize {
173 HEADER_SIZE +
174 4 + self.module_name.len() +
175 4 + self.method_name.len() +
176 4 + self.args.len() +
177 16 +
178 8
179 }
180}
181
182#[derive(Debug, Clone)]
183pub struct ZeroCopyResponse<'a> {
184 pub header: MessageHeader,
185 pub data: &'a [u8],
186 pub status: crate::types::StatusCode,
187}
188
189impl<'a> ZeroCopyResponse<'a> {
190 pub fn parse(shm: &'a ShmView<'a>) -> Result<Self> {
191 let header = shm.read_header()?;
192
193 let data = shm.as_slice();
194 let mut offset = HEADER_SIZE;
195
196 if offset >= data.len() {
197 return Err(ProtocolError::InvalidHeader(
198 "insufficient data for status code".to_string(),
199 ));
200 }
201 let status_code = data[offset];
202 let status = crate::types::StatusCode::from_u8(status_code).ok_or_else(|| {
203 ProtocolError::InvalidHeader(format!("unknown status code: {}", status_code))
204 })?;
205 offset += 1;
206
207 if offset + 4 > data.len() {
208 return Err(ProtocolError::InvalidHeader(
209 "insufficient data for data length".to_string(),
210 ));
211 }
212 let data_len =
213 u32::from_le_bytes([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]])
214 as usize;
215 offset += 4;
216
217 if offset + data_len > data.len() {
218 return Err(ProtocolError::InvalidHeader(
219 "insufficient data for data".to_string(),
220 ));
221 }
222 let data = &data[offset..offset + data_len];
223
224 Ok(Self {
225 header,
226 data,
227 status,
228 })
229 }
230
231 pub fn to_owned(&self) -> crate::response::Response {
232 use crate::response::Response;
233
234 Response::with_routing(
235 self.header.request_id(),
236 self.status,
237 self.data.to_vec(),
238 self.header.module_id(),
239 self.header.method_hash(),
240 )
241 }
242}