3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_span::symbol::{Ident, Symbol};
9 // format_args!("hello {abc:.xyz$}!!", abc="world");
10 // └──────────────────────────────────────────────┘
13 // format_args!("hello {abc:.xyz$}!!", abc="world");
17 // format_args!("hello {abc:.xyz$}!!", abc="world");
18 // └───────────────────┘
21 // format_args!("hello {abc:.xyz$}!!", abc="world");
22 // └────┘└─────────┘└┘
25 // format_args!("hello {abc:.xyz$}!!", abc="world");
29 // format_args!("hello {abc:.xyz$}!!", abc="world");
33 // format_args!("hello {abc:.xyz$}!!", abc="world");
35 // positions (could be names, numbers, empty, or `*`)
37 /// (Parsed) format args.
39 /// Basically the "AST" for a complete `format_args!()`.
41 /// E.g., `format_args!("hello {name}");`.
42 #[derive(Clone, Encodable, Decodable, Debug)]
43 pub struct FormatArgs {
45 pub template: Vec<FormatArgsPiece>,
46 pub arguments: FormatArguments,
49 /// A piece of a format template string.
51 /// E.g. "hello" or "{name}".
52 #[derive(Clone, Encodable, Decodable, Debug)]
53 pub enum FormatArgsPiece {
55 Placeholder(FormatPlaceholder),
58 /// The arguments to format_args!().
60 /// E.g. `1, 2, name="ferris", n=3`,
61 /// but also implicit captured arguments like `x` in `format_args!("{x}")`.
62 #[derive(Clone, Encodable, Decodable, Debug)]
63 pub struct FormatArguments {
64 arguments: Vec<FormatArgument>,
65 num_unnamed_args: usize,
66 num_explicit_args: usize,
67 names: FxHashMap<Symbol, usize>,
70 // FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
71 #[cfg(parallel_compiler)]
72 unsafe impl Sync for FormatArguments {}
73 #[cfg(parallel_compiler)]
74 unsafe impl Send for FormatArguments {}
76 impl FormatArguments {
77 pub fn new() -> Self {
79 arguments: Vec::new(),
80 names: FxHashMap::default(),
86 pub fn add(&mut self, arg: FormatArgument) -> usize {
87 let index = self.arguments.len();
88 if let Some(name) = arg.kind.ident() {
89 self.names.insert(name.name, index);
90 } else if self.names.is_empty() {
91 // Only count the unnamed args before the first named arg.
92 // (Any later ones are errors.)
93 self.num_unnamed_args += 1;
95 if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
96 // This is an explicit argument.
97 // Make sure that all arguments so far are explcit.
99 self.num_explicit_args,
100 self.arguments.len(),
101 "captured arguments must be added last"
103 self.num_explicit_args += 1;
105 self.arguments.push(arg);
109 pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
110 let i = *self.names.get(&name)?;
111 Some((i, &self.arguments[i]))
114 pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
115 (i < self.num_explicit_args).then(|| &self.arguments[i])
118 pub fn unnamed_args(&self) -> &[FormatArgument] {
119 &self.arguments[..self.num_unnamed_args]
122 pub fn named_args(&self) -> &[FormatArgument] {
123 &self.arguments[self.num_unnamed_args..self.num_explicit_args]
126 pub fn explicit_args(&self) -> &[FormatArgument] {
127 &self.arguments[..self.num_explicit_args]
130 pub fn all_args(&self) -> &[FormatArgument] {
134 pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
135 &mut self.arguments[..]
139 #[derive(Clone, Encodable, Decodable, Debug)]
140 pub struct FormatArgument {
141 pub kind: FormatArgumentKind,
145 #[derive(Clone, Encodable, Decodable, Debug)]
146 pub enum FormatArgumentKind {
147 /// `format_args(…, arg)`
149 /// `format_args(…, arg = 1)`
151 /// `format_args("… {arg} …")`
155 impl FormatArgumentKind {
156 pub fn ident(&self) -> Option<Ident> {
158 &Self::Normal => None,
159 &Self::Named(id) => Some(id),
160 &Self::Captured(id) => Some(id),
165 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
166 pub struct FormatPlaceholder {
167 /// Index into [`FormatArgs::arguments`].
168 pub argument: FormatArgPosition,
169 /// The span inside the format string for the full `{…}` placeholder.
170 pub span: Option<Span>,
171 /// `{}`, `{:?}`, or `{:x}`, etc.
172 pub format_trait: FormatTrait,
173 /// `{}` or `{:.5}` or `{:-^20}`, etc.
174 pub format_options: FormatOptions,
177 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
178 pub struct FormatArgPosition {
179 /// Which argument this position refers to (Ok),
180 /// or would've referred to if it existed (Err).
181 pub index: Result<usize, usize>,
182 /// What kind of position this is. See [`FormatArgPositionKind`].
183 pub kind: FormatArgPositionKind,
184 /// The span of the name or number.
185 pub span: Option<Span>,
188 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
189 pub enum FormatArgPositionKind {
192 /// `{1}` or `{:1$}` or `{:.1$}`
194 /// `{a}` or `{:a$}` or `{:.a$}`
198 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
199 pub enum FormatTrait {
220 #[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
221 pub struct FormatOptions {
222 /// The width. E.g. `{:5}` or `{:width$}`.
223 pub width: Option<FormatCount>,
224 /// The precision. E.g. `{:.5}` or `{:.precision$}`.
225 pub precision: Option<FormatCount>,
226 /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
227 pub alignment: Option<FormatAlignment>,
228 /// The fill character. E.g. the `.` in `{:.>10}`.
229 pub fill: Option<char>,
230 /// The `+` or `-` flag.
231 pub sign: Option<FormatSign>,
234 /// The `0` flag. E.g. the `0` in `{:02x}`.
236 /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
237 pub debug_hex: Option<FormatDebugHex>,
240 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
241 pub enum FormatSign {
248 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
249 pub enum FormatDebugHex {
250 /// The `x` flag in `{:x?}`.
252 /// The `X` flag in `{:X?}`.
256 #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
257 pub enum FormatAlignment {
266 #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
267 pub enum FormatCount {
268 /// `{:5}` or `{:.5}`
270 /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
271 Argument(FormatArgPosition),