Coverage Report

Created: 2025-12-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/iri-string-0.7.9/src/template/expand.rs
Line
Count
Source
1
//! Expansion.
2
3
use core::fmt::{self, Write as _};
4
use core::marker::PhantomData;
5
use core::mem;
6
use core::ops::ControlFlow;
7
8
#[cfg(feature = "alloc")]
9
use alloc::string::{String, ToString};
10
11
use crate::parser::str::{find_split, find_split_hole};
12
use crate::parser::str::{process_percent_encoded_best_effort, PctEncodedFragments};
13
use crate::percent_encode::PercentEncoded;
14
use crate::spec::Spec;
15
use crate::template::components::{ExprBody, Modifier, Operator, VarName, VarSpec};
16
use crate::template::context::{
17
    private::Sealed as VisitorSealed, AssocVisitor, Context, DynamicContext, ListVisitor,
18
    VisitPurpose, Visitor,
19
};
20
use crate::template::error::{Error, ErrorKind};
21
use crate::template::{UriTemplateStr, ValueType};
22
#[cfg(feature = "alloc")]
23
use crate::types;
24
25
/// A chunk in a template string.
26
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27
pub(super) enum Chunk<'a> {
28
    /// Literal.
29
    Literal(&'a str),
30
    /// Expression excluding the wrapping braces.
31
    Expr(ExprBody<'a>),
32
}
33
34
/// Iterator of template chunks.
35
#[derive(Debug, Clone)]
36
pub(super) struct Chunks<'a> {
37
    /// Template.
38
    template: &'a str,
39
}
40
41
impl<'a> Chunks<'a> {
42
    /// Creates a new iterator.
43
    #[inline]
44
    #[must_use]
45
0
    pub(super) fn new(template: &'a UriTemplateStr) -> Self {
46
0
        Self {
47
0
            template: template.as_str(),
48
0
        }
49
0
    }
50
}
51
52
impl<'a> Iterator for Chunks<'a> {
53
    type Item = Chunk<'a>;
54
55
0
    fn next(&mut self) -> Option<Self::Item> {
56
0
        if self.template.is_empty() {
57
0
            return None;
58
0
        }
59
0
        match find_split(self.template, b'{') {
60
0
            Some(("", _)) => {
61
0
                let (expr_body, rest) = find_split_hole(&self.template[1..], b'}')
62
0
                    .expect("[validity] expression inside a template must be closed");
63
0
                self.template = rest;
64
0
                Some(Chunk::Expr(ExprBody::new(expr_body)))
65
            }
66
0
            Some((lit, rest)) => {
67
0
                self.template = rest;
68
0
                Some(Chunk::Literal(lit))
69
            }
70
0
            None => Some(Chunk::Literal(mem::take(&mut self.template))),
71
        }
72
0
    }
73
}
74
75
/// Template expansion result.
76
#[derive(Debug, Clone, Copy)]
77
pub struct Expanded<'a, S, C> {
78
    /// Compiled template.
79
    template: &'a UriTemplateStr,
80
    /// Context.
81
    context: &'a C,
82
    /// Spec.
83
    _spec: PhantomData<fn() -> S>,
84
}
85
86
impl<'a, S: Spec, C: Context> Expanded<'a, S, C> {
87
    /// Creates a new `Expanded` object.
88
    #[inline]
89
0
    pub(super) fn new(template: &'a UriTemplateStr, context: &'a C) -> Result<Self, Error> {
90
0
        Self::typecheck_context(template, context)?;
91
0
        Ok(Self {
92
0
            template,
93
0
            context,
94
0
            _spec: PhantomData,
95
0
        })
96
0
    }
97
98
    /// Checks if the types of variables are allowed for the corresponding expressions in the template.
99
0
    fn typecheck_context(template: &UriTemplateStr, context: &C) -> Result<(), Error> {
100
0
        let mut pos = 0;
101
0
        for chunk in Chunks::new(template) {
102
0
            let (expr_len, (op, varlist)) = match chunk {
103
0
                Chunk::Expr(expr_body) => (expr_body.as_str().len(), expr_body.decompose()),
104
0
                Chunk::Literal(lit) => {
105
0
                    pos += lit.len();
106
0
                    continue;
107
                }
108
            };
109
            // +2: wrapping braces (`{` and `}`).
110
0
            let chunk_end_pos = pos + expr_len + 2;
111
            // +1: opening brace `{`.
112
0
            pos += op.len() + 1;
113
0
            for (varspec_len, varspec) in varlist {
114
0
                let ty = context.visit(TypeVisitor::new(varspec.name()));
115
0
                let modifier = varspec.modifier();
116
117
0
                if matches!(modifier, Modifier::MaxLen(_))
118
0
                    && matches!(ty, ValueType::List | ValueType::Assoc)
119
                {
120
                    // > Prefix modifiers are not applicable to variables that
121
                    // > have composite values.
122
                    //
123
                    // --- [RFC 6570 Section 2.4.1. Prefix](https://www.rfc-editor.org/rfc/rfc6570.html#section-2.4.1)
124
0
                    return Err(Error::new(ErrorKind::UnexpectedValueType, pos));
125
0
                }
126
127
                // +1: A trailing comman (`,`) or a closing brace (`}`).
128
0
                pos += varspec_len + 1;
129
            }
130
0
            assert_eq!(pos, chunk_end_pos);
131
        }
132
0
        Ok(())
133
0
    }
134
}
135
136
impl<S: Spec, C: Context> fmt::Display for Expanded<'_, S, C> {
137
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138
0
        for chunk in Chunks::new(self.template) {
139
0
            let expr = match chunk {
140
0
                Chunk::Literal(lit) => {
141
0
                    f.write_str(lit)?;
142
0
                    continue;
143
                }
144
0
                Chunk::Expr(body) => body,
145
            };
146
0
            expand::<S, _>(f, expr, self.context)?;
147
        }
