1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//! Defines traits and types to help make arbitrary values formattable at runtime.

use std::borrow::Borrow;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;

use crate::Specifier;

/// A type that indicates whether its value supports a specific format, and provides formatting
/// functions that correspond to different format types.
pub trait FormatArgument {
    /// Returns `true` if `self` can be formatted using the given specifier.
    fn supports_format(&self, specifier: &Specifier) -> bool;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::Display`.
    fn fmt_display(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::Debug`.
    fn fmt_debug(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::Octal`.
    fn fmt_octal(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::LowerHex`.
    fn fmt_lower_hex(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::UpperHex`.
    fn fmt_upper_hex(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::Binary`.
    fn fmt_binary(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::LowerExp`.
    fn fmt_lower_exp(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Formats the value the way it would be formatted if it implemented `std::fmt::UpperExp`.
    fn fmt_upper_exp(&self, f: &mut fmt::Formatter) -> fmt::Result;
    /// Performs a type conversion into `usize` that might fail. Like `TryInto<usize>`, but does not
    /// consume `self`. The parser uses this to support formats whose width or precision use "dollar
    /// syntax". For more information about these, see [std::fmt]. The default implementation always
    /// returns an error.
    fn to_usize(&self) -> Result<usize, ()> {
        Err(())
    }
}

/// Holds a `FormatArgument` and implements all the `std::fmt` formatting traits.
pub struct ArgumentFormatter<'v, V: FormatArgument>(pub &'v V);

impl<'v, V: FormatArgument> fmt::Display for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_display(f)
    }
}

impl<'v, V: FormatArgument> fmt::Debug for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_debug(f)
    }
}

impl<'v, V: FormatArgument> fmt::Octal for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_octal(f)
    }
}

impl<'v, V: FormatArgument> fmt::LowerHex for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_lower_hex(f)
    }
}

impl<'v, V: FormatArgument> fmt::UpperHex for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_upper_hex(f)
    }
}

impl<'v, V: FormatArgument> fmt::Binary for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_binary(f)
    }
}

impl<'v, V: FormatArgument> fmt::LowerExp for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_lower_exp(f)
    }
}

impl<'v, V: FormatArgument> fmt::UpperExp for ArgumentFormatter<'v, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_upper_exp(f)
    }
}

/// A type that associates an argument with a name.
pub trait NamedArguments<V: FormatArgument> {
    /// Returns a reference to the argument associated with the given name, if any.
    fn get(&self, key: &str) -> Option<&V>;
}

impl<K, V> NamedArguments<V> for HashMap<K, V>
where
    K: Borrow<str> + Hash + Eq,
    V: FormatArgument,
{
    fn get(&self, key: &str) -> Option<&V> {
        <HashMap<K, V>>::get(self, key)
    }
}

impl<K, V> NamedArguments<V> for HashMap<K, &V>
where
    K: Borrow<str> + Hash + Eq,
    V: FormatArgument,
{
    fn get(&self, key: &str) -> Option<&V> {
        <HashMap<K, &V>>::get(self, key).map(|v| *v)
    }
}

/// A `NamedArguments` implementation that always returns `None`.
pub struct NoNamedArguments;

impl<V> NamedArguments<V> for NoNamedArguments
where
    V: FormatArgument,
{
    fn get(&self, _: &str) -> Option<&V> {
        None
    }
}

/// A type that provides a list of arguments, randomly accessible by their position.
pub trait PositionalArguments<'v, V>
where
    V: 'v + FormatArgument,
{
    /// The type of the iterator that can be used to iterate over arguments.
    type Iter: Iterator<Item = &'v V>;

    /// Returns a reference to the argument at the given index, if any.
    fn get(&self, index: usize) -> Option<&V>;

    /// Creates an iterator over the arguments.
    fn iter(&'v self) -> Self::Iter;
}

impl<'v, V, T> PositionalArguments<'v, V> for T
where
    V: 'v + FormatArgument,
    T: AsRef<[V]> + ?Sized,
{
    type Iter = std::slice::Iter<'v, V>;

    fn get(&self, index: usize) -> Option<&V> {
        <[V]>::get(self.as_ref(), index)
    }

    fn iter(&'v self) -> Self::Iter {
        <[V]>::iter(self.as_ref())
    }
}

/// A 'PositionalArguments` implementation that always returns `None`.
pub struct NoPositionalArguments;

impl<'v, V> PositionalArguments<'v, V> for NoPositionalArguments
where
    V: 'v + FormatArgument,
{
    type Iter = std::iter::Empty<&'v V>;

    fn get(&self, _: usize) -> Option<&V> {
        None
    }

    fn iter(&'v self) -> Self::Iter {
        std::iter::empty()
    }
}

/// A source of values to use when parsing the formatting string.
pub trait ArgumentSource<V>
where
    V: FormatArgument,
{
    /// Returns the next positional argument, if any. Calling `lookup_argument_by_index` does not
    /// affect which value will be returned by the next call to `next_argument`.
    fn next_argument(&mut self) -> Option<&V>;

    /// Returns the positional argument with the given index, if any. Calling
    /// `lookup_argument_by_index` does not affect which value will be returned by the next call to
    /// `next_argument`.
    fn lookup_argument_by_index(&self, idx: usize) -> Option<&V>;

    /// Returns the named argument with the given name, if any.
    fn lookup_argument_by_name(&self, name: &str) -> Option<&V>;
}