rt_format/
argument.rs

1//! Defines traits and types to help make arbitrary values formattable at runtime.
2
3use std::borrow::Borrow;
4use std::collections::HashMap;
5use std::fmt;
6use std::hash::Hash;
7
8use crate::Specifier;
9
10/// A type that indicates whether its value supports a specific format, and provides formatting
11/// functions that correspond to different format types.
12pub trait FormatArgument {
13    /// Returns `true` if `self` can be formatted using the given specifier.
14    fn supports_format(&self, specifier: &Specifier) -> bool;
15    /// Formats the value the way it would be formatted if it implemented `std::fmt::Display`.
16    fn fmt_display(&self, f: &mut fmt::Formatter) -> fmt::Result;
17    /// Formats the value the way it would be formatted if it implemented `std::fmt::Debug`.
18    fn fmt_debug(&self, f: &mut fmt::Formatter) -> fmt::Result;
19    /// Formats the value the way it would be formatted if it implemented `std::fmt::Octal`.
20    fn fmt_octal(&self, f: &mut fmt::Formatter) -> fmt::Result;
21    /// Formats the value the way it would be formatted if it implemented `std::fmt::LowerHex`.
22    fn fmt_lower_hex(&self, f: &mut fmt::Formatter) -> fmt::Result;
23    /// Formats the value the way it would be formatted if it implemented `std::fmt::UpperHex`.
24    fn fmt_upper_hex(&self, f: &mut fmt::Formatter) -> fmt::Result;
25    /// Formats the value the way it would be formatted if it implemented `std::fmt::Binary`.
26    fn fmt_binary(&self, f: &mut fmt::Formatter) -> fmt::Result;
27    /// Formats the value the way it would be formatted if it implemented `std::fmt::LowerExp`.
28    fn fmt_lower_exp(&self, f: &mut fmt::Formatter) -> fmt::Result;
29    /// Formats the value the way it would be formatted if it implemented `std::fmt::UpperExp`.
30    fn fmt_upper_exp(&self, f: &mut fmt::Formatter) -> fmt::Result;
31    /// Performs a type conversion into `usize` that might fail. Like `TryInto<usize>`, but does not
32    /// consume `self`. The parser uses this to support formats whose width or precision use "dollar
33    /// syntax". For more information about these, see [std::fmt]. The default implementation always
34    /// returns an error.
35    fn to_usize(&self) -> Result<usize, ()> {
36        Err(())
37    }
38}
39
40/// Holds a `FormatArgument` and implements all the `std::fmt` formatting traits.
41pub struct ArgumentFormatter<'v, V: FormatArgument>(pub &'v V);
42
43impl<'v, V: FormatArgument> fmt::Display for ArgumentFormatter<'v, V> {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        self.0.fmt_display(f)
46    }
47}
48
49impl<'v, V: FormatArgument> fmt::Debug for ArgumentFormatter<'v, V> {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        self.0.fmt_debug(f)
52    }
53}
54
55impl<'v, V: FormatArgument> fmt::Octal for ArgumentFormatter<'v, V> {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        self.0.fmt_octal(f)
58    }
59}
60
61impl<'v, V: FormatArgument> fmt::LowerHex for ArgumentFormatter<'v, V> {
62    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63        self.0.fmt_lower_hex(f)
64    }
65}
66
67impl<'v, V: FormatArgument> fmt::UpperHex for ArgumentFormatter<'v, V> {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        self.0.fmt_upper_hex(f)
70    }
71}
72
73impl<'v, V: FormatArgument> fmt::Binary for ArgumentFormatter<'v, V> {
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        self.0.fmt_binary(f)
76    }
77}
78
79impl<'v, V: FormatArgument> fmt::LowerExp for ArgumentFormatter<'v, V> {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        self.0.fmt_lower_exp(f)
82    }
83}
84
85impl<'v, V: FormatArgument> fmt::UpperExp for ArgumentFormatter<'v, V> {
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        self.0.fmt_upper_exp(f)
88    }
89}
90
91/// A type that associates an argument with a name.
92pub trait NamedArguments<V: FormatArgument> {
93    /// Returns a reference to the argument associated with the given name, if any.
94    fn get(&self, key: &str) -> Option<&V>;
95}
96
97impl<K, V> NamedArguments<V> for HashMap<K, V>
98where
99    K: Borrow<str> + Hash + Eq,
100    V: FormatArgument,
101{
102    fn get(&self, key: &str) -> Option<&V> {
103        <HashMap<K, V>>::get(self, key)
104    }
105}
106
107impl<K, V> NamedArguments<V> for HashMap<K, &V>
108where
109    K: Borrow<str> + Hash + Eq,
110    V: FormatArgument,
111{
112    fn get(&self, key: &str) -> Option<&V> {
113        <HashMap<K, &V>>::get(self, key).map(|v| *v)
114    }
115}
116
117/// A `NamedArguments` implementation that always returns `None`.
118pub struct NoNamedArguments;
119
120impl<V> NamedArguments<V> for NoNamedArguments
121where
122    V: FormatArgument,
123{
124    fn get(&self, _: &str) -> Option<&V> {
125        None
126    }
127}
128
129/// A type that provides a list of arguments, randomly accessible by their position.
130pub trait PositionalArguments<'v, V>
131where
132    V: 'v + FormatArgument,
133{
134    /// The type of the iterator that can be used to iterate over arguments.
135    type Iter: Iterator<Item = &'v V>;
136
137    /// Returns a reference to the argument at the given index, if any.
138    fn get(&self, index: usize) -> Option<&V>;
139
140    /// Creates an iterator over the arguments.
141    fn iter(&'v self) -> Self::Iter;
142}
143
144impl<'v, V, T> PositionalArguments<'v, V> for T
145where
146    V: 'v + FormatArgument,
147    T: AsRef<[V]> + ?Sized,
148{
149    type Iter = std::slice::Iter<'v, V>;
150
151    fn get(&self, index: usize) -> Option<&V> {
152        <[V]>::get(self.as_ref(), index)
153    }
154
155    fn iter(&'v self) -> Self::Iter {
156        <[V]>::iter(self.as_ref())
157    }
158}
159
160/// A 'PositionalArguments` implementation that always returns `None`.
161pub struct NoPositionalArguments;
162
163impl<'v, V> PositionalArguments<'v, V> for NoPositionalArguments
164where
165    V: 'v + FormatArgument,
166{
167    type Iter = std::iter::Empty<&'v V>;
168
169    fn get(&self, _: usize) -> Option<&V> {
170        None
171    }
172
173    fn iter(&'v self) -> Self::Iter {
174        std::iter::empty()
175    }
176}
177
178/// A source of values to use when parsing the formatting string.
179pub trait ArgumentSource<V>
180where
181    V: FormatArgument,
182{
183    /// Returns the next positional argument, if any. Calling `lookup_argument_by_index` does not
184    /// affect which value will be returned by the next call to `next_argument`.
185    fn next_argument(&mut self) -> Option<&V>;
186
187    /// Returns the positional argument with the given index, if any. Calling
188    /// `lookup_argument_by_index` does not affect which value will be returned by the next call to
189    /// `next_argument`.
190    fn lookup_argument_by_index(&self, idx: usize) -> Option<&V>;
191
192    /// Returns the named argument with the given name, if any.
193    fn lookup_argument_by_name(&self, name: &str) -> Option<&V>;
194}