148
149
0
        Ok(())
150
0
    }
151
}
152
153
/// Implement `TryFrom<Expanded<...>> for SomeUriStringType`.
154
macro_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
0
            fn try_from(v: Expanded<'_, S, C>) -> Result<Self, Self::Error> {
162
0
                Self::try_from(v.to_string())
163
0
            }
Unexecuted instantiation: <iri_string::types::generic::reference::RiReferenceString<_> as core::convert::TryFrom<iri_string::template::expand::Expanded<_, _>>>::try_from
Unexecuted instantiation: <iri_string::types::generic::relative::RiRelativeString<_> as core::convert::TryFrom<iri_string::template::expand::Expanded<_, _>>>::try_from
Unexecuted instantiation: <iri_string::types::generic::normal::RiString<_> as core::convert::TryFrom<iri_string::template::expand::Expanded<_, _>>>::try_from
Unexecuted instantiation: <iri_string::types::generic::absolute::RiAbsoluteString<_> as core::convert::TryFrom<iri_string::template::expand::Expanded<_, _>>>::try_from
164
        }
165
    };
166
}
167
168
// Not implementing `TryFrom<Expand<...>>` for query and fragment strings
169
// since they cannot behave as a query or a fragment only by themselves.
170
// Query strings in practical starts with `?` prefix but `RiQueryStr{,ing}`
171
// strips that, and so do fragment strings (but `#` instead of `?`).
172
// Because of this, query and fragment string types won't be used to represent
173
// a relative IRIs without combining the prefix.
174
//
175
// In contrast, RFC 6570 URI Template expects that the users are constructing a
176
// "working" IRIs, including the necessary prefixes for syntax components.
177
// For example, fragment expansion `{#var}`, where `var` is "hello", expands to
178
// `#hello`, including the prefix `#`. This means that a URI template will be
179
// used to generate neither `RiQueryStr{,ing}` nor `RiFragmentStr{,ing}` strings.
180
impl_try_from_expanded!(RiAbsoluteString);
181
impl_try_from_expanded!(RiReferenceString);
182
impl_try_from_expanded!(RiRelativeString);
183
impl_try_from_expanded!(RiString);
184
185
/// Expands the whole template with the dynamic context.
186
0
pub(super) fn expand_whole_dynamic<S: Spec, W: fmt::Write, C: DynamicContext>(
187
0
    template: &UriTemplateStr,
188
0
    writer: &mut W,
189
0
    context: &mut C,
190
0
) -> Result<(), Error> {
191
0
    context.on_expansion_start();
192
0
    let result = expand_whole_dynamic_impl::<S, W, C>(template, writer, context);
193
0
    context.on_expansion_end();
194
0
    result
195
0
}
196
197
/// Expands the whole template with the dynamic context.
198
///
199
/// Note that the caller is responsible to set up or finalize the `context`.
200
0
fn expand_whole_dynamic_impl<S: Spec, W: fmt::Write, C: DynamicContext>(
201
0
    template: &UriTemplateStr,
202
0
    writer: &mut W,
203
0
    context: &mut C,
204
0
) -> Result<(), Error> {
205
0
    let mut pos = 0;
206
0
    for chunk in Chunks::new(template) {
207
0
        let expr = match chunk {
208
0
            Chunk::Literal(lit) => {
209
0
                writer
210
0
                    .write_str(lit)
211
0
                    .map_err(|_| Error::new(ErrorKind::WriteFailed, pos))?;
212
0
                pos += lit.len();
213
0
                continue;
214
            }
215
0
            Chunk::Expr(body) => body,
216
        };
217
0
        expand_expr_mut::<S, _, _>(writer, &mut pos, expr, context)?;
218
    }
219
220
0
    Ok(())
221
0
}
222
223
/// Expands the expression using the given operator and the dynamic context.
224
0
fn expand_expr_mut<S: Spec, W: fmt::Write, C: DynamicContext>(
225
0
    writer: &mut W,
226
0
    pos: &mut usize,
227
0
    expr: ExprBody<'_>,
228
0
    context: &mut C,
229
0
) -> Result<(), Error> {
230
0
    let (op, varlist) = expr.decompose();
231
232
0
    let mut is_first_varspec = true;
233
    // +2: wrapping braces (`{` and `}`).
234
0
    let chunk_end_pos = *pos + expr.as_str().len() + 2;
235
    // +1: opening brace `{`.
236
0
    *pos += op.len() + 1;
237
0
    for (varspec_len, varspec) in varlist {
238
        // Check the type before the actual expansion.
239
0
        let ty = context.visit_dynamic(TypeVisitor::new(varspec.name()));
240
0
        let modifier = varspec.modifier();
241
242
0
        if matches!(modifier, Modifier::MaxLen(_))
243
0
            && matches!(ty, ValueType::List | ValueType::Assoc)
244
        {
245
            // > Prefix modifiers are not applicable to variables that
246
            // > have composite values.
247
            //
248
            // --- [RFC 6570 Section 2.4.1. Prefix](https://www.rfc-editor.org/rfc/rfc6570.html#section-2.4.1)
249
0
            return Err(Error::new(ErrorKind::UnexpectedValueType, *pos));
250
0
        }
251
252
        // Typecheck passed. Expand.
253
0
        let visitor = ValueVisitor::<S, _>::new(writer, varspec, op, &mut is_first_varspec);
254
0
        let token = context
255
0
            .visit_dynamic(visitor)
256
0
            .map_err(|_| Error::new(ErrorKind::WriteFailed, *pos))?;
257
0
        let writer_ptr = token.writer_ptr();
258
0
        if !core::ptr::eq(writer_ptr, writer) {
259
            // Invalid `VisitDoneToken` was returned. This cannot usually happen
260
            // without intentional unnatural usage.
261
0
            panic!("invalid `VisitDoneToken` was returned");
262
0
        }
263
264
        // +1: A trailing comman (`,`) or a closing brace (`}`).
265
0
        *pos += varspec_len + 1;
266
    }
267
0
    assert_eq!(*pos, chunk_end_pos);
268
269
0
    Ok(())
270
0
}
271
272
/// Properties of an operator.
273
///
274
/// See [RFC 6570 Appendix A](https://www.rfc-editor.org/rfc/rfc6570#appendix-A).
275
#[derive(Debug, Clone, Copy)]
276
struct OpProps {
277
    /// Prefix for the first element.
278
    first: &'static str,
279
    /// Separator.
280
    sep: &'static str,
281
    /// Whether or not the expansion includes the variable or key name.
282
    named: bool,
283
    /// Result string if the variable is empty.
284
    ifemp: &'static str,
285
    /// Whether or not the reserved values can be written without being encoded.
286
    allow_reserved: bool,
287
}
288
289
impl OpProps {
290
    /// Properties for all known operators.
291
    const PROPS: [Self; 8] = [
292
        // String
293
        Self {
294
            first: "",
295
            sep: ",",
296
            named: false,
297
            ifemp: "",
298
            allow_reserved: false,
299
        },
300
        // Reserved
301
        Self {
302
            first: "",
303
            sep: ",",
304
            named: false,
305
            ifemp: "",
306
            allow_reserved: true,
307
        },
308
        // Fragment
309
        Self {
310
            first: "#",
311
            sep: ",",
312
            named: false,
313
            ifemp: "",
314
            allow_reserved: true,
315
        },
316
        // Label
317
        Self {
318
            first: ".",
319
            sep: ".",
320
            named: false,
321
            ifemp: "",
322
            allow_reserved: false,
323
        },
324
        // PathSegments
325
        Self {
326
            first: "/",
327
            sep: "/",
328
            named: false,
329
            ifemp: "",
330
            allow_reserved: false,
331
        },
332
        // PathParams
333
        Self {
334
            first: ";",
335
            sep: ";",
336
            named: true,
337
            ifemp: "",
338
            allow_reserved: false,
339
        },
340
        // FormQuery
341
        Self {
342
            first: "?",
343
            sep: "&",
344
            named: true,
345
            ifemp: "=",
346
            allow_reserved: false,
347
        },
348
        // FormQueryCont
349
        Self {
350
            first: "&",
351
            sep: "&",
352
            named: true,
353
            ifemp: "=",
354
            allow_reserved: false,
355
        },
356
    ];
357
358
    /// Returns the properties for the operator.
359
    #[must_use]
360
    #[inline]
361
0
    pub(super) fn from_op(op: Operator) -> &'static Self {
362
0
        let index = match op {
363
0
            Operator::String => 0,
364
0
            Operator::Reserved => 1,
365
0
            Operator::Fragment => 2,
366
0
            Operator::Label => 3,
367
0
            Operator::PathSegments => 4,
368
0
            Operator::PathParams => 5,
369
0
            Operator::FormQuery => 6,
370
0
            Operator::FormQueryCont => 7,
371
        };
372
0
        &Self::PROPS[index]
373
0
    }
374
}
375
376
/// Expands the expression using the given operator.
377
0
fn expand<S: Spec, C: Context>(
378
0
    f: &mut fmt::Formatter<'_>,
379
0
    expr: ExprBody<'_>,
380
0
    context: &C,
381
0
) -> fmt::Result {
382
0
    let (op, varlist) = expr.decompose();
383
384
0
    let mut is_first_varspec = true;
385
0
    for (_varspec_len, varspec) in varlist {
386
0
        let visitor = ValueVisitor::<S, _>::new(f, varspec, op, &mut is_first_varspec);
387
0
        let token = context.visit(visitor)?;
388
0
        let writer_ptr = token.writer_ptr();
389
0
        if !core::ptr::eq(writer_ptr, f) {
390
            // Invalid `VisitDoneToken` was returned. This cannot usually happen
391
            // without intentional unnatural usage.
392
0
            panic!("invalid `VisitDoneToken` was returned");
393
0
        }
394
    }
395
396
0
    Ok(())
397
0
}
398
399
/// Escapes the given value and writes it.
400
#[inline]
401
0
fn escape_write<S: Spec, T: fmt::Display, W: fmt::Write>(
402
0
    f: &mut W,
403
0
    v: T,
404
0
    allow_reserved: bool,
405
0
) -> fmt::Result {
406
0
    if allow_reserved {
407
0
        let result = process_percent_encoded_best_effort(v, |frag| {
408
0
            let result = match frag {
409
0
                PctEncodedFragments::Char(s, _) => f.write_str(s),
410
0
                PctEncodedFragments::NoPctStr(s) => {
411
0
                    write!(f, "{}", PercentEncoded::<_, S>::characters(s))
412
                }
413
0
                PctEncodedFragments::StrayPercent => f.write_str("%25"),
414
0
                PctEncodedFragments::InvalidUtf8PctTriplets(s) => f.write_str(s),
415
            };
416
0
            if result.is_err() {
417
0
                return ControlFlow::Break(result);
418
0
            }
419
0
            ControlFlow::Continue(())
420
0
        });
421
0
        match result {
422
0
            Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
423
0
            Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
424
        }
425
    } else {
426
        /// Writer that escapes the unreserved characters and writes them.
427
        struct UnreservePercentEncodeWriter<'a, S, W> {
428
            /// Inner writer.
429
            writer: &'a mut W,
430
            /// Spec.
431
            _spec: PhantomData<fn() -> S>,
432
        }
433
        impl<S: Spec, W: fmt::Write> fmt::Write for UnreservePercentEncodeWriter<'_, S, W> {
434
            #[inline]
435
0
            fn write_str(&mut self, s: &str) -> fmt::Result {
436
0
                write!(self.writer, "{}", PercentEncoded::<_, S>::unreserve(s))
437
0
            }
438
        }
439
0
        let mut writer = UnreservePercentEncodeWriter::<S, W> {
440
0
            writer: f,
441
0
            _spec: PhantomData,
442
0
        };
443
0
        write!(writer, "{v}")
444
    }
445
0
}
446
447
/// Truncates the given value as a string, escapes the value, and writes it.
448
0
fn escape_write_with_maxlen<S: Spec, T: fmt::Display, W: fmt::Write>(
449
0
    writer: &mut PrefixOnceWriter<'_, W>,
450
0
    v: T,
451
0
    allow_reserved: bool,
452
0
    max_len: Option<u16>,
453
0
) -> fmt::Result {
454
0
    if allow_reserved {
455
0
        let mut max_len = max_len.map_or(usize::MAX, usize::from);
456
0
        let result = process_percent_encoded_best_effort(v, |frag| {
457
0
            if max_len == 0 {
458
0
                return ControlFlow::Break(Ok(()));
459
0
            }
460
0
            let result =
461
0
                match frag {
462
0
                    PctEncodedFragments::Char(s, _) => {
463
0
                        max_len -= 1;
464
0
                        writer.write_str(s)
465
                    }
466
0
                    PctEncodedFragments::NoPctStr(s) => {
467
0
                        let mut chars = s.char_indices();
468
0
                        let count =
469
0
                            chars.by_ref().take(max_len).last().map(|(i, _)| i).expect(
470
0
                                "[consistency] decomposed string fragment must not be empty",
471
                            );
472
0
                        let sub_len = s.len() - chars.as_str().len();
473
0
                        max_len -= count;
474
0
                        write!(
475
0
                            writer,
476
0
                            "{}",
477
0
                            PercentEncoded::<_, S>::characters(&s[..sub_len])
478
                        )
479
                    }
480
                    PctEncodedFragments::StrayPercent => {
481
0
                        max_len -= 1;
482
0
                        writer.write_str("%25")
483
                    }
484
0
                    PctEncodedFragments::InvalidUtf8PctTriplets(s) => {
485
0
                        let count = max_len.min(s.len() / 3);
486
0
                        let sub_len = count * 3;
487
0
                        max_len -= count;
488
0
                        writer.write_str(&s[..sub_len])
489
                    }
490
                };
491
0
            if result.is_err() {
492
0
                return ControlFlow::Break(result);
493
0
            }
494
0
            ControlFlow::Continue(())
495
0
        });
496
0
        match result {
497
0
            Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
498
0
            Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
499
        }
500
    } else {
501
0
        match max_len {
502
0
            Some(max_len) => {
503
0
                let mut writer = TruncatePercentEncodeWriter::<S, _> {
504
0
                    inner: writer,
505
0
                    rest_num_chars: usize::from(max_len),
506
0
                    _spec: PhantomData,
507
0
                };
508
0
                write!(writer, "{v}")
509
            }
510
0
            None => write!(writer, "{}", PercentEncoded::<_, S>::unreserve(v)),
511
        }
512
    }
513
0
}
514
515
/// A writer that truncates the input to the given length and writes to the backend.
516
struct TruncatePercentEncodeWriter<'a, S, W> {
517
    /// Inner writer.
518
    inner: &'a mut W,
519
    /// Maximum number of characters to be written.
520
    rest_num_chars: usize,
521
    /// Spec.
522
    _spec: PhantomData<fn() -> S>,
523
}
524
525
impl<S: Spec, W: fmt::Write> fmt::Write for TruncatePercentEncodeWriter<'_, S, W> {
526
0
    fn write_str(&mut self, s: &str) -> fmt::Result {
527
0
        if self.rest_num_chars == 0 {
528
0
            return Ok(());
529
0
        }
530
0
        let mut chars = s.char_indices();
531
0
        let skip_count = chars
532
0
            .by_ref()
533
0
            .take(self.rest_num_chars)
534
0
            .last()
535
0
            .map_or(0, |(i, _)| i + 1);
536
0
        let len = s.len() - chars.as_str().len();
537
0
        let truncated = &s[..len];
538
0
        write!(
539
0
            self.inner,
540
0
            "{}",
541
0
            PercentEncoded::<_, S>::unreserve(truncated)
542
0
        )?;
543
0
        self.rest_num_chars -= skip_count;
544
0
        Ok(())
545
0
    }
546
}
547
548
/// A writer that writes a prefix only once if and only if some value is written.
549
struct PrefixOnceWriter<'a, W> {
550
    /// Inner writer.
551
    inner: &'a mut W,
552
    /// Prefix to write.
553
    prefix: Option<&'a str>,
554
}
555
556
impl<'a, W: fmt::Write> PrefixOnceWriter<'a, W> {
557
    /// Creates a new writer with no prefix.
558
    #[inline]
559
    #[must_use]
560
0
    fn new(inner: &'a mut W) -> Self {
561
0
        Self {
562
0
            inner,
563
0
            prefix: None,
564
0
        }
565
0
    }
566
567
    /// Creates a new writer with a prefix.
568
    #[inline]
569
    #[must_use]
570
0
    fn with_prefix(inner: &'a mut W, prefix: &'a str) -> Self {
571
0
        Self {
572
0
            inner,
573
0
            prefix: Some(prefix),
574
0
        }
575
0
    }
576
577
    /// Returns true if the writer have not yet written the prefix.
578
    #[inline]
579
    #[must_use]
580
0
    fn has_unwritten_prefix(&self) -> bool {
581
0
        self.prefix.is_some()
582
0
    }
583
}
584
585
impl<W: fmt::Write> fmt::Write for PrefixOnceWriter<'_, W> {
586
    #[inline]
587
0
    fn write_str(&mut self, s: &str) -> fmt::Result {
588
0
        if let Some(prefix) = self.prefix.take() {
589
0
            self.inner.write_str(prefix)?;
590
0
        }
591
0
        self.inner.write_str(s)
592
0
    }
593
}
594
595
/// An opaque token value that proves some variable is visited.
596
// This should not be able to be created by any means other than `VarVisitor::visit_foo()`.
597
// Do not derive any traits that allows the value to be generated or cloned.
598
struct VisitDoneToken<'a, S, W>(ValueVisitor<'a, S, W>);
599
600
impl<'a, S: Spec, W: fmt::Write> VisitDoneToken<'a, S, W> {
601
    /// Creates a new token.
602
    #[inline]
603
    #[must_use]
604
0
    fn new(visitor: ValueVisitor<'a, S, W>) -> Self {
605
0
        Self(visitor)
606
0
    }
607
608
    /// Returns the raw pointer to the backend formatter.
609
    #[inline]
610
    #[must_use]
611
0
    fn writer_ptr(&self) -> *const W {
612
0
        self.0.writer_ptr()
613
0
    }
614
}
615
616
impl<S: Spec, W: fmt::Write> fmt::Debug for VisitDoneToken<'_, S, W> {
617
    #[inline]
618
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619
0
        f.write_str("VisitDoneToken")
620
0
    }
621
}
622
623
/// Visitor to retrieve a variable value.
624
// Single `ValueVisitor` should be used for single expansion.
625
// Do not derive any traits that allows the value to be generated or cloned.
626
struct ValueVisitor<'a, S, W> {
627
    /// Formatter.
628
    writer: &'a mut W,
629
    /// Varspec.
630
    varspec: VarSpec<'a>,
631
    /// Operator.
632
    op: Operator,
633
    /// Whether the variable to visit is the first one in an expression.
634
    is_first_varspec: &'a mut bool,
635
    /// Spec.
636
    _spec: PhantomData<fn() -> S>,
637
}
638
639
impl<'a, S: Spec, W: fmt::Write> ValueVisitor<'a, S, W> {
640
    /// Creates a visitor.
641
    #[inline]
642
    #[must_use]
643
0
    fn new(
644
0
        f: &'a mut W,
645
0
        varspec: VarSpec<'a>,
646
0
        op: Operator,
647
0
        is_first_varspec: &'a mut bool,
648
0
    ) -> Self {
649
0
        Self {
650
0
            writer: f,
651
0
            varspec,
652
0
            op,
653
0
            is_first_varspec,
654
0
            _spec: PhantomData,
655
0
        }
656
0
    }
657
658
    /// Returns the raw pointer to the backend formatter.
659
    #[inline]
660
    #[must_use]
661
0
    fn writer_ptr(&self) -> *const W {
662
0
        self.writer as &_ as *const _
663
0
    }
664
}
665
666
impl<S: Spec, W: fmt::Write> VisitorSealed for ValueVisitor<'_, S, W> {}
667
668
impl<'a, S: Spec, W: fmt::Write> Visitor for ValueVisitor<'a, S, W> {
669
    type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
670
    type ListVisitor = ListValueVisitor<'a, S, W>;
671
    type AssocVisitor = AssocValueVisitor<'a, S, W>;
672
673
    /// Returns the name of the variable to visit.
674
    #[inline]
675
0
    fn var_name(&self) -> VarName<'a> {
676
0
        self.varspec.name()
677
0
    }
678
679
    #[inline]
680
0
    fn purpose(&self) -> VisitPurpose {
681
0
        VisitPurpose::Expand
682
0
    }
683
684
    /// Visits an undefined variable, i.e. indicates that the requested variable is unavailable.
685
    #[inline]
686
0
    fn visit_undefined(self) -> Self::Result {
687
0
        Ok(VisitDoneToken::new(self))
688
0
    }
689
690
    /// Visits a string variable.
691
    #[inline]
692
0
    fn visit_string<T: fmt::Display>(self, v: T) -> Self::Result {
693
0
        let oppr = OpProps::from_op(self.op);
694
695
0
        if mem::replace(self.is_first_varspec, false) {
696
0
            self.writer.write_str(oppr.first)?;
697
        } else {
698
0
            self.writer.write_str(oppr.sep)?;
699
        }
700
0
        let mut writer = if oppr.named {
701
0
            self.writer.write_str(self.varspec.name().as_str())?;
702
0
            PrefixOnceWriter::with_prefix(self.writer, "=")
703
        } else {
704
0
            PrefixOnceWriter::new(self.writer)
705
        };
706
707
0
        let max_len = match self.varspec.modifier() {
708
0
            Modifier::None | Modifier::Explode => None,
709
0
            Modifier::MaxLen(max_len) => Some(max_len),
710
        };
711
0
        escape_write_with_maxlen::<S, T, W>(&mut writer, v, oppr.allow_reserved, max_len)?;
712
0
        if writer.has_unwritten_prefix() {
713
0
            self.writer.write_str(oppr.ifemp)?;
714
0
        }
715
0
        Ok(VisitDoneToken::new(self))
716
0
    }
717
718
    /// Visits a list variable.
719
    #[inline]
720
0
    fn visit_list(self) -> Self::ListVisitor {
721
0
        let oppr = OpProps::from_op(self.op);
722
0
        ListValueVisitor {
723
0
            visitor: self,
724
0
            num_elems: 0,
725
0
            oppr,
726
0
        }
727
0
    }
728
729
    /// Visits an associative array variable.
730
    #[inline]
731
0
    fn visit_assoc(self) -> Self::AssocVisitor {
732
0
        let oppr = OpProps::from_op(self.op);
733
0
        AssocValueVisitor {
734
0
            visitor: self,
735
0
            num_elems: 0,
736
0
            oppr,
737
0
        }
738
0
    }
739
}
740
741
/// Visitor to retrieve value of a list variable.
742
// RFC 6570 section 2.3:
743
//
744
// > A variable defined as a list value is considered undefined if the
745
// > list contains zero members.  A variable defined as an associative
746
// > array of (name, value) pairs is considered undefined if the array
747
// > contains zero members or if all member names in the array are
748
// > associated with undefined values.
749
//
750
// Single variable visitor should be used for single expansion.
751
// Do not derive any traits that allows the value to be generated or cloned.
752
struct ListValueVisitor<'a, S, W> {
753
    /// Visitor.
754
    visitor: ValueVisitor<'a, S, W>,
755
    /// Number of already emitted elements.
756
    num_elems: usize,
757
    /// Operator props.
758
    oppr: &'static OpProps,
759
}
760
761
impl<S: Spec, W: fmt::Write> ListValueVisitor<'_, S, W> {
762
    /// Visits an item.
763
0
    fn visit_item_impl<T: fmt::Display>(&mut self, item: T) -> fmt::Result {
764
0
        let modifier = self.visitor.varspec.modifier();
765
0
        let is_explode = match modifier {
766
0
            Modifier::MaxLen(_) => panic!(
767
0
                "value type changed since `UriTemplateStr::expand()`: \
768
0
                 prefix modifier is not applicable to a list"
769
            ),
770
0
            Modifier::None => false,
771
0
            Modifier::Explode => true,
772
        };
773
774
        // Write prefix for each variable.
775
0
        if self.num_elems == 0 {
776
0
            if mem::replace(self.visitor.is_first_varspec, false) {
777
0
                self.visitor.writer.write_str(self.oppr.first)?;
778
            } else {
779
0
                self.visitor.writer.write_str(self.oppr.sep)?;
780
            }
781
0
            if self.oppr.named {
782
0
                self.visitor
783
0
                    .writer
784
0
                    .write_str(self.visitor.varspec.name().as_str())?;
785
0
                self.visitor.writer.write_char('=')?;
786
0
            }
787
        } else {
788
            // Write prefix for the non-first item.
789
0
            match (self.oppr.named, is_explode) {
790
0
                (_, false) => self.visitor.writer.write_char(',')?,
791
0
                (false, true) => self.visitor.writer.write_str(self.oppr.sep)?,
792
                (true, true) => {
793
0
                    self.visitor.writer.write_str(self.oppr.sep)?;
794
0
                    escape_write::<S, _, _>(
795
0
                        self.visitor.writer,
796
0
                        self.visitor.varspec.name().as_str(),
797
0
                        self.oppr.allow_reserved,
798
0
                    )?;
799
0
                    self.visitor.writer.write_char('=')?;
800
                }
801
            }
802
        }
803
804
0
        escape_write::<S, _, _>(self.visitor.writer, item, self.oppr.allow_reserved)?;
805
806
0
        self.num_elems += 1;
807
0
        Ok(())
808
0
    }
809
}
810
811
impl<S: Spec, W: fmt::Write> VisitorSealed for ListValueVisitor<'_, S, W> {}
812
813
impl<'a, S: Spec, W: fmt::Write> ListVisitor for ListValueVisitor<'a, S, W> {
814
    type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
815
816
    /// Visits an item.
817
    #[inline]
818
0
    fn visit_item<T: fmt::Display>(&mut self, item: T) -> ControlFlow<Self::Result> {
819
0
        match self.visit_item_impl(item) {
820
0
            Ok(_) => ControlFlow::Continue(()),
821
0
            Err(e) => ControlFlow::Break(Err(e)),
822
        }
823
0
    }
824
825
    /// Finishes visiting the list.
826
    #[inline]
827
0
    fn finish(self) -> Self::Result {
828
0
        Ok(VisitDoneToken::new(self.visitor))
829
0
    }
830
}
831
832
/// Visitor to retrieve entries of an associative array variable.
833
// RFC 6570 section 2.3:
834
//
835
// > A variable defined as a list value is considered undefined if the
836
// > list contains zero members.  A variable defined as an associative
837
// > array of (name, value) pairs is considered undefined if the array
838
// > contains zero members or if all member names in the array are
839
// > associated with undefined values.
840
//
841
// Single variable visitor should be used for single expansion.
842
// Do not derive any traits that allows the value to be generated or cloned.
843
struct AssocValueVisitor<'a, S, W> {
844
    /// Visitor.
845
    visitor: ValueVisitor<'a, S, W>,
846
    /// Number of already emitted elements.
847
    num_elems: usize,
848
    /// Operator props.
849
    oppr: &'static OpProps,
850
}
851
852
impl<S: Spec, W: fmt::Write> AssocValueVisitor<'_, S, W> {
853
    /// Visits an entry.
854
0
    fn visit_entry_impl<K: fmt::Display, V: fmt::Display>(
855
0
        &mut self,
856
0
        key: K,
857
0
        value: V,
858
0
    ) -> fmt::Result {
859
0
        let modifier = self.visitor.varspec.modifier();
860
0
        let is_explode = match modifier {
861
0
            Modifier::MaxLen(_) => panic!(
862
0
                "value type changed since `UriTemplateStr::expand()`: \
863
0
                 prefix modifier is not applicable to an associative array"
864
            ),
865
0
            Modifier::None => false,
866
0
            Modifier::Explode => true,
867
        };
868
869
        // Write prefix for each variable.
870
0
        if self.num_elems == 0 {
871
0
            if mem::replace(self.visitor.is_first_varspec, false) {
872
0
                self.visitor.writer.write_str(self.oppr.first)?;
873
            } else {
874
0
                self.visitor.writer.write_str(self.oppr.sep)?;
875
            }
876
0
            if is_explode {
877
0
                escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
878
0
                self.visitor.writer.write_char('=')?;
879
            } else {
880
0
                if self.oppr.named {
881
0
                    escape_write::<S, _, _>(
882
0
                        self.visitor.writer,
883
0
                        self.visitor.varspec.name().as_str(),
884
0
                        self.oppr.allow_reserved,
885
0
                    )?;
886
0
                    self.visitor.writer.write_char('=')?;
887
0
                }
888
0
                escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
889
0
                self.visitor.writer.write_char(',')?;
890
            }
891
        } else {
892
            // Write prefix for the non-first item.
893
0
            match (self.oppr.named, is_explode) {
894
                (_, false) => {
895
0
                    self.visitor.writer.write_char(',')?;
896
0
                    escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
897
0
                    self.visitor.writer.write_char(',')?;
898
                }
899
                (false, true) => {
900
0
                    self.visitor.writer.write_str(self.oppr.sep)?;
901
0
                    escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
902
0
                    self.visitor.writer.write_char('=')?;
903
                }
904
                (true, true) => {
905
0
                    self.visitor.writer.write_str(self.oppr.sep)?;
906
0
                    escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
907
0
                    self.visitor.writer.write_char('=')?;
908
                }
909
            }
910
        }
911
912
0
        escape_write::<S, _, _>(self.visitor.writer, value, self.oppr.allow_reserved)?;
913
914
0
        self.num_elems += 1;
915
0
        Ok(())
916
0
    }
917
}
918
919
impl<S: Spec, W: fmt::Write> VisitorSealed for AssocValueVisitor<'_, S, W> {}
920
921
impl<'a, S: Spec, W: fmt::Write> AssocVisitor for AssocValueVisitor<'a, S, W> {
922
    type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
923
924
    /// Visits an entry.
925
    #[inline]
926
0
    fn visit_entry<K: fmt::Display, V: fmt::Display>(
927
0
        &mut self,
928
0
        key: K,
929
0
        value: V,
930
0
    ) -> ControlFlow<Self::Result> {
931
0
        match self.visit_entry_impl(key, value) {
932
0
            Ok(_) => ControlFlow::Continue(()),
933
0
            Err(e) => ControlFlow::Break(Err(e)),
934
        }
935
0
    }
936
937
    /// Finishes visiting the associative array.
938
    #[inline]
939
0
    fn finish(self) -> Self::Result {
940
0
        Ok(VisitDoneToken::new(self.visitor))
941
0
    }
942
}
943
944
/// Visitor to retrieve effective type of a variable.
945
struct TypeVisitor<'a> {
946
    /// Variable name.
947
    var_name: VarName<'a>,
948
}
949
950
impl<'a> TypeVisitor<'a> {
951
    /// Creates a new type visitor.
952
    #[inline]
953
    #[must_use]
954
0
    fn new(var_name: VarName<'a>) -> Self {
955
0
        Self { var_name }
956
0
    }
957
}
958
959
impl VisitorSealed for TypeVisitor<'_> {}
960
961
impl<'a> Visitor for TypeVisitor<'a> {
962
    type Result = ValueType;
963
    type ListVisitor = ListTypeVisitor;
964
    type AssocVisitor = AssocTypeVisitor;
965
966
    #[inline]
967
0
    fn var_name(&self) -> VarName<'a> {
968
0
        self.var_name
969
0
    }
970
    #[inline]
971
0
    fn purpose(&self) -> VisitPurpose {
972
0
        VisitPurpose::Typecheck
973
0
    }
974
    #[inline]
975
0
    fn visit_undefined(self) -> Self::Result {
976
0
        ValueType::undefined()
977
0
    }
978
    #[inline]
979
0
    fn visit_string<T: fmt::Display>(self, _: T) -> Self::Result {
980
0
        ValueType::string()
981
0
    }
982
    #[inline]
983
0
    fn visit_list(self) -> Self::ListVisitor {
984
0
        ListTypeVisitor
985
0
    }
986
    #[inline]
987
0
    fn visit_assoc(self) -> Self::AssocVisitor {
988
0
        AssocTypeVisitor
989
0
    }
990
}
991
992
/// Visitor to retrieve effective type of a list variable.
993
struct ListTypeVisitor;
994
995
impl VisitorSealed for ListTypeVisitor {}
996
997
impl ListVisitor for ListTypeVisitor {
998
    type Result = ValueType;
999
1000
    /// Visits an item.
1001
    #[inline]
1002
0
    fn visit_item<T: fmt::Display>(&mut self, _item: T) -> ControlFlow<Self::Result> {
1003
0
        ControlFlow::Break(ValueType::nonempty_list())
1004
0
    }
1005
1006
    /// Finishes visiting the list.
1007
    #[inline]
1008
0
    fn finish(self) -> Self::Result {
1009
0
        ValueType::empty_list()
1010
0
    }
1011
}
1012
1013
/// Visitor to retrieve effective type of an associative array variable.
1014
struct AssocTypeVisitor;
1015
1016
impl VisitorSealed for AssocTypeVisitor {}
1017
1018
impl AssocVisitor for AssocTypeVisitor {
1019
    type Result = ValueType;
1020
1021
    /// Visits an item.
1022
    #[inline]
1023
0
    fn visit_entry<K: fmt::Display, V: fmt::Display>(
1024
0
        &mut self,
1025
0
        _key: K,
1026
0
        _value: V,
1027
0
    ) -> ControlFlow<Self::Result> {
1028
0
        ControlFlow::Break(ValueType::nonempty_assoc())
1029
0
    }
1030
1031
    /// Finishes visiting the list.
1032
    #[inline]
1033
0
    fn finish(self) -> Self::Result {
1034
0
        ValueType::empty_assoc()
1035
0
    }
1036
}