diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
commit | 4547b622d8d29df964fa2914213088b148c498fc (patch) | |
tree | 9fc6b25f3c3add6b745be9a2400a6e96140046e9 /vendor/displaydoc/src/fmt.rs | |
parent | Releasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz rustc-4547b622d8d29df964fa2914213088b148c498fc.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/displaydoc/src/fmt.rs')
-rw-r--r-- | vendor/displaydoc/src/fmt.rs | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/displaydoc/src/fmt.rs b/vendor/displaydoc/src/fmt.rs new file mode 100644 index 000000000..5848557ea --- /dev/null +++ b/vendor/displaydoc/src/fmt.rs @@ -0,0 +1,159 @@ +use crate::attr::Display; +use proc_macro2::TokenStream; +use quote::quote_spanned; +use syn::{Ident, LitStr}; + +macro_rules! peek_next { + ($read:ident) => { + match $read.chars().next() { + Some(next) => next, + None => return, + } + }; +} + +impl Display { + // Transform `"error {var}"` to `"error {}", var`. + pub(crate) fn expand_shorthand(&mut self) { + let span = self.fmt.span(); + let fmt = self.fmt.value(); + let mut read = fmt.as_str(); + let mut out = String::new(); + let mut args = TokenStream::new(); + + while let Some(brace) = read.find('{') { + out += &read[..=brace]; + read = &read[brace + 1..]; + + // skip cases where we find a {{ + if read.starts_with('{') { + out.push('{'); + read = &read[1..]; + continue; + } + + let next = peek_next!(read); + + let var = match next { + '0'..='9' => take_int(&mut read), + 'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read), + _ => return, + }; + + let ident = Ident::new(&var, span); + + let next = peek_next!(read); + + let arg = if cfg!(feature = "std") && next == '}' { + quote_spanned!(span=> , #ident.__displaydoc_display()) + } else { + quote_spanned!(span=> , #ident) + }; + + args.extend(arg); + } + + out += read; + self.fmt = LitStr::new(&out, self.fmt.span()); + self.args = args; + } +} + +fn take_int(read: &mut &str) -> String { + let mut int = String::new(); + int.push('_'); + for (i, ch) in read.char_indices() { + match ch { + '0'..='9' => int.push(ch), + _ => { + *read = &read[i..]; + break; + } + } + } + int +} + +fn take_ident(read: &mut &str) -> String { + let mut ident = String::new(); + for (i, ch) in read.char_indices() { + match ch { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch), + _ => { + *read = &read[i..]; + break; + } + } + } + ident +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + use proc_macro2::Span; + + fn assert(input: &str, fmt: &str, args: &str) { + let mut display = Display { + fmt: LitStr::new(input, Span::call_site()), + args: TokenStream::new(), + }; + display.expand_shorthand(); + assert_eq!(fmt, display.fmt.value()); + assert_eq!(args, display.args.to_string()); + } + + #[test] + fn test_expand() { + assert("fn main() {{ }}", "fn main() {{ }}", ""); + } + + #[test] + #[cfg_attr(not(feature = "std"), ignore)] + fn test_std_expand() { + assert( + "{v} {v:?} {0} {0:?}", + "{} {:?} {} {:?}", + ", v . __displaydoc_display () , v , _0 . __displaydoc_display () , _0", + ); + assert("error {var}", "error {}", ", var . __displaydoc_display ()"); + + assert( + "error {var1}", + "error {}", + ", var1 . __displaydoc_display ()", + ); + + assert( + "error {var1var}", + "error {}", + ", var1var . __displaydoc_display ()", + ); + + assert( + "The path {0}", + "The path {}", + ", _0 . __displaydoc_display ()", + ); + assert("The path {0:?}", "The path {:?}", ", _0"); + } + + #[test] + #[cfg_attr(feature = "std", ignore)] + fn test_nostd_expand() { + assert( + "{v} {v:?} {0} {0:?}", + "{} {:?} {} {:?}", + ", v , v , _0 , _0", + ); + assert("error {var}", "error {}", ", var"); + + assert("The path {0}", "The path {}", ", _0"); + assert("The path {0:?}", "The path {:?}", ", _0"); + + assert("error {var1}", "error {}", ", var1"); + + assert("error {var1var}", "error {}", ", var1var"); + } +} |