From 8cdfa445d6629ffef4cb84967ff7017654045bc2 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 18:36:06 -0600 Subject: chore: add vendor directory --- vendor/thiserror-impl/src/attr.rs | 358 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 vendor/thiserror-impl/src/attr.rs (limited to 'vendor/thiserror-impl/src/attr.rs') diff --git a/vendor/thiserror-impl/src/attr.rs b/vendor/thiserror-impl/src/attr.rs new file mode 100644 index 00000000..7ad83e02 --- /dev/null +++ b/vendor/thiserror-impl/src/attr.rs @@ -0,0 +1,358 @@ +use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; +use std::collections::BTreeSet as Set; +use syn::parse::discouraged::Speculative; +use syn::parse::{End, ParseStream}; +use syn::{ + braced, bracketed, parenthesized, token, Attribute, Error, ExprPath, Ident, Index, LitFloat, + LitInt, LitStr, Meta, Result, Token, +}; + +pub struct Attrs<'a> { + pub display: Option>, + pub source: Option>, + pub backtrace: Option<&'a Attribute>, + pub from: Option>, + pub transparent: Option>, + pub fmt: Option>, +} + +#[derive(Clone)] +pub struct Display<'a> { + pub original: &'a Attribute, + pub fmt: LitStr, + pub args: TokenStream, + pub requires_fmt_machinery: bool, + pub has_bonus_display: bool, + pub infinite_recursive: bool, + pub implied_bounds: Set<(usize, Trait)>, + pub bindings: Vec<(Ident, TokenStream)>, +} + +#[derive(Copy, Clone)] +pub struct Source<'a> { + pub original: &'a Attribute, + pub span: Span, +} + +#[derive(Copy, Clone)] +pub struct From<'a> { + pub original: &'a Attribute, + pub span: Span, +} + +#[derive(Copy, Clone)] +pub struct Transparent<'a> { + pub original: &'a Attribute, + pub span: Span, +} + +#[derive(Clone)] +pub struct Fmt<'a> { + pub original: &'a Attribute, + pub path: ExprPath, +} + +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum Trait { + Debug, + Display, + Octal, + LowerHex, + UpperHex, + Pointer, + Binary, + LowerExp, + UpperExp, +} + +pub fn get(input: &[Attribute]) -> Result { + let mut attrs = Attrs { + display: None, + source: None, + backtrace: None, + from: None, + transparent: None, + fmt: None, + }; + + for attr in input { + if attr.path().is_ident("error") { + parse_error_attribute(&mut attrs, attr)?; + } else if attr.path().is_ident("source") { + attr.meta.require_path_only()?; + if attrs.source.is_some() { + return Err(Error::new_spanned(attr, "duplicate #[source] attribute")); + } + let span = (attr.pound_token.span) + .join(attr.bracket_token.span.join()) + .unwrap_or(attr.path().get_ident().unwrap().span()); + attrs.source = Some(Source { + original: attr, + span, + }); + } else if attr.path().is_ident("backtrace") { + attr.meta.require_path_only()?; + if attrs.backtrace.is_some() { + return Err(Error::new_spanned(attr, "duplicate #[backtrace] attribute")); + } + attrs.backtrace = Some(attr); + } else if attr.path().is_ident("from") { + match attr.meta { + Meta::Path(_) => {} + Meta::List(_) | Meta::NameValue(_) => { + // Assume this is meant for derive_more crate or something. + continue; + } + } + if attrs.from.is_some() { + return Err(Error::new_spanned(attr, "duplicate #[from] attribute")); + } + let span = (attr.pound_token.span) + .join(attr.bracket_token.span.join()) + .unwrap_or(attr.path().get_ident().unwrap().span()); + attrs.from = Some(From { + original: attr, + span, + }); + } + } + + Ok(attrs) +} + +fn parse_error_attribute<'a>(attrs: &mut Attrs<'a>, attr: &'a Attribute) -> Result<()> { + mod kw { + syn::custom_keyword!(transparent); + syn::custom_keyword!(fmt); + } + + attr.parse_args_with(|input: ParseStream| { + let lookahead = input.lookahead1(); + let fmt = if lookahead.peek(LitStr) { + input.parse::()? + } else if lookahead.peek(kw::transparent) { + let kw: kw::transparent = input.parse()?; + if attrs.transparent.is_some() { + return Err(Error::new_spanned( + attr, + "duplicate #[error(transparent)] attribute", + )); + } + attrs.transparent = Some(Transparent { + original: attr, + span: kw.span, + }); + return Ok(()); + } else if lookahead.peek(kw::fmt) { + input.parse::()?; + input.parse::()?; + let path: ExprPath = input.parse()?; + if attrs.fmt.is_some() { + return Err(Error::new_spanned( + attr, + "duplicate #[error(fmt = ...)] attribute", + )); + } + attrs.fmt = Some(Fmt { + original: attr, + path, + }); + return Ok(()); + } else { + return Err(lookahead.error()); + }; + + let args = if input.is_empty() || input.peek(Token![,]) && input.peek2(End) { + input.parse::>()?; + TokenStream::new() + } else { + parse_token_expr(input, false)? + }; + + let requires_fmt_machinery = !args.is_empty(); + + let display = Display { + original: attr, + fmt, + args, + requires_fmt_machinery, + has_bonus_display: false, + infinite_recursive: false, + implied_bounds: Set::new(), + bindings: Vec::new(), + }; + if attrs.display.is_some() { + return Err(Error::new_spanned( + attr, + "only one #[error(...)] attribute is allowed", + )); + } + attrs.display = Some(display); + Ok(()) + }) +} + +fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result { + let mut tokens = Vec::new(); + while !input.is_empty() { + if input.peek(token::Group) { + let group: TokenTree = input.parse()?; + tokens.push(group); + begin_expr = false; + continue; + } + + if begin_expr && input.peek(Token![.]) { + if input.peek2(Ident) { + input.parse::()?; + begin_expr = false; + continue; + } else if input.peek2(LitInt) { + input.parse::()?; + let int: Index = input.parse()?; + tokens.push({ + let ident = format_ident!("_{}", int.index, span = int.span); + TokenTree::Ident(ident) + }); + begin_expr = false; + continue; + } else if input.peek2(LitFloat) { + let ahead = input.fork(); + ahead.parse::()?; + let float: LitFloat = ahead.parse()?; + let repr = float.to_string(); + let mut indices = repr.split('.').map(syn::parse_str::); + if let (Some(Ok(first)), Some(Ok(second)), None) = + (indices.next(), indices.next(), indices.next()) + { + input.advance_to(&ahead); + tokens.push({ + let ident = format_ident!("_{}", first, span = float.span()); + TokenTree::Ident(ident) + }); + tokens.push({ + let mut punct = Punct::new('.', Spacing::Alone); + punct.set_span(float.span()); + TokenTree::Punct(punct) + }); + tokens.push({ + let mut literal = Literal::u32_unsuffixed(second.index); + literal.set_span(float.span()); + TokenTree::Literal(literal) + }); + begin_expr = false; + continue; + } + } + } + + begin_expr = input.peek(Token![break]) + || input.peek(Token![continue]) + || input.peek(Token![if]) + || input.peek(Token![in]) + || input.peek(Token![match]) + || input.peek(Token![mut]) + || input.peek(Token![return]) + || input.peek(Token![while]) + || input.peek(Token![+]) + || input.peek(Token![&]) + || input.peek(Token![!]) + || input.peek(Token![^]) + || input.peek(Token![,]) + || input.peek(Token![/]) + || input.peek(Token![=]) + || input.peek(Token![>]) + || input.peek(Token![<]) + || input.peek(Token![|]) + || input.peek(Token![%]) + || input.peek(Token![;]) + || input.peek(Token![*]) + || input.peek(Token![-]); + + let token: TokenTree = if input.peek(token::Paren) { + let content; + let delimiter = parenthesized!(content in input); + let nested = parse_token_expr(&content, true)?; + let mut group = Group::new(Delimiter::Parenthesis, nested); + group.set_span(delimiter.span.join()); + TokenTree::Group(group) + } else if input.peek(token::Brace) { + let content; + let delimiter = braced!(content in input); + let nested = parse_token_expr(&content, true)?; + let mut group = Group::new(Delimiter::Brace, nested); + group.set_span(delimiter.span.join()); + TokenTree::Group(group) + } else if input.peek(token::Bracket) { + let content; + let delimiter = bracketed!(content in input); + let nested = parse_token_expr(&content, true)?; + let mut group = Group::new(Delimiter::Bracket, nested); + group.set_span(delimiter.span.join()); + TokenTree::Group(group) + } else { + input.parse()? + }; + tokens.push(token); + } + Ok(TokenStream::from_iter(tokens)) +} + +impl ToTokens for Display<'_> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if self.infinite_recursive { + let span = self.fmt.span(); + tokens.extend(quote_spanned! {span=> + #[warn(unconditional_recursion)] + fn _fmt() { _fmt() } + }); + } + + let fmt = &self.fmt; + let args = &self.args; + + // Currently `write!(f, "text")` produces less efficient code than + // `f.write_str("text")`. We recognize the case when the format string + // has no braces and no interpolated values, and generate simpler code. + let write = if self.requires_fmt_machinery { + quote! { + ::core::write!(__formatter, #fmt #args) + } + } else { + quote! { + __formatter.write_str(#fmt) + } + }; + + tokens.extend(if self.bindings.is_empty() { + write + } else { + let locals = self.bindings.iter().map(|(local, _value)| local); + let values = self.bindings.iter().map(|(_local, value)| value); + quote! { + match (#(#values,)*) { + (#(#locals,)*) => #write + } + } + }); + } +} + +impl ToTokens for Trait { + fn to_tokens(&self, tokens: &mut TokenStream) { + let trait_name = match self { + Trait::Debug => "Debug", + Trait::Display => "Display", + Trait::Octal => "Octal", + Trait::LowerHex => "LowerHex", + Trait::UpperHex => "UpperHex", + Trait::Pointer => "Pointer", + Trait::Binary => "Binary", + Trait::LowerExp => "LowerExp", + Trait::UpperExp => "UpperExp", + }; + let ident = Ident::new(trait_name, Span::call_site()); + tokens.extend(quote!(::core::fmt::#ident)); + } +} -- cgit v1.2.3