1use super::*;
4
5pub const WS: &[char] = &[' ', '\t'];
8
9define_derive_deftly! {
10 ParseOptions beta_deftly, expect items:
19
20 impl<$tgens> $ttype {
21 pub fn parse_options(&self) -> &'s ParseOptions {
23 &self
24 ${tmeta(parse_options(field))
25 as token_stream,
26 default { .options }}
27 }
28 }
29}
30
31#[derive(Debug, Clone, Deftly)]
33#[derive_deftly(ParseOptions)]
34pub struct ItemStream<'s> {
35 whole_input: &'s str,
37 lines: Lines<'s>,
39 peeked: PeekState<'s>,
41 options: &'s ParseOptions,
43}
44
45#[derive(Debug, Clone)]
47enum PeekState<'s> {
48 Some(ItemStreamPeeked<'s>),
50 None {
52 yielded_item_lno: usize,
56 },
57}
58
59#[derive(Debug, Clone)]
61struct ItemStreamPeeked<'s> {
62 keyword: KeywordRef<'s>,
64 line: lines::Peeked,
66 args_len: usize,
70}
71
72#[derive(Debug, Clone, amplify::Getters, Deftly)]
74#[derive_deftly(ParseOptions)]
75#[deftly(parse_options(field = ".args.options"))]
76pub struct UnparsedItem<'s> {
77 #[getter(as_copy)]
79 keyword: KeywordRef<'s>,
80 #[getter(skip)]
82 args: ArgumentStream<'s>,
83 #[getter(as_clone)]
85 object: Option<UnparsedObject<'s>>,
86}
87
88#[derive(Debug, Clone, Deftly)]
92#[derive_deftly(ParseOptions)]
93pub struct ArgumentStream<'s> {
94 rest: &'s str,
98
99 whole_line_len: usize,
103
104 previous_rest_len: usize,
106
107 options: &'s ParseOptions,
109}
110
111#[derive(Debug, Clone, amplify::Getters, Deftly)]
113#[derive_deftly(ParseOptions)]
114pub struct UnparsedObject<'s> {
115 #[getter(as_copy)]
117 label: &'s str,
118
119 #[getter(skip)]
121 data_b64: &'s str,
122
123 options: &'s ParseOptions,
125}
126
127impl<'s> ItemStream<'s> {
128 pub fn new(input: &'s ParseInput<'s>) -> Result<Self, ParseError> {
130 Ok(ItemStream {
131 whole_input: input.input,
132 lines: Lines::new(input.input),
133 peeked: PeekState::None {
134 yielded_item_lno: 0,
135 },
136 options: &input.options,
137 })
138 }
139
140 pub fn lno_for_error(&self) -> usize {
146 match self.peeked {
147 PeekState::Some { .. } => {
148 self.lines.peek_lno()
151 }
152 PeekState::None { yielded_item_lno } => {
153 yielded_item_lno
155 }
156 }
157 }
158
159 fn peek_internal<'i>(&'i mut self) -> Result<(), EP> {
161 if matches!(self.peeked, PeekState::None { .. }) {
162 let Some(peeked) = self.lines.peek() else {
163 return Ok(());
164 };
165
166 let peeked_line = self.lines.peeked_line(&peeked);
167
168 let (keyword, args) = peeked_line.split_once(WS).unwrap_or((peeked_line, ""));
169 let keyword = KeywordRef::new(keyword)?;
170
171 self.peeked = PeekState::Some(ItemStreamPeeked {
172 keyword,
173 line: peeked,
174 args_len: args.len(),
175 });
176 }
177
178 Ok(())
179 }
180
181 pub fn peek_keyword(&mut self) -> Result<Option<KeywordRef<'s>>, EP> {
183 self.peek_internal()?;
184 let PeekState::Some(peeked) = &self.peeked else {
185 return Ok(None);
186 };
187 Ok(Some(peeked.keyword))
188 }
189
190 pub fn body_sofar_for_signature(&self) -> SignedDocumentBody<'s> {
192 let body = &self.whole_input[0..self.byte_position()];
193 SignedDocumentBody { body }
194 }
195
196 pub fn byte_position(&self) -> usize {
202 self.whole_input.len() - self.lines.remaining().len()
203 }
204
205 pub fn whole_input(&self) -> &'s str {
211 self.whole_input
212 }
213
214 pub fn parse_signed<
226 B: HasUnverifiedParsedBody,
227 S: NetdocParseableSignatures,
228 O: NetdocUnverified<Body = B, Signatures = S>,
229 >(
230 &mut self,
231 outer_stop: stop_at!(),
232 ) -> Result<O, EP> {
233 let mut input = ItemStream {
234 whole_input: &self.whole_input[self.whole_input.len() - self.lines.remaining().len()..],
235 ..self.clone()
236 };
237 let r = (|| {
238 let inner_always_stop = outer_stop | StopAt::doc_intro::<B::UnverifiedParsedBody>();
239 let body = B::UnverifiedParsedBody::from_items(
240 &mut input,
241 inner_always_stop | StopAt(S::is_item_keyword),
242 )?;
243 let signed_doc_body = input.body_sofar_for_signature();
244 let unsigned_body_len = signed_doc_body.body().len();
245 let mut hashes = S::HashesAccu::default();
246 let sigs = S::from_items(&mut input, signed_doc_body, &mut hashes, inner_always_stop)?;
247 let sigs = SignaturesData {
248 sigs,
249 unsigned_body_len,
250 hashes,
251 };
252 let signed = O::from_parts(B::unverified_into_inner_unchecked(body), sigs);
257 Ok(signed)
258 })(); *self = ItemStream {
261 whole_input: self.whole_input,
262 ..input
263 };
264
265 r
266 }
267
268 pub fn peek_signature_hash_inputs(
273 &mut self,
274 body: SignedDocumentBody<'s>,
275 ) -> Result<Option<SignatureHashInputs<'s>>, EP> {
276 self.peek_internal()?;
277 let PeekState::Some(peeked) = &self.peeked else {
278 return Ok(None);
279 };
280 let document_sofar = self.body_sofar_for_signature().body();
281 let signature_item_line = self.lines.peeked_line(&peeked.line);
282 let signature_item_kw_spc = signature_item_line.strip_end_counted(peeked.args_len);
283 Ok(Some(SignatureHashInputs {
284 body,
285 document_sofar,
286 signature_item_kw_spc,
287 signature_item_line,
288 }))
289 }
290
291 pub fn next_item(&mut self) -> Result<Option<UnparsedItem<'s>>, EP> {
293 self.peek_internal()?;
294 let peeked = match self.peeked {
295 PeekState::None { .. } => return Ok(None),
296 PeekState::Some { .. } => match mem::replace(
297 &mut self.peeked,
298 PeekState::None {
299 yielded_item_lno: self.lines.peek_lno(),
300 },
301 ) {
302 PeekState::Some(peeked) => peeked,
303 PeekState::None { .. } => panic!("it was Some just now"),
304 },
305 };
306
307 let keyword = peeked.keyword;
308 let line = self.lines.consume_peeked(peeked.line);
309 let args = &line[keyword.len()..];
310 let options = self.options;
311 let args = ArgumentStream::new(args, line.len(), options);
312
313 let object = if self.lines.remaining().starts_with('-') {
314 fn pem_delimiter<'s>(lines: &mut Lines<'s>, start: &str) -> Result<&'s str, EP> {
315 let line = lines.next().ok_or(
316 EP::ObjectMissingFooter,
319 )?;
320 let label = line
321 .strip_prefix(start)
322 .ok_or(EP::InvalidObjectDelimiters)?
323 .strip_suffix(PEM_AFTER_LABEL)
324 .ok_or(EP::InvalidObjectDelimiters)?;
325 Ok(label)
326 }
327
328 let label1 = pem_delimiter(&mut self.lines, PEM_HEADER_START)?;
329 let base64_start_remaining = self.lines.remaining();
330 while !self.lines.remaining().starts_with('-') {
331 let _: &str = self.lines.next().ok_or(EP::ObjectMissingFooter)?;
332 }
333 let data_b64 = base64_start_remaining.strip_end_counted(self.lines.remaining().len());
334 let label2 = pem_delimiter(&mut self.lines, PEM_FOOTER_START)?;
335 let label = [label1, label2]
336 .into_iter()
337 .all_equal_value()
338 .map_err(|_| EP::ObjectMismatchedLabels)?;
339 Some(UnparsedObject {
340 label,
341 data_b64,
342 options,
343 })
344 } else {
345 None
346 };
347
348 Ok(Some(UnparsedItem {
349 keyword,
350 args,
351 object,
352 }))
353 }
354}
355
356impl<'s> UnparsedItem<'s> {
357 pub fn args_mut(&mut self) -> &mut ArgumentStream<'s> {
359 &mut self.args
360 }
361 pub fn args_copy(&self) -> ArgumentStream<'s> {
365 self.args.clone()
366 }
367
368 pub fn args(&self) -> &ArgumentStream<'s> {
372 &self.args
373 }
374
375 pub fn check_no_object(&self) -> Result<(), EP> {
377 if self.object.is_some() {
378 return Err(EP::ObjectUnexpected);
379 }
380 Ok(())
381 }
382 pub fn invalid_argument_handler<E>(
390 &self,
391 field: &'static str,
392 ) -> impl FnOnce(E) -> ErrorProblem {
393 let error = self.args().handle_error(field, AE::Invalid);
394 move |_any_error| error
395 }
396}
397
398#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
402#[allow(clippy::exhaustive_structs)]
403pub struct NoFurtherArguments;
404
405impl ItemArgumentParseable for NoFurtherArguments {
406 fn from_args(args: &mut ArgumentStream) -> Result<Self, AE> {
407 Ok(args.reject_extra_args()?)
408 }
409}
410
411impl<'s> Iterator for ItemStream<'s> {
412 type Item = Result<UnparsedItem<'s>, EP>;
413 fn next(&mut self) -> Option<Result<UnparsedItem<'s>, EP>> {
414 self.next_item().transpose()
415 }
416}
417
418impl<'s> ArgumentStream<'s> {
419 pub fn new(rest: &'s str, whole_line_len: usize, options: &'s ParseOptions) -> Self {
423 let previous_rest_len = whole_line_len;
424 ArgumentStream {
425 rest,
426 whole_line_len,
427 previous_rest_len,
428 options,
429 }
430 }
431
432 pub fn into_remaining(&mut self) -> &'s str {
439 self.prep_yield();
440 mem::take(&mut self.rest)
441 }
442
443 pub fn whole_line_len(&self) -> usize {
447 self.whole_line_len
448 }
449
450 fn prep_yield(&mut self) {
455 self.rest = self.rest.trim_start_matches(WS);
456 self.previous_rest_len = self.rest.len();
457 }
458
459 pub fn something_to_yield(&mut self) -> bool {
465 self.prep_yield();
466 !self.rest.is_empty()
467 }
468
469 pub fn reject_extra_args(&mut self) -> Result<NoFurtherArguments, UnexpectedArgument> {
473 if self.something_to_yield() {
474 let column = self.next_arg_column();
475 Err(UnexpectedArgument { column })
476 } else {
477 Ok(NoFurtherArguments)
478 }
479 }
480
481 fn arg_column_from_rest_len(&self, rest_len: usize) -> usize {
483 self.whole_line_len - rest_len + 1
486 }
487
488 pub fn prev_arg_column(&self) -> usize {
493 self.arg_column_from_rest_len(self.previous_rest_len)
494 }
495
496 fn next_arg_column(&self) -> usize {
503 self.arg_column_from_rest_len(self.rest.len())
504 }
505
506 pub fn handle_error(&self, field: &'static str, ae: ArgumentError) -> ErrorProblem {
510 self.error_handler(field)(ae)
511 }
512
513 pub fn error_handler(
517 &self,
518 field: &'static str,
519 ) -> impl Fn(ArgumentError) -> ErrorProblem + 'static {
520 let column = self.prev_arg_column();
521 move |ae| match ae {
522 AE::Missing => EP::MissingArgument { field },
523 AE::Invalid => EP::InvalidArgument { field, column },
524 AE::Unexpected => EP::UnexpectedArgument { column },
525 }
526 }
527}
528
529impl<'s> Iterator for ArgumentStream<'s> {
530 type Item = &'s str;
531 fn next(&mut self) -> Option<&'s str> {
532 if !self.something_to_yield() {
533 return None;
534 }
535 let arg;
536 (arg, self.rest) = self.rest.split_once(WS).unwrap_or((self.rest, ""));
537 Some(arg)
538 }
539}
540
541impl<'s> UnparsedObject<'s> {
542 pub fn decode_data(&self) -> Result<Vec<u8>, EP> {
544 crate::parse::tokenize::base64_decode_multiline(self.data_b64)
545 .map_err(|_e| EP::ObjectInvalidBase64)
546 }
547}