1use core::fmt::{self, Write as _};
4use core::marker::PhantomData;
5use core::mem;
6use core::ops::ControlFlow;
7
8#[cfg(feature = "alloc")]
9use alloc::string::{String, ToString};
10
11use crate::parser::str::{find_split, find_split_hole};
12use crate::parser::str::{process_percent_encoded_best_effort, PctEncodedFragments};
13use crate::percent_encode::PercentEncoded;
14use crate::spec::Spec;
15use crate::template::components::{ExprBody, Modifier, Operator, VarName, VarSpec};
16use crate::template::context::{
17 private::Sealed as VisitorSealed, AssocVisitor, Context, DynamicContext, ListVisitor,
18 VisitPurpose, Visitor,
19};
20use crate::template::error::{Error, ErrorKind};
21use crate::template::{UriTemplateStr, ValueType};
22#[cfg(feature = "alloc")]
23use crate::types;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub(super) enum Chunk<'a> {
28 Literal(&'a str),
30 Expr(ExprBody<'a>),
32}
33
34#[derive(Debug, Clone)]
36pub(super) struct Chunks<'a> {
37 template: &'a str,
39}
40
41impl<'a> Chunks<'a> {
42 #[inline]
44 #[must_use]
45 pub(super) fn new(template: &'a UriTemplateStr) -> Self {
46 Self {
47 template: template.as_str(),
48 }
49 }
50}
51
52impl<'a> Iterator for Chunks<'a> {
53 type Item = Chunk<'a>;
54
55 fn next(&mut self) -> Option<Self::Item> {
56 if self.template.is_empty() {
57 return None;
58 }
59 match find_split(self.template, b'{') {
60 Some(("", _)) => {
61 let (expr_body, rest) = find_split_hole(&self.template[1..], b'}')
62 .expect("expression inside a template must be closed");
63 self.template = rest;
64 Some(Chunk::Expr(ExprBody::new(expr_body)))
65 }
66 Some((lit, rest)) => {
67 self.template = rest;
68 Some(Chunk::Literal(lit))
69 }
70 None => Some(Chunk::Literal(mem::take(&mut self.template))),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Copy)]
77pub struct Expanded<'a, S, C> {
78 template: &'a UriTemplateStr,
80 context: &'a C,
82 _spec: PhantomData<fn() -> S>,
84}
85
86impl<'a, S: Spec, C: Context> Expanded<'a, S, C> {
87 #[inline]
89 pub(super) fn new(template: &'a UriTemplateStr, context: &'a C) -> Result<Self, Error> {
90 Self::typecheck_context(template, context)?;
91 Ok(Self {
92 template,
93 context,
94 _spec: PhantomData,
95 })
96 }
97
98 fn typecheck_context(template: &UriTemplateStr, context: &C) -> Result<(), Error> {
100 let mut pos = 0;
101 for chunk in Chunks::new(template) {
102 let (expr_len, (op, varlist)) = match chunk {
103 Chunk::Expr(expr_body) => (expr_body.as_str().len(), expr_body.decompose()),
104 Chunk::Literal(lit) => {
105 pos += lit.len();
106 continue;
107 }
108 };
109 let chunk_end_pos = pos + expr_len + 2;
111 pos += op.len() + 1;
113 for (varspec_len, varspec) in varlist {
114 let ty = context.visit(TypeVisitor::new(varspec.name()));
115 let modifier = varspec.modifier();
116
117 if matches!(modifier, Modifier::MaxLen(_))
118 && matches!(ty, ValueType::List | ValueType::Assoc)
119 {
120 return Err(Error::new(ErrorKind::UnexpectedValueType, pos));
125 }
126
127 pos += varspec_len + 1;
129 }
130 assert_eq!(pos, chunk_end_pos);
131 }
132 Ok(())
133 }
134}
135
136impl<S: Spec, C: Context> fmt::Display for Expanded<'_, S, C> {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 for chunk in Chunks::new(self.template) {
139 let expr = match chunk {
140 Chunk::Literal(lit) => {
141 f.write_str(lit)?;
142 continue;
143 }
144 Chunk::Expr(body) => body,
145 };
146 expand::<S, _>(f, expr, self.context)?;
147 }
148
149 Ok(())
150 }
151}
152
153macro_rules! impl_try_from_expanded {
155 ($ty_outer:ident) => {
156 #[cfg(feature = "alloc")]
157 impl<S: Spec, C: Context> TryFrom<Expanded<'_, S, C>> for types::$ty_outer<S> {
158 type Error = types::CreationError<String>;
159
160 #[inline]
161 fn try_from(v: Expanded<'_, S, C>) -> Result<Self, Self::Error> {
162 Self::try_from(v.to_string())
163 }
164 }
165 };
166}
167
168impl_try_from_expanded!(RiAbsoluteString);
181impl_try_from_expanded!(RiReferenceString);
182impl_try_from_expanded!(RiRelativeString);
183impl_try_from_expanded!(RiString);
184
185pub(super) fn expand_whole_dynamic<S: Spec, W: fmt::Write, C: DynamicContext>(
187 template: &UriTemplateStr,
188 writer: &mut W,
189 context: &mut C,
190) -> Result<(), Error> {
191 context.on_expansion_start();
192 let result = expand_whole_dynamic_impl::<S, W, C>(template, writer, context);
193 context.on_expansion_end();
194 result
195}
196
197fn expand_whole_dynamic_impl<S: Spec, W: fmt::Write, C: DynamicContext>(
201 template: &UriTemplateStr,
202 writer: &mut W,
203 context: &mut C,
204) -> Result<(), Error> {
205 let mut pos = 0;
206 for chunk in Chunks::new(template) {
207 let expr = match chunk {
208 Chunk::Literal(lit) => {
209 writer
210 .write_str(lit)
211 .map_err(|_| Error::new(ErrorKind::WriteFailed, pos))?;
212 pos += lit.len();
213 continue;
214 }
215 Chunk::Expr(body) => body,
216 };
217 expand_expr_mut::<S, _, _>(writer, &mut pos, expr, context)?;
218 }
219
220 Ok(())
221}
222
223fn expand_expr_mut<S: Spec, W: fmt::Write, C: DynamicContext>(
225 writer: &mut W,
226 pos: &mut usize,
227 expr: ExprBody<'_>,
228 context: &mut C,
229) -> Result<(), Error> {
230 let (op, varlist) = expr.decompose();
231
232 let mut is_first_varspec = true;
233 let chunk_end_pos = *pos + expr.as_str().len() + 2;
235 *pos += op.len() + 1;
237 for (varspec_len, varspec) in varlist {
238 let ty = context.visit_dynamic(TypeVisitor::new(varspec.name()));
240 let modifier = varspec.modifier();
241
242 if matches!(modifier, Modifier::MaxLen(_))
243 && matches!(ty, ValueType::List | ValueType::Assoc)
244 {
245 return Err(Error::new(ErrorKind::UnexpectedValueType, *pos));
250 }
251
252 let visitor = ValueVisitor::<S, _>::new(writer, varspec, op, &mut is_first_varspec);
254 let token = context
255 .visit_dynamic(visitor)
256 .map_err(|_| Error::new(ErrorKind::WriteFailed, *pos))?;
257 let writer_ptr = token.writer_ptr();
258 if !core::ptr::eq(writer_ptr, writer) {
259 panic!("invalid `VisitDoneToken` was returned");
262 }
263
264 *pos += varspec_len + 1;
266 }
267 assert_eq!(*pos, chunk_end_pos);
268
269 Ok(())
270}
271
272#[derive(Debug, Clone, Copy)]
276struct OpProps {
277 first: &'static str,
279 sep: &'static str,
281 named: bool,
283 ifemp: &'static str,
285 allow_reserved: bool,
287}
288
289impl OpProps {
290 const PROPS: [Self; 8] = [
292 Self {
294 first: "",
295 sep: ",",
296 named: false,
297 ifemp: "",
298 allow_reserved: false,
299 },
300 Self {
302 first: "",
303 sep: ",",
304 named: false,
305 ifemp: "",
306 allow_reserved: true,
307 },
308 Self {
310 first: "#",
311 sep: ",",
312 named: false,
313 ifemp: "",
314 allow_reserved: true,
315 },
316 Self {
318 first: ".",
319 sep: ".",
320 named: false,
321 ifemp: "",
322 allow_reserved: false,
323 },
324 Self {
326 first: "/",
327 sep: "/",
328 named: false,
329 ifemp: "",
330 allow_reserved: false,
331 },
332 Self {
334 first: ";",
335 sep: ";",
336 named: true,
337 ifemp: "",
338 allow_reserved: false,
339 },
340 Self {
342 first: "?",
343 sep: "&",
344 named: true,
345 ifemp: "=",
346 allow_reserved: false,
347 },
348 Self {
350 first: "&",
351 sep: "&",
352 named: true,
353 ifemp: "=",
354 allow_reserved: false,
355 },
356 ];
357
358 #[must_use]
360 #[inline]
361 pub(super) fn from_op(op: Operator) -> &'static Self {
362 let index = match op {
363 Operator::String => 0,
364 Operator::Reserved => 1,
365 Operator::Fragment => 2,
366 Operator::Label => 3,
367 Operator::PathSegments => 4,
368 Operator::PathParams => 5,
369 Operator::FormQuery => 6,
370 Operator::FormQueryCont => 7,
371 };
372 &Self::PROPS[index]
373 }
374}
375
376fn expand<S: Spec, C: Context>(
378 f: &mut fmt::Formatter<'_>,
379 expr: ExprBody<'_>,
380 context: &C,
381) -> fmt::Result {
382 let (op, varlist) = expr.decompose();
383
384 let mut is_first_varspec = true;
385 for (_varspec_len, varspec) in varlist {
386 let visitor = ValueVisitor::<S, _>::new(f, varspec, op, &mut is_first_varspec);
387 let token = context.visit(visitor)?;
388 let writer_ptr = token.writer_ptr();
389 if !core::ptr::eq(writer_ptr, f) {
390 panic!("invalid `VisitDoneToken` was returned");
393 }
394 }
395
396 Ok(())
397}
398
399#[inline]
401fn escape_write<S: Spec, T: fmt::Display, W: fmt::Write>(
402 f: &mut W,
403 v: T,
404 allow_reserved: bool,
405) -> fmt::Result {
406 if allow_reserved {
407 let result = process_percent_encoded_best_effort(v, |frag| {
408 let result = match frag {
409 PctEncodedFragments::Char(s, _) => f.write_str(s),
410 PctEncodedFragments::NoPctStr(s) => {
411 write!(f, "{}", PercentEncoded::<_, S>::characters(s))
412 }
413 PctEncodedFragments::StrayPercent => f.write_str("%25"),
414 PctEncodedFragments::InvalidUtf8PctTriplets(s) => f.write_str(s),
415 };
416 if result.is_err() {
417 return ControlFlow::Break(result);
418 }
419 ControlFlow::Continue(())
420 });
421 match result {
422 Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
423 Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
424 }
425 } else {
426 struct UnreservePercentEncodeWriter<'a, S, W> {
428 writer: &'a mut W,
430 _spec: PhantomData<fn() -> S>,
432 }
433 impl<S: Spec, W: fmt::Write> fmt::Write for UnreservePercentEncodeWriter<'_, S, W> {
434 #[inline]
435 fn write_str(&mut self, s: &str) -> fmt::Result {
436 write!(self.writer, "{}", PercentEncoded::<_, S>::unreserve(s))
437 }
438 }
439 let mut writer = UnreservePercentEncodeWriter::<S, W> {
440 writer: f,
441 _spec: PhantomData,
442 };
443 write!(writer, "{v}")
444 }
445}
446
447fn escape_write_with_maxlen<S: Spec, T: fmt::Display, W: fmt::Write>(
449 writer: &mut PrefixOnceWriter<'_, W>,
450 v: T,
451 allow_reserved: bool,
452 max_len: Option<u16>,
453) -> fmt::Result {
454 if allow_reserved {
455 let mut max_len = max_len.map_or(usize::MAX, usize::from);
456 let result = process_percent_encoded_best_effort(v, |frag| {
457 if max_len == 0 {
458 return ControlFlow::Break(Ok(()));
459 }
460 let result = match frag {
461 PctEncodedFragments::Char(s, _) => {
462 max_len -= 1;
463 writer.write_str(s)
464 }
465 PctEncodedFragments::NoPctStr(s) => {
466 let mut chars = s.char_indices();
467 let count = chars
468 .by_ref()
469 .take(max_len)
470 .last()
471 .map(|(i, _)| i)
472 .expect("decomposed string fragment must not be empty");
473 let sub_len = s.len() - chars.as_str().len();
474 max_len -= count;
475 write!(
476 writer,
477 "{}",
478 PercentEncoded::<_, S>::characters(&s[..sub_len])
479 )
480 }
481 PctEncodedFragments::StrayPercent => {
482 max_len -= 1;
483 writer.write_str("%25")
484 }
485 PctEncodedFragments::InvalidUtf8PctTriplets(s) => {
486 let count = max_len.min(s.len() / 3);
487 let sub_len = count * 3;
488 max_len -= count;
489 writer.write_str(&s[..sub_len])
490 }
491 };
492 if result.is_err() {
493 return ControlFlow::Break(result);
494 }
495 ControlFlow::Continue(())
496 });
497 match result {
498 Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
499 Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
500 }
501 } else {
502 match max_len {
503 Some(max_len) => {
504 let mut writer = TruncatePercentEncodeWriter::<S, _> {
505 inner: writer,
506 rest_num_chars: usize::from(max_len),
507 _spec: PhantomData,
508 };
509 write!(writer, "{v}")
510 }
511 None => write!(writer, "{}", PercentEncoded::<_, S>::unreserve(v)),
512 }
513 }
514}
515
516struct TruncatePercentEncodeWriter<'a, S, W> {
518 inner: &'a mut W,
520 rest_num_chars: usize,
522 _spec: PhantomData<fn() -> S>,
524}
525
526impl<S: Spec, W: fmt::Write> fmt::Write for TruncatePercentEncodeWriter<'_, S, W> {
527 fn write_str(&mut self, s: &str) -> fmt::Result {
528 if self.rest_num_chars == 0 {
529 return Ok(());
530 }
531 let mut chars = s.char_indices();
532 let skip_count = chars
533 .by_ref()
534 .take(self.rest_num_chars)
535 .last()
536 .map_or(0, |(i, _)| i + 1);
537 let len = s.len() - chars.as_str().len();
538 let truncated = &s[..len];
539 write!(
540 self.inner,
541 "{}",
542 PercentEncoded::<_, S>::unreserve(truncated)
543 )?;
544 self.rest_num_chars -= skip_count;
545 Ok(())
546 }
547}
548
549struct PrefixOnceWriter<'a, W> {
551 inner: &'a mut W,
553 prefix: Option<&'a str>,
555}
556
557impl<'a, W: fmt::Write> PrefixOnceWriter<'a, W> {
558 #[inline]
560 #[must_use]
561 fn new(inner: &'a mut W) -> Self {
562 Self {
563 inner,
564 prefix: None,
565 }
566 }
567
568 #[inline]
570 #[must_use]
571 fn with_prefix(inner: &'a mut W, prefix: &'a str) -> Self {
572 Self {
573 inner,
574 prefix: Some(prefix),
575 }
576 }
577
578 #[inline]
580 #[must_use]
581 fn has_unwritten_prefix(&self) -> bool {
582 self.prefix.is_some()
583 }
584}
585
586impl<W: fmt::Write> fmt::Write for PrefixOnceWriter<'_, W> {
587 #[inline]
588 fn write_str(&mut self, s: &str) -> fmt::Result {
589 if let Some(prefix) = self.prefix.take() {
590 self.inner.write_str(prefix)?;
591 }
592 self.inner.write_str(s)
593 }
594}
595
596struct VisitDoneToken<'a, S, W>(ValueVisitor<'a, S, W>);
600
601impl<'a, S: Spec, W: fmt::Write> VisitDoneToken<'a, S, W> {
602 #[inline]
604 #[must_use]
605 fn new(visitor: ValueVisitor<'a, S, W>) -> Self {
606 Self(visitor)
607 }
608
609 #[inline]
611 #[must_use]
612 fn writer_ptr(&self) -> *const W {
613 self.0.writer_ptr()
614 }
615}
616
617impl<S: Spec, W: fmt::Write> fmt::Debug for VisitDoneToken<'_, S, W> {
618 #[inline]
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 f.write_str("VisitDoneToken")
621 }
622}
623
624struct ValueVisitor<'a, S, W> {
628 writer: &'a mut W,
630 varspec: VarSpec<'a>,
632 op: Operator,
634 is_first_varspec: &'a mut bool,
636 _spec: PhantomData<fn() -> S>,
638}
639
640impl<'a, S: Spec, W: fmt::Write> ValueVisitor<'a, S, W> {
641 #[inline]
643 #[must_use]
644 fn new(
645 f: &'a mut W,
646 varspec: VarSpec<'a>,
647 op: Operator,
648 is_first_varspec: &'a mut bool,
649 ) -> Self {
650 Self {
651 writer: f,
652 varspec,
653 op,
654 is_first_varspec,
655 _spec: PhantomData,
656 }
657 }
658
659 #[inline]
661 #[must_use]
662 fn writer_ptr(&self) -> *const W {
663 self.writer as &_ as *const _
664 }
665}
666
667impl<S: Spec, W: fmt::Write> VisitorSealed for ValueVisitor<'_, S, W> {}
668
669impl<'a, S: Spec, W: fmt::Write> Visitor for ValueVisitor<'a, S, W> {
670 type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
671 type ListVisitor = ListValueVisitor<'a, S, W>;
672 type AssocVisitor = AssocValueVisitor<'a, S, W>;
673
674 #[inline]
676 fn var_name(&self) -> VarName<'a> {
677 self.varspec.name()
678 }
679
680 #[inline]
681 fn purpose(&self) -> VisitPurpose {
682 VisitPurpose::Expand
683 }
684
685 #[inline]
687 fn visit_undefined(self) -> Self::Result {
688 Ok(VisitDoneToken::new(self))
689 }
690
691 #[inline]
693 fn visit_string<T: fmt::Display>(self, v: T) -> Self::Result {
694 let oppr = OpProps::from_op(self.op);
695
696 if mem::replace(self.is_first_varspec, false) {
697 self.writer.write_str(oppr.first)?;
698 } else {
699 self.writer.write_str(oppr.sep)?;
700 }
701 let mut writer = if oppr.named {
702 self.writer.write_str(self.varspec.name().as_str())?;
703 PrefixOnceWriter::with_prefix(self.writer, "=")
704 } else {
705 PrefixOnceWriter::new(self.writer)
706 };
707
708 let max_len = match self.varspec.modifier() {
709 Modifier::None | Modifier::Explode => None,
710 Modifier::MaxLen(max_len) => Some(max_len),
711 };
712 escape_write_with_maxlen::<S, T, W>(&mut writer, v, oppr.allow_reserved, max_len)?;
713 if writer.has_unwritten_prefix() {
714 self.writer.write_str(oppr.ifemp)?;
715 }
716 Ok(VisitDoneToken::new(self))
717 }
718
719 #[inline]
721 fn visit_list(self) -> Self::ListVisitor {
722 let oppr = OpProps::from_op(self.op);
723 ListValueVisitor {
724 visitor: self,
725 num_elems: 0,
726 oppr,
727 }
728 }
729
730 #[inline]
732 fn visit_assoc(self) -> Self::AssocVisitor {
733 let oppr = OpProps::from_op(self.op);
734 AssocValueVisitor {
735 visitor: self,
736 num_elems: 0,
737 oppr,
738 }
739 }
740}
741
742struct ListValueVisitor<'a, S, W> {
754 visitor: ValueVisitor<'a, S, W>,
756 num_elems: usize,
758 oppr: &'static OpProps,
760}
761
762impl<S: Spec, W: fmt::Write> ListValueVisitor<'_, S, W> {
763 fn visit_item_impl<T: fmt::Display>(&mut self, item: T) -> fmt::Result {
765 let modifier = self.visitor.varspec.modifier();
766 let is_explode = match modifier {
767 Modifier::MaxLen(_) => panic!(
768 "value type changed since `UriTemplateStr::expand()`: \
769 prefix modifier is not applicable to a list"
770 ),
771 Modifier::None => false,
772 Modifier::Explode => true,
773 };
774
775 if self.num_elems == 0 {
777 if mem::replace(self.visitor.is_first_varspec, false) {
778 self.visitor.writer.write_str(self.oppr.first)?;
779 } else {
780 self.visitor.writer.write_str(self.oppr.sep)?;
781 }
782 if self.oppr.named {
783 self.visitor
784 .writer
785 .write_str(self.visitor.varspec.name().as_str())?;
786 self.visitor.writer.write_char('=')?;
787 }
788 } else {
789 match (self.oppr.named, is_explode) {
791 (_, false) => self.visitor.writer.write_char(',')?,
792 (false, true) => self.visitor.writer.write_str(self.oppr.sep)?,
793 (true, true) => {
794 self.visitor.writer.write_str(self.oppr.sep)?;
795 escape_write::<S, _, _>(
796 self.visitor.writer,
797 self.visitor.varspec.name().as_str(),
798 self.oppr.allow_reserved,
799 )?;
800 self.visitor.writer.write_char('=')?;
801 }
802 }
803 }
804
805 escape_write::<S, _, _>(self.visitor.writer, item, self.oppr.allow_reserved)?;
806
807 self.num_elems += 1;
808 Ok(())
809 }
810}
811
812impl<S: Spec, W: fmt::Write> VisitorSealed for ListValueVisitor<'_, S, W> {}
813
814impl<'a, S: Spec, W: fmt::Write> ListVisitor for ListValueVisitor<'a, S, W> {
815 type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
816
817 #[inline]
819 fn visit_item<T: fmt::Display>(&mut self, item: T) -> ControlFlow<Self::Result> {
820 match self.visit_item_impl(item) {
821 Ok(_) => ControlFlow::Continue(()),
822 Err(e) => ControlFlow::Break(Err(e)),
823 }
824 }
825
826 #[inline]
828 fn finish(self) -> Self::Result {
829 Ok(VisitDoneToken::new(self.visitor))
830 }
831}
832
833struct AssocValueVisitor<'a, S, W> {
845 visitor: ValueVisitor<'a, S, W>,
847 num_elems: usize,
849 oppr: &'static OpProps,
851}
852
853impl<S: Spec, W: fmt::Write> AssocValueVisitor<'_, S, W> {
854 fn visit_entry_impl<K: fmt::Display, V: fmt::Display>(
856 &mut self,
857 key: K,
858 value: V,
859 ) -> fmt::Result {
860 let modifier = self.visitor.varspec.modifier();
861 let is_explode = match modifier {
862 Modifier::MaxLen(_) => panic!(
863 "value type changed since `UriTemplateStr::expand()`: \
864 prefix modifier is not applicable to an associative array"
865 ),
866 Modifier::None => false,
867 Modifier::Explode => true,
868 };
869
870 if self.num_elems == 0 {
872 if mem::replace(self.visitor.is_first_varspec, false) {
873 self.visitor.writer.write_str(self.oppr.first)?;
874 } else {
875 self.visitor.writer.write_str(self.oppr.sep)?;
876 }
877 if is_explode {
878 escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
879 self.visitor.writer.write_char('=')?;
880 } else {
881 if self.oppr.named {
882 escape_write::<S, _, _>(
883 self.visitor.writer,
884 self.visitor.varspec.name().as_str(),
885 self.oppr.allow_reserved,
886 )?;
887 self.visitor.writer.write_char('=')?;
888 }
889 escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
890 self.visitor.writer.write_char(',')?;
891 }
892 } else {
893 match (self.oppr.named, is_explode) {
895 (_, false) => {
896 self.visitor.writer.write_char(',')?;
897 escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
898 self.visitor.writer.write_char(',')?;
899 }
900 (false, true) => {
901 self.visitor.writer.write_str(self.oppr.sep)?;
902 escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
903 self.visitor.writer.write_char('=')?;
904 }
905 (true, true) => {
906 self.visitor.writer.write_str(self.oppr.sep)?;
907 escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
908 self.visitor.writer.write_char('=')?;
909 }
910 }
911 }
912
913 escape_write::<S, _, _>(self.visitor.writer, value, self.oppr.allow_reserved)?;
914
915 self.num_elems += 1;
916 Ok(())
917 }
918}
919
920impl<S: Spec, W: fmt::Write> VisitorSealed for AssocValueVisitor<'_, S, W> {}
921
922impl<'a, S: Spec, W: fmt::Write> AssocVisitor for AssocValueVisitor<'a, S, W> {
923 type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
924
925 #[inline]
927 fn visit_entry<K: fmt::Display, V: fmt::Display>(
928 &mut self,
929 key: K,
930 value: V,
931 ) -> ControlFlow<Self::Result> {
932 match self.visit_entry_impl(key, value) {
933 Ok(_) => ControlFlow::Continue(()),
934 Err(e) => ControlFlow::Break(Err(e)),
935 }
936 }
937
938 #[inline]
940 fn finish(self) -> Self::Result {
941 Ok(VisitDoneToken::new(self.visitor))
942 }
943}
944
945struct TypeVisitor<'a> {
947 var_name: VarName<'a>,
949}
950
951impl<'a> TypeVisitor<'a> {
952 #[inline]
954 #[must_use]
955 fn new(var_name: VarName<'a>) -> Self {
956 Self { var_name }
957 }
958}
959
960impl VisitorSealed for TypeVisitor<'_> {}
961
962impl<'a> Visitor for TypeVisitor<'a> {
963 type Result = ValueType;
964 type ListVisitor = ListTypeVisitor;
965 type AssocVisitor = AssocTypeVisitor;
966
967 #[inline]
968 fn var_name(&self) -> VarName<'a> {
969 self.var_name
970 }
971 #[inline]
972 fn purpose(&self) -> VisitPurpose {
973 VisitPurpose::Typecheck
974 }
975 #[inline]
976 fn visit_undefined(self) -> Self::Result {
977 ValueType::undefined()
978 }
979 #[inline]
980 fn visit_string<T: fmt::Display>(self, _: T) -> Self::Result {
981 ValueType::string()
982 }
983 #[inline]
984 fn visit_list(self) -> Self::ListVisitor {
985 ListTypeVisitor
986 }
987 #[inline]
988 fn visit_assoc(self) -> Self::AssocVisitor {
989 AssocTypeVisitor
990 }
991}
992
993struct ListTypeVisitor;
995
996impl VisitorSealed for ListTypeVisitor {}
997
998impl ListVisitor for ListTypeVisitor {
999 type Result = ValueType;
1000
1001 #[inline]
1003 fn visit_item<T: fmt::Display>(&mut self, _item: T) -> ControlFlow<Self::Result> {
1004 ControlFlow::Break(ValueType::nonempty_list())
1005 }
1006
1007 #[inline]
1009 fn finish(self) -> Self::Result {
1010 ValueType::empty_list()
1011 }
1012}
1013
1014struct AssocTypeVisitor;
1016
1017impl VisitorSealed for AssocTypeVisitor {}
1018
1019impl AssocVisitor for AssocTypeVisitor {
1020 type Result = ValueType;
1021
1022 #[inline]
1024 fn visit_entry<K: fmt::Display, V: fmt::Display>(
1025 &mut self,
1026 _key: K,
1027 _value: V,
1028 ) -> ControlFlow<Self::Result> {
1029 ControlFlow::Break(ValueType::nonempty_assoc())
1030 }
1031
1032 #[inline]
1034 fn finish(self) -> Self::Result {
1035 ValueType::empty_assoc()
1036 }
1037}