rocket_http_community/uri/fmt/
formatter.rs

1use std::borrow::Cow;
2use std::fmt::{self, Write};
3use std::marker::PhantomData;
4
5use crate::uri::fmt::{Kind, Part, Path, Query, UriDisplay};
6use crate::uri::{Absolute, Origin, Reference};
7
8/// A struct used to format strings for [`UriDisplay`].
9///
10/// # Marker Generic: `Formatter<Path>` vs. `Formatter<Query>`
11///
12/// Like [`UriDisplay`], the [`Part`] parameter `P` in `Formatter<P>` must be
13/// either [`Path`] or [`Query`] resulting in either `Formatter<Path>` or
14/// `Formatter<Query>`. The `Path` version is used when formatting parameters
15/// in the path part of the URI while the `Query` version is used when
16/// formatting parameters in the query part of the URI. The
17/// [`write_named_value()`] method is only available to `UriDisplay<Query>`.
18///
19/// # Overview
20///
21/// A mutable version of this struct is passed to [`UriDisplay::fmt()`]. This
22/// struct properly formats series of values for use in URIs. In particular,
23/// this struct applies the following transformations:
24///
25///   * When **multiple values** are written, they are separated by `/` for
26///     `Path` types and `&` for `Query` types.
27///
28/// Additionally, for `Formatter<Query>`:
29///
30///   * When a **named value** is written with [`write_named_value()`], the name
31///     is written out, followed by a `=`, followed by the value.
32///
33///   * When **nested named values** are written, typically by passing a value
34///     to [`write_named_value()`] whose implementation of `UriDisplay` also
35///     calls `write_named_value()`, the nested names are joined by a `.`,
36///     written out followed by a `=`, followed by the value.
37///
38/// # Usage
39///
40/// Usage is fairly straightforward:
41///
42///   * For every _named value_ you wish to emit, call [`write_named_value()`].
43///   * For every _unnamed value_ you wish to emit, call [`write_value()`].
44///   * To write a string directly, call [`write_raw()`].
45///
46/// The `write_named_value` method automatically prefixes the `name` to the
47/// written value and, along with `write_value` and `write_raw`, handles nested
48/// calls to `write_named_value` automatically, prefixing names when necessary.
49/// Unlike the other methods, `write_raw` does _not_ prefix any nested names
50/// every time it is called. Instead, it only prefixes the _first_ time it is
51/// called, after a call to `write_named_value` or `write_value`, or after a
52/// call to [`refresh()`].
53///
54/// # Example
55///
56/// The following example uses all of the `write` methods in a varied order to
57/// display the semantics of `Formatter<Query>`. Note that `UriDisplay` should
58/// rarely be implemented manually, preferring to use the derive, and that this
59/// implementation is purely demonstrative.
60///
61/// ```rust
62/// # extern crate rocket;
63/// use std::fmt;
64///
65/// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query};
66///
67/// struct Outer {
68///     value: Inner,
69///     another: usize,
70///     extra: usize
71/// }
72///
73/// struct Inner {
74///     value: usize,
75///     extra: usize
76/// }
77///
78/// impl UriDisplay<Query> for Outer {
79///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
80///         f.write_named_value("outer_field", &self.value)?;
81///         f.write_named_value("another", &self.another)?;
82///         f.write_raw("out")?;
83///         f.write_raw("side")?;
84///         f.write_value(&self.extra)
85///     }
86/// }
87///
88/// impl UriDisplay<Query> for Inner {
89///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
90///         f.write_named_value("inner_field", &self.value)?;
91///         f.write_value(&self.extra)?;
92///         f.write_raw("inside")
93///     }
94/// }
95///
96/// let inner = Inner { value: 0, extra: 1 };
97/// let outer = Outer { value: inner, another: 2, extra: 3 };
98/// let uri_string = format!("{}", &outer as &dyn UriDisplay<Query>);
99/// assert_eq!(uri_string, "outer_field.inner_field=0&\
100///                         outer_field=1&\
101///                         outer_field=inside&\
102///                         another=2&\
103///                         outside&\
104///                         3");
105/// ```
106///
107/// Note that you can also use the `write!` macro to write directly to the
108/// formatter as long as the [`std::fmt::Write`] trait is in scope. Internally,
109/// the `write!` macro calls [`write_raw()`], so care must be taken to ensure
110/// that the written string is URI-safe.
111///
112/// ```rust
113/// # #[macro_use] extern crate rocket;
114/// use std::fmt::{self, Write};
115///
116/// use rocket::http::uri::fmt::{UriDisplay, Formatter, Part, Path, Query};
117///
118/// pub struct Complex(u8, u8);
119///
120/// impl<P: Part> UriDisplay<P> for Complex {
121///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
122///         write!(f, "{}+{}", self.0, self.1)
123///     }
124/// }
125///
126/// let uri_string = format!("{}", &Complex(42, 231) as &dyn UriDisplay<Path>);
127/// assert_eq!(uri_string, "42+231");
128///
129/// #[derive(UriDisplayQuery)]
130/// struct Message {
131///     number: Complex,
132/// }
133///
134/// let message = Message { number: Complex(42, 47) };
135/// let uri_string = format!("{}", &message as &dyn UriDisplay<Query>);
136/// assert_eq!(uri_string, "number=42+47");
137/// ```
138///
139/// [`write_named_value()`]: Formatter::write_value()
140/// [`write_value()`]: Formatter::write_value()
141/// [`write_raw()`]: Formatter::write_raw()
142/// [`refresh()`]: Formatter::refresh()
143pub struct Formatter<'i, P: Part> {
144    prefixes: tinyvec::TinyVec<[&'static str; 3]>,
145    inner: &'i mut (dyn Write + 'i),
146    previous: bool,
147    fresh: bool,
148    _marker: PhantomData<P>,
149}
150
151impl<'i, P: Part> Formatter<'i, P> {
152    #[inline(always)]
153    pub(crate) fn new(inner: &'i mut (dyn Write + 'i)) -> Self {
154        Formatter {
155            inner,
156            prefixes: Default::default(),
157            previous: false,
158            fresh: true,
159            _marker: PhantomData,
160        }
161    }
162
163    #[inline(always)]
164    fn refreshed<F: FnOnce(&mut Self) -> fmt::Result>(&mut self, f: F) -> fmt::Result {
165        self.refresh();
166        let result = f(self);
167        self.refresh();
168        result
169    }
170
171    /// Writes `string` to `self`.
172    ///
173    /// If `self` is _fresh_ (after a call to other `write_` methods or
174    /// [`refresh()`]), prefixes any names and adds separators as necessary.
175    ///
176    /// This method is called by the `write!` macro.
177    ///
178    /// [`refresh()`]: Formatter::refresh()
179    ///
180    /// # Example
181    ///
182    /// ```rust
183    /// # extern crate rocket;
184    /// use std::fmt;
185    ///
186    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Part, Path};
187    ///
188    /// struct Foo;
189    ///
190    /// impl<P: Part> UriDisplay<P> for Foo {
191    ///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
192    ///         f.write_raw("f")?;
193    ///         f.write_raw("o")?;
194    ///         f.write_raw("o")
195    ///     }
196    /// }
197    ///
198    /// let foo = Foo;
199    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Path>);
200    /// assert_eq!(uri_string, "foo");
201    /// ```
202    pub fn write_raw<S: AsRef<str>>(&mut self, string: S) -> fmt::Result {
203        // This implementation is a bit of a lie to the type system. Instead of
204        // implementing this twice, one for <Path> and again for <Query>, we do
205        // this once here. This is okay since we know that this handles the
206        // cases for both Path and Query, and doing it this way allows us to
207        // keep the uri part generic _generic_ in other implementations that use
208        // `write_raw`.
209        if self.fresh {
210            if self.previous {
211                self.inner.write_char(P::DELIMITER)?;
212            }
213
214            if P::KIND == Kind::Query && !self.prefixes.is_empty() {
215                for (i, prefix) in self.prefixes.iter().enumerate() {
216                    if i != 0 {
217                        self.inner.write_char('.')?
218                    }
219                    self.inner.write_str(prefix)?;
220                }
221
222                self.inner.write_str("=")?;
223            }
224        }
225
226        self.fresh = false;
227        self.previous = true;
228        self.inner.write_str(string.as_ref())
229    }
230
231    /// Writes the unnamed value `value`. Any nested names are prefixed as
232    /// necessary.
233    ///
234    /// Refreshes `self` before and after the value is written.
235    ///
236    /// # Example
237    ///
238    /// ```rust
239    /// # extern crate rocket;
240    /// use std::fmt;
241    ///
242    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Part, Path, Query};
243    ///
244    /// struct Foo(usize);
245    ///
246    /// impl<P: Part> UriDisplay<P> for Foo {
247    ///     fn fmt(&self, f: &mut Formatter<P>) -> fmt::Result {
248    ///         f.write_value(&self.0)
249    ///     }
250    /// }
251    ///
252    /// let foo = Foo(123);
253    ///
254    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Path>);
255    /// assert_eq!(uri_string, "123");
256    ///
257    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Query>);
258    /// assert_eq!(uri_string, "123");
259    /// ```
260    #[inline]
261    pub fn write_value<T: UriDisplay<P>>(&mut self, value: T) -> fmt::Result {
262        self.refreshed(|f| UriDisplay::fmt(&value, f))
263    }
264
265    /// Refreshes the formatter.
266    ///
267    /// After refreshing, [`write_raw()`] will prefix any nested names as well
268    /// as insert a separator.
269    ///
270    /// [`write_raw()`]: Formatter::write_raw()
271    ///
272    /// # Example
273    ///
274    /// ```rust
275    /// # #[macro_use] extern crate rocket;
276    /// use std::fmt;
277    ///
278    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query, Path};
279    ///
280    /// struct Foo;
281    ///
282    /// impl UriDisplay<Query> for Foo {
283    ///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
284    ///         f.write_raw("a")?;
285    ///         f.write_raw("raw")?;
286    ///         f.refresh();
287    ///         f.write_raw("format")
288    ///     }
289    /// }
290    ///
291    /// let uri_string = format!("{}", &Foo as &dyn UriDisplay<Query>);
292    /// assert_eq!(uri_string, "araw&format");
293    ///
294    /// impl UriDisplay<Path> for Foo {
295    ///     fn fmt(&self, f: &mut Formatter<Path>) -> fmt::Result {
296    ///         f.write_raw("a")?;
297    ///         f.write_raw("raw")?;
298    ///         f.refresh();
299    ///         f.write_raw("format")
300    ///     }
301    /// }
302    ///
303    /// let uri_string = format!("{}", &Foo as &dyn UriDisplay<Path>);
304    /// assert_eq!(uri_string, "araw/format");
305    ///
306    /// #[derive(UriDisplayQuery)]
307    /// struct Message {
308    ///     inner: Foo,
309    /// }
310    ///
311    /// let msg = Message { inner: Foo };
312    /// let uri_string = format!("{}", &msg as &dyn UriDisplay<Query>);
313    /// assert_eq!(uri_string, "inner=araw&inner=format");
314    /// ```
315    #[inline(always)]
316    pub fn refresh(&mut self) {
317        self.fresh = true;
318    }
319}
320
321impl Formatter<'_, Query> {
322    fn with_prefix<F>(&mut self, prefix: &str, f: F) -> fmt::Result
323    where
324        F: FnOnce(&mut Self) -> fmt::Result,
325    {
326        struct PrefixGuard<'f, 'i>(&'f mut Formatter<'i, Query>);
327
328        impl<'f, 'i> PrefixGuard<'f, 'i> {
329            fn new(prefix: &str, f: &'f mut Formatter<'i, Query>) -> Self {
330                // SAFETY: The `prefix` string is pushed in a `StackVec` for use
331                // by recursive (nested) calls to `write_raw`. The string is
332                // pushed in `PrefixGuard` here and then popped in `Drop`.
333                // `prefixes` is modified nowhere else, and no concrete-lifetime
334                // strings leak from the the vector. As a result, it is
335                // impossible for a `prefix` to be accessed incorrectly as:
336                //
337                //   * Rust _guarantees_ `prefix` is valid for this method
338                //   * `prefix` is only reachable while this method's stack is
339                //     active because it is unconditionally popped before this
340                //     method returns via `PrefixGuard::drop()`.
341                //   * should a panic occur in `f()`, `PrefixGuard::drop()` is
342                //     still called (or the program aborts), ensuring `prefix`
343                //     is no longer in `prefixes` and thus inaccessible.
344                //   * thus, at any point `prefix` is reachable, it is valid
345                //
346                // Said succinctly: `prefixes` shadows a subset of the
347                // `with_prefix` stack, making it reachable to other code.
348                let prefix = unsafe { std::mem::transmute::<&str, &str>(prefix) };
349                f.prefixes.push(prefix);
350                PrefixGuard(f)
351            }
352        }
353
354        impl Drop for PrefixGuard<'_, '_> {
355            fn drop(&mut self) {
356                self.0.prefixes.pop();
357            }
358        }
359
360        f(PrefixGuard::new(prefix, self).0)
361    }
362
363    /// Writes the named value `value` by prefixing `name` followed by `=` to
364    /// the value. Any nested names are also prefixed as necessary.
365    ///
366    /// Refreshes `self` before the name is written and after the value is
367    /// written.
368    ///
369    /// # Example
370    ///
371    /// ```rust
372    /// # extern crate rocket;
373    /// use std::fmt;
374    ///
375    /// use rocket::http::uri::fmt::{Formatter, UriDisplay, Query};
376    ///
377    /// struct Foo {
378    ///     name: usize
379    /// }
380    ///
381    /// // Note: This is identical to what #[derive(UriDisplayQuery)] would
382    /// // generate! In practice, _always_ use the derive.
383    /// impl UriDisplay<Query> for Foo {
384    ///     fn fmt(&self, f: &mut Formatter<Query>) -> fmt::Result {
385    ///         f.write_named_value("name", &self.name)
386    ///     }
387    /// }
388    ///
389    /// let foo = Foo { name: 123 };
390    /// let uri_string = format!("{}", &foo as &dyn UriDisplay<Query>);
391    /// assert_eq!(uri_string, "name=123");
392    /// ```
393    #[inline]
394    pub fn write_named_value<T: UriDisplay<Query>>(&mut self, name: &str, value: T) -> fmt::Result {
395        self.refreshed(|f| f.with_prefix(name, |f| f.write_value(value)))
396    }
397}
398
399impl<P: Part> fmt::Write for Formatter<'_, P> {
400    fn write_str(&mut self, s: &str) -> fmt::Result {
401        self.write_raw(s)
402    }
403}
404
405// Used by code generation.
406#[doc(hidden)]
407pub enum UriArgumentsKind<A> {
408    Static(&'static str),
409    Dynamic(A),
410}
411
412// Used by code generation.
413#[doc(hidden)]
414pub enum UriQueryArgument<'a> {
415    Raw(&'a str),
416    NameValue(&'a str, &'a dyn UriDisplay<Query>),
417    Value(&'a dyn UriDisplay<Query>),
418}
419
420/// No prefix at all.
421#[doc(hidden)]
422pub struct Void;
423
424// Used by code generation.
425#[doc(hidden)]
426pub trait ValidRoutePrefix {
427    type Output;
428
429    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output;
430}
431
432impl<'a> ValidRoutePrefix for Origin<'a> {
433    type Output = Self;
434
435    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output {
436        // No-op if `self` is already normalized.
437        let mut prefix = self.into_normalized();
438        prefix.clear_query();
439
440        // Avoid a double `//` to start.
441        if prefix.path() == "/" {
442            return Origin::new(path, query);
443        }
444
445        // Avoid allocating if the `path` would result in just the prefix.
446        if path == "/" {
447            prefix.set_query(query);
448            return prefix;
449        }
450
451        // Avoid a `//` resulting from joining.
452        if prefix.has_trailing_slash() && path.starts_with('/') {
453            return Origin::new(format!("{}{}", prefix.path(), &path[1..]), query);
454        }
455
456        // Join normally.
457        Origin::new(format!("{}{}", prefix.path(), path), query)
458    }
459}
460
461impl<'a> ValidRoutePrefix for Absolute<'a> {
462    type Output = Self;
463
464    fn append(self, path: Cow<'static, str>, query: Option<Cow<'static, str>>) -> Self::Output {
465        // No-op if `self` is already normalized.
466        let mut prefix = self.into_normalized();
467        prefix.clear_query();
468
469        // Distinguish for routes `/` with bases of `/foo/` and `/foo`. The
470        // latter base, without a trailing slash, should combine as `/foo`.
471        if path == "/" {
472            prefix.set_query(query);
473            return prefix;
474        }
475
476        // In these cases, appending `path` would be a no-op or worse.
477        if prefix.path().is_empty() || prefix.path() == "/" {
478            prefix.set_path(path);
479            prefix.set_query(query);
480            return prefix;
481        }
482
483        // Create the combined URI.
484        prefix.set_path(format!("{}{}", prefix.path(), path));
485        prefix.set_query(query);
486        prefix
487    }
488}
489
490// `Self` is a valid suffix for `T`.
491#[doc(hidden)]
492pub trait ValidRouteSuffix<T> {
493    type Output;
494
495    fn prepend(self, prefix: T) -> Self::Output;
496}
497
498impl<'a> ValidRouteSuffix<Origin<'a>> for Reference<'a> {
499    type Output = Self;
500
501    fn prepend(self, prefix: Origin<'a>) -> Self::Output {
502        Reference::from(prefix).with_query_fragment_of(self)
503    }
504}
505
506impl<'a> ValidRouteSuffix<Absolute<'a>> for Reference<'a> {
507    type Output = Self;
508
509    fn prepend(self, prefix: Absolute<'a>) -> Self::Output {
510        Reference::from(prefix).with_query_fragment_of(self)
511    }
512}
513
514impl<'a> ValidRouteSuffix<Origin<'a>> for Absolute<'a> {
515    type Output = Origin<'a>;
516
517    fn prepend(self, mut prefix: Origin<'a>) -> Self::Output {
518        if let Some(query) = self.query {
519            if prefix.query().is_none() {
520                prefix.set_query(query.value.into_concrete(&self.source));
521            }
522        }
523
524        prefix
525    }
526}
527
528impl<'a> ValidRouteSuffix<Absolute<'a>> for Absolute<'a> {
529    type Output = Self;
530
531    fn prepend(self, mut prefix: Absolute<'a>) -> Self::Output {
532        if let Some(query) = self.query {
533            if prefix.query().is_none() {
534                prefix.set_query(query.value.into_concrete(&self.source));
535            }
536        }
537
538        prefix
539    }
540}
541
542// Used by code generation.
543#[doc(hidden)]
544pub struct RouteUriBuilder {
545    pub path: Cow<'static, str>,
546    pub query: Option<Cow<'static, str>>,
547}
548
549// Used by code generation.
550#[doc(hidden)]
551pub struct PrefixedRouteUri<T>(T);
552
553// Used by code generation.
554#[doc(hidden)]
555pub struct SuffixedRouteUri<T>(T);
556
557// Used by code generation.
558#[doc(hidden)]
559impl RouteUriBuilder {
560    /// Create a new `RouteUriBuilder` with the given path/query args.
561    pub fn new(
562        path_args: UriArgumentsKind<&[&dyn UriDisplay<Path>]>,
563        query_args: Option<UriArgumentsKind<&[UriQueryArgument<'_>]>>,
564    ) -> Self {
565        use self::{UriArgumentsKind::*, UriQueryArgument::*};
566
567        let path: Cow<'static, str> = match path_args {
568            Static(path) => path.into(),
569            Dynamic(args) => {
570                let mut string = String::from("/");
571                let mut formatter = Formatter::<Path>::new(&mut string);
572                for value in args {
573                    let _ = formatter.write_value(value);
574                }
575
576                string.into()
577            }
578        };
579
580        let query: Option<Cow<'_, str>> = match query_args {
581            None => None,
582            Some(Static(query)) => Some(query.into()),
583            Some(Dynamic(args)) => {
584                let mut string = String::new();
585                let mut f = Formatter::<Query>::new(&mut string);
586                for arg in args {
587                    let _ = match arg {
588                        Raw(v) => f.write_raw(v),
589                        NameValue(n, v) => f.write_named_value(n, v),
590                        Value(v) => f.write_value(v),
591                    };
592                }
593
594                (!string.is_empty()).then(|| string.into())
595            }
596        };
597
598        RouteUriBuilder { path, query }
599    }
600
601    pub fn with_prefix<P: ValidRoutePrefix>(self, p: P) -> PrefixedRouteUri<P::Output> {
602        PrefixedRouteUri(p.append(self.path, self.query))
603    }
604
605    pub fn with_suffix<S>(self, suffix: S) -> SuffixedRouteUri<S::Output>
606    where
607        S: ValidRouteSuffix<Origin<'static>>,
608    {
609        SuffixedRouteUri(suffix.prepend(self.render()))
610    }
611
612    pub fn render(self) -> Origin<'static> {
613        Origin::new(self.path, self.query)
614    }
615}
616
617#[doc(hidden)]
618impl<T> PrefixedRouteUri<T> {
619    pub fn with_suffix<S: ValidRouteSuffix<T>>(self, suffix: S) -> SuffixedRouteUri<S::Output> {
620        SuffixedRouteUri(suffix.prepend(self.0))
621    }
622
623    pub fn render(self) -> T {
624        self.0
625    }
626}
627
628#[doc(hidden)]
629impl<T> SuffixedRouteUri<T> {
630    pub fn render(self) -> T {
631        self.0
632    }
633}
634
635// See https://github.com/rwf2/Rocket/issues/1534.
636#[cfg(test)]
637mod prefix_soundness_test {
638    use crate::uri::fmt::{Formatter, Query, UriDisplay};
639
640    struct MyValue;
641
642    impl UriDisplay<Query> for MyValue {
643        fn fmt(&self, _f: &mut Formatter<'_, Query>) -> std::fmt::Result {
644            panic!()
645        }
646    }
647
648    struct MyDisplay;
649
650    impl UriDisplay<Query> for MyDisplay {
651        fn fmt(&self, formatter: &mut Formatter<'_, Query>) -> std::fmt::Result {
652            struct Wrapper<'a, 'b>(&'a mut Formatter<'b, Query>);
653
654            impl<'a, 'b> Drop for Wrapper<'a, 'b> {
655                fn drop(&mut self) {
656                    let _overlap = String::from("12345");
657                    self.0.write_raw("world").ok();
658                    assert!(self.0.prefixes.is_empty());
659                }
660            }
661
662            let wrapper = Wrapper(formatter);
663            let temporary_string = String::from("hello");
664
665            // `write_named_value` will push `temp_string` into a buffer and
666            // call the formatter for `MyValue`, which panics. At the panic
667            // point, `formatter` contains an (illegal) static reference to
668            // `temp_string` in its `prefixes` stack. When unwinding occurs,
669            // `Wrapper` will be dropped. `Wrapper` holds a reference to
670            // `Formatter`, thus `Formatter` must be consistent at this point.
671            let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
672                wrapper.0.write_named_value(&temporary_string, MyValue)
673            }));
674
675            Ok(())
676        }
677    }
678
679    #[test]
680    fn check_consistency() {
681        let string = format!("{}", &MyDisplay as &dyn UriDisplay<Query>);
682        assert_eq!(string, "world");
683    }
684}