const_panic_proc_macros-0.2.12/.cargo_vcs_info.json0000644000000001650000000000100160070ustar { "git": { "sha1": "63ab8eb44138e793fac5c843038727ccb206e58e" }, "path_in_vcs": "const_panic_proc_macros" }const_panic_proc_macros-0.2.12/Cargo.toml0000644000000024320000000000100140040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "const_panic_proc_macros" version = "0.2.12" authors = ["rodrimati1992 "] build = false include = [ "Cargo.toml", "src/**/*.rs", "../README.md", "LICENSE-ZLIB.md", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Implementation detail of the `const_panic` crate" readme = false keywords = [] categories = [] license = "Zlib" repository = "https://github.com/rodrimati1992/const_panic/" [lib] name = "const_panic_proc_macros" path = "src/lib.rs" proc-macro = true [dependencies.proc-macro2] version = "1.0.86" [dependencies.quote] version = "1.0.37" [dependencies.syn] version = "2.0" [dependencies.unicode-xid] version = "0.2.5" [badges.travis-ci] repository = "rodrimati1992/const_format_crates/" const_panic_proc_macros-0.2.12/Cargo.toml.orig000064400000000000000000000011531046102023000174640ustar 00000000000000[package] name = "const_panic_proc_macros" version = "0.2.12" authors = ["rodrimati1992 "] edition = "2021" license = "Zlib" description = "Implementation detail of the `const_panic` crate" keywords = [] categories = [] repository = "https://github.com/rodrimati1992/const_panic/" include = [ "Cargo.toml", "src/**/*.rs", "../README.md", "LICENSE-ZLIB.md", ] [badges] travis-ci = { repository = "rodrimati1992/const_format_crates/" } [lib] proc-macro = true [dependencies] quote = "1.0.37" proc-macro2 = "1.0.86" unicode-xid = "0.2.5" [dependencies.syn] version = "2.0" const_panic_proc_macros-0.2.12/LICENSE-ZLIB.md000064400000000000000000000015271046102023000167440ustar 00000000000000Copyright (c) 2021 Matias Rodriguez. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.const_panic_proc_macros-0.2.12/src/datastructure.rs000064400000000000000000000172051046102023000206310ustar 00000000000000use syn::{ self, Attribute, Data, DeriveInput, Field as SynField, Fields as SynFields, Generics, Ident, Type, Visibility, }; use quote::ToTokens; use proc_macro2::TokenStream; use alloc::format; use core::fmt::{self, Display}; use alloc::vec::Vec; ////////////////////////////////////////////////////////////////////////////// /// A type definition(enum,struct,union). #[derive(Clone)] pub struct DataStructure<'a> { pub vis: &'a Visibility, pub name: &'a Ident, pub generics: &'a Generics, pub attrs: &'a [Attribute], /// Whether this is a struct/union/enum. pub data_variant: DataVariant, // the amount of lifetime parameters in the type pub lifetime_count: usize, /// The variants in the type definition. /// /// If it is a struct or a union this only has 1 element. pub variants: Vec>, } impl<'a> DataStructure<'a> { pub fn new(ast: &'a DeriveInput) -> Self { let name = &ast.ident; let data_variant: DataVariant; let mut variants = Vec::new(); match &ast.data { Data::Enum(enum_) => { for (variant, var) in enum_.variants.iter().enumerate() { variants.push(Struct::new( StructParams { variant: variant, attrs: &var.attrs, name: &var.ident, }, &var.fields, )); } data_variant = DataVariant::Enum; } Data::Struct(struct_) => { variants.push(Struct::new( StructParams { variant: 0, attrs: &[], name: name, }, &struct_.fields, )); data_variant = DataVariant::Struct; } Data::Union(union_) => { let fields = Some(&union_.fields.named); let sk = StructKind::Braced; let vari = Struct::with_fields( StructParams { variant: 0, attrs: &[], name: name, }, sk, fields, ); variants.push(vari); data_variant = DataVariant::Union; } } Self { vis: &ast.vis, name, attrs: &ast.attrs, generics: &ast.generics, data_variant, lifetime_count: ast.generics.lifetimes().count(), variants, } } } ////////////////////////////////////////////////////////////////////////////// /// Whether the struct is tupled or not. #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] pub enum StructKind { /// structs declared using the `struct Name( ... ) syntax. Tupled, /// structs declared using the `struct Name{ ... }` or `struct name;` syntaxes Braced, } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] pub enum DataVariant { Struct, Enum, Union, } #[derive(Copy, Clone)] pub struct FieldIndex { pub variant: usize, pub pos: usize, } ////////////////////////////////////////////////////////////////////////////// #[derive(Copy, Clone)] struct StructParams<'a> { variant: usize, attrs: &'a [Attribute], name: &'a Ident, } /// A struct/union or a variant of an enum. #[derive(Clone)] pub struct Struct<'a> { /// The attributes of this `Struct`. /// /// If this is a struct/union:these is the same as DataStructure.attrs. /// /// If this is an enum:these are the attributes on the variant. pub attrs: &'a [Attribute], /// The name of this `Struct`. /// /// If this is a struct/union:these is the same as DataStructure.name. /// /// If this is an enum:this is the name of the variant. pub name: &'a Ident, pub kind: StructKind, pub fields: Vec>, _priv: (), } impl<'a> Struct<'a> { fn new(p: StructParams<'a>, fields: &'a SynFields) -> Self { let kind = match *fields { SynFields::Named { .. } => StructKind::Braced, SynFields::Unnamed { .. } => StructKind::Tupled, SynFields::Unit { .. } => StructKind::Braced, }; let fields = match fields { SynFields::Named(f) => Some(&f.named), SynFields::Unnamed(f) => Some(&f.unnamed), SynFields::Unit => None, }; Self::with_fields(p, kind, fields) } fn with_fields(p: StructParams<'a>, kind: StructKind, fields: Option) -> Self where I: IntoIterator, { let fields = match fields { Some(x) => Field::from_iter(p, x), None => Vec::new(), }; Self { attrs: p.attrs, name: p.name, kind, fields, _priv: (), } } } ////////////////////////////////////////////////////////////////////////////// /// Represent a struct field /// #[derive(Clone)] pub struct Field<'a> { pub index: FieldIndex, pub attrs: &'a [Attribute], /// identifier for the field,which is either an index(in a tuple struct) or a name. pub ident: FieldIdent<'a>, pub pattern_ident: Ident, pub ty: &'a Type, } impl<'a> Field<'a> { fn new(index: FieldIndex, field: &'a SynField) -> Self { let span; let ident = match field.ident.as_ref() { Some(ident) => { span = ident.span(); FieldIdent::Named(ident) } None => { span = syn::spanned::Spanned::span(&field.ty); FieldIdent::new_index(index.pos) } }; let pattern_ident = Ident::new(&format!("f{}_7ac4rtizw8q", ident), span); Self { index, attrs: &field.attrs, ident, pattern_ident, ty: &field.ty, } } /// Gets the identifier of this field as an `&Ident`. #[allow(dead_code)] pub fn pattern_ident(&self) -> &Ident { &self.pattern_ident } fn from_iter(p: StructParams<'a>, fields: I) -> Vec where I: IntoIterator, { fields .into_iter() .enumerate() .map(|(pos, f)| { let fi = FieldIndex { variant: p.variant, pos, }; Field::new(fi, f) }) .collect() } } ////////////////////////////////////////////////////////////////////////////// #[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum FieldIdent<'a> { Index(usize), Named(&'a Ident), } impl<'a> Display for FieldIdent<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { FieldIdent::Index(x) => Display::fmt(x, f), FieldIdent::Named(x) => Display::fmt(x, f), } } } impl<'a> ToTokens for FieldIdent<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { match *self { FieldIdent::Index(ind) => syn::Index::from(ind).to_tokens(tokens), FieldIdent::Named(name) => name.to_tokens(tokens), } } } impl<'a> FieldIdent<'a> { fn new_index(index: usize) -> Self { FieldIdent::Index(index) } } ////////////////////////////////////////////////////////////////////////////// #[derive(Copy, Clone, PartialEq)] pub(super) enum GenParamKind { Lifetime, Type, Const, } const_panic_proc_macros-0.2.12/src/derive_debug/attribute_parsing.rs000064400000000000000000000216421046102023000241110ustar 00000000000000use crate::{ datastructure::{DataStructure, DataVariant, Field, GenParamKind, Struct}, syntax::ImplHeader, utils::{ParseBufferExt, SynResultExt}, TokenStream2, }; use syn::{ parse::{ParseBuffer, Parser}, Attribute, GenericParam, Ident, Token, }; use quote::{quote, ToTokens}; use alloc::vec::Vec; use core::marker::PhantomData; mod keyword { syn::custom_keyword!(display_fmt); syn::custom_keyword!(panicvals_lower_bound); syn::custom_keyword!(debug_print); syn::custom_keyword!(ignore); } #[derive(Copy, Clone)] pub(crate) enum ParseCtx<'a> { Container, Variant(usize, &'a Struct<'a>), Field(&'a Field<'a>), } struct ParsedAttributes<'a> { debug_print: bool, crate_path: syn::Path, display_fmt: Option, panicvals_lower_bound: Option, impls: Vec, gen_params_props: Vec>, type_const_params: Vec, _marker: PhantomData<&'a ()>, } pub(super) struct Configuration<'a> { pub(super) debug_print: bool, pub(super) crate_path: syn::Path, pub(super) display_fmt: Option, pub(super) panicvals_lower_bound: Option, pub(super) impls: Vec, pub(super) gen_params_props: Vec>, _marker: PhantomData<&'a ()>, } pub(super) fn parse_attributes<'a>(ds: &'a DataStructure<'a>) -> syn::Result> { let mut this = ParsedAttributes { debug_print: false, crate_path: syn::parse_quote!(::const_panic), display_fmt: None, panicvals_lower_bound: None, impls: Vec::new(), gen_params_props: ds .generics .params .iter() .map(|ga| { let (kind, ignored) = match ga { GenericParam::Lifetime { .. } => { (GenParamKind::Lifetime, GenParamIgnorance::Ignored) } GenericParam::Type { .. } => (GenParamKind::Type, GenParamIgnorance::Included), GenericParam::Const { .. } => (GenParamKind::Const, GenParamIgnorance::Ignored), }; GenParamProps { kind, ignored } }) .collect(), type_const_params: ds .generics .params .iter() .filter_map(|ga| match ga { GenericParam::Lifetime { .. } => None, GenericParam::Type(x) => Some(x.ident.clone()), GenericParam::Const(x) => Some(x.ident.clone()), }) .collect(), _marker: PhantomData, }; let mut res = syn::Result::Ok(()); for attr in ds.attrs { res.combine_err(parse_attribute(&mut this, ds, ParseCtx::Container, attr)); } if ds.data_variant == DataVariant::Enum { for (i, v) in ds.variants.iter().enumerate() { let ctx = ParseCtx::Variant(i, v); for attr in v.attrs { res.combine_err(parse_attribute(&mut this, ds, ctx, attr)); } } } for v in &ds.variants { for f in &v.fields { for attr in f.attrs { res.combine_err(parse_attribute(&mut this, ds, ParseCtx::Field(f), attr)); } } } res?; finish(this, ds) } fn parse_attribute<'a>( this: &mut ParsedAttributes<'a>, ds: &'a DataStructure<'a>, ctx: ParseCtx<'a>, attribute: &Attribute, ) -> syn::Result<()> { if attribute.path().is_ident("pfmt") { let closure = move |input: &'_ ParseBuffer<'_>| parse_helper_attribute(this, ds, ctx, input); if attribute.to_token_stream().is_empty() { Parser::parse2(closure, crate::TokenStream2::new()) } else { attribute.parse_args_with(closure) } } else { Ok(()) } } fn parse_helper_attribute<'a>( this: &mut ParsedAttributes<'a>, ds: &'a DataStructure<'a>, ctx: ParseCtx<'a>, input: &'_ ParseBuffer<'_>, ) -> syn::Result<()> { let empty = &crate::utils::Empty(input.span()); if let Some(_) = input.peek_parse(keyword::debug_print)? { check_is_container(&ctx, empty)?; this.debug_print = true; } else if let Some(_) = input.peek_parse(keyword::display_fmt)? { check_is_container(&ctx, empty)?; input.parse::()?; this.display_fmt = Some(syn::Expr::Verbatim(input.parse()?)); } else if let Some(_) = input.peek_parse(keyword::panicvals_lower_bound)? { check_is_container(&ctx, empty)?; input.parse::()?; this.panicvals_lower_bound = Some(syn::Expr::Verbatim(input.parse()?)); } else if let Some(_) = input.peek_parse(Token!(crate))? { check_is_container(&ctx, empty)?; input.parse::()?; this.crate_path = input.parse::()?; } else if input.peek(Token!(impl)) { check_is_container(&ctx, empty)?; this.impls.push(ImplHeader::parse(ds.name, input)?); } else if let Some(_) = input.peek_parse(keyword::ignore)? { check_is_container(&ctx, empty)?; let contents; let _ = syn::parenthesized!(contents in input); if contents.is_empty() { return Ok(()); } loop { let ident = contents.parse::()?; let gpi: usize = this .type_const_params .iter() .position(|x| *x == ident) .map(|pos| pos + ds.lifetime_count) .ok_or_else(|| { syn::Error::new(ident.span(), "Expected name of a type or const parameter") })?; let gen_props = &mut this.gen_params_props[gpi]; gen_props.ignored = if let Some(_) = contents.peek_parse(syn::Token!(=))? { let replacement = match gen_props.kind { GenParamKind::Lifetime => unreachable!(), GenParamKind::Type => contents.parse::()?.into_token_stream(), GenParamKind::Const => contents.parse::()?.into_token_stream(), }; GenParamIgnorance::Replaced(replacement) } else { GenParamIgnorance::Ignored }; if contents.is_empty() { break; } else { contents.parse::()?; } } } else { let span = input.parse::()?.span(); return Err(syn::Error::new(span, "Invalid attribute")); } Ok(()) } fn finish<'a>( this: ParsedAttributes<'a>, _ds: &'a DataStructure<'a>, ) -> syn::Result> { let ParsedAttributes { debug_print, crate_path, display_fmt, panicvals_lower_bound, impls, gen_params_props, type_const_params: _, _marker, } = this; Ok(Configuration { debug_print, crate_path, display_fmt, panicvals_lower_bound, impls, gen_params_props, _marker, }) } pub(crate) fn check_is_container( ctx: &ParseCtx<'_>, sp: &dyn syn::spanned::Spanned, ) -> syn::Result<()> { if matches!(ctx, ParseCtx::Container) { Ok(()) } else { Err(syn::Error::new( sp.span(), "Can only use this attribute above the type definition", )) } } pub(super) struct GenParamProps<'a> { pub(super) kind: GenParamKind, pub(super) ignored: GenParamIgnorance<'a>, } pub(super) enum GenParamIgnorance<'a> { Included, Ignored, Replaced(TokenStream2), #[allow(dead_code)] ReplacedB(&'a TokenStream2), } impl<'a> GenParamProps<'a> { #[allow(dead_code)] pub fn reborrow(&self) -> GenParamProps<'_> { GenParamProps { kind: self.kind, ignored: self.ignored.reborrow(), } } pub fn tokenize_arg(&self, arg: &A) -> TokenStream2 where A: ToTokens, { match (self.kind, &self.ignored) { (_, GenParamIgnorance::Included) => arg.to_token_stream(), (GenParamKind::Lifetime, GenParamIgnorance::Ignored) => quote!('_), (GenParamKind::Type, GenParamIgnorance::Ignored) => quote!(()), (GenParamKind::Const, GenParamIgnorance::Ignored) => { quote!({ __cp_bCj7dq3Pud::__::ConstDefault::DEFAULT }) } (_, GenParamIgnorance::Replaced(x)) => x.to_token_stream(), (_, GenParamIgnorance::ReplacedB(x)) => x.to_token_stream(), } } } impl<'a> GenParamIgnorance<'a> { pub fn reborrow(&self) -> GenParamIgnorance<'_> { match self { GenParamIgnorance::Included => GenParamIgnorance::Included, GenParamIgnorance::Ignored => GenParamIgnorance::Ignored, GenParamIgnorance::Replaced(x) => GenParamIgnorance::ReplacedB(x), GenParamIgnorance::ReplacedB(x) => GenParamIgnorance::ReplacedB(*x), } } } const_panic_proc_macros-0.2.12/src/derive_debug/tests.rs000064400000000000000000000115411046102023000215220ustar 00000000000000use crate::test_utils::StrExt; use alloc::string::{String, ToString}; fn process_str(s: &str) -> Result { syn::parse_str(s) .and_then(crate::derive_debug::derive_constdebug_impl) .map(|x| x.to_string()) .map_err(|e| e.to_compile_error().to_string()) } #[test] fn ignored_generic_arguments() { { let s = process_str( r#" #[pfmt(ignore(A, B))] pub struct IgnoredGenericParams<'a, A, B, const X: u32, const Y: char> ( pub &'a u32, pub PhantomData, pub PhantomData, ); "#, ) .unwrap(); assert!( s.consecutive_unspace(&[r#" ; < IgnoredGenericParams< '_, (), (), {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT}, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT} > as __cp_bCj7dq3Pud::PanicFmt >::PV_COUNT ] "#]), "\n{}\n", s, ); } { let s = process_str( r#" #[pfmt(ignore(A, B = u64, X = 100, Y = '_'))] pub struct IgnoredGenericParams<'a, A, B, const X: u32, const Y: char> ( pub &'a u32, pub PhantomData, pub PhantomData, ); "#, ) .unwrap(); assert!( s.consecutive_unspace(&[r#" ; < IgnoredGenericParams< '_, (), u64, 100, '_' > as __cp_bCj7dq3Pud::PanicFmt >::PV_COUNT ] "#]), "\n{}\n", s, ); } } #[test] fn ignored_generic_arguments_and_impl() { let s = process_str( r#" #[pfmt(ignore(A))] #[pfmt(impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u8, H, I>)] #[pfmt(impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u16, H, I>)] #[pfmt(impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u32, H, I>)] pub struct IgnoredAndImpl<'a, A, B, const X: u32, const Y: char> ( pub &'a u32, pub PhantomData, pub PhantomData, ); "#, ) .unwrap(); assert!( s.consecutive_unspace(&[ "impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u8, H, I>", "IgnoredAndImpl< '_, (), u8, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT}, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT} >", ]), "\n{}\n", s, ); assert!( s.consecutive_unspace(&[ "impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u16, H, I>", "IgnoredAndImpl< '_, (), u16, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT}, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT} >", ]), "\n{}\n", s, ); assert!( s.consecutive_unspace(&[ "impl<'b, G, const H: u32, const I: char> IgnoredAndImpl<'b, G, u32, H, I>", "IgnoredAndImpl< '_, (), u32, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT}, {__cp_bCj7dq3Pud::__::ConstDefault::DEFAULT} >", ]), "\n{}\n", s, ); } #[test] fn generic_type_error() { for case in [ r#" pub struct IgnoredAndImpl<'a, A, B, const X: u32, const Y: char> ( pub &'a u32, pub PhantomData, pub PhantomData, ); "#, r#" pub struct IgnoredAndImpl<'a, A, B> ( pub &'a u32, pub PhantomData, pub PhantomData, ); "#, ] { let err = process_str(case).unwrap_err(); assert!( err.consecutive_unspace(&["`#[pfmt(ignore(", "`#[pfmt(impl",]), "\n{}\n", err, ); } } #[test] fn impl_attribute_typename_error() { let input = r#" #[pfmt(impl Baaa)] pub struct Fooo<'a, A> ( pub PhantomData, ); "#; let err = process_str(input).unwrap_err(); assert!(err.consecutive_unspace(&["expected `Fooo`"]), "\n{}\n", err,); } const_panic_proc_macros-0.2.12/src/derive_debug.rs000064400000000000000000000254711046102023000203670ustar 00000000000000use crate::{ datastructure::{DataStructure, DataVariant, GenParamKind, StructKind}, syntax::ImplHeader, }; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use syn::{punctuated::Punctuated, DeriveInput, Ident}; use alloc::{string::ToString, vec::Vec}; use self::attribute_parsing::{Configuration, GenParamIgnorance}; mod attribute_parsing; #[cfg(test)] mod tests; pub(crate) fn derive_constdebug_impl(input: DeriveInput) -> syn::Result { let ds = &DataStructure::new(&input); let config = attribute_parsing::parse_attributes(ds)?; let crate_path = &config.crate_path; let name = ds.name; if config.impls.is_empty() { let not_ignored = config .gen_params_props .iter() .zip(ds.generics.type_params()) .filter(|(x, _)| matches!(x.ignored, GenParamIgnorance::Included)) .map(|(_, tp)| &tp.ident) .collect::>(); if !not_ignored.is_empty() { let not_ignored = not_ignored.into_iter(); let msg = alloc::format!( concat!( "these type parameters were not ignored or replaced with concrete types:\n", " {0}\n", "You must use either or both of these attributes:\n", "- `#[pfmt(ignore({0}))]`:", "if the type parameters are only used in marker types (eg: `PhantomData`).\n", "- `#[pfmt(impl ...)]`:", "To implement panic formatting with concrete types for those type parameters", "(this attribute can be used multiple times to add impls).\n", ), quote!(#(#not_ignored),*) ); return Err(syn::Error::new(Span::call_site(), msg)); } } let (impl_generics, ty_generics, where_clause) = ds.generics.split_for_impl(); let preds = Punctuated::new(); let preds = where_clause.map_or(&preds, |x| &x.predicates).into_iter(); let preds = quote!(#( #preds, )*); let delimiters = ds .variants .iter() .map(|v| match v.kind { StructKind::Tupled => quote!(__cp_bCj7dq3Pud::TypeDelim::Tupled), StructKind::Braced => quote!(__cp_bCj7dq3Pud::TypeDelim::Braced), }) .collect::>(); let mut field_counters = ds.variants.iter().enumerate().map(|(v_index, v)| { let field_amount = v.fields.len(); let field_tys = v.fields.iter().map(|x| x.ty); let delimiter = &delimiters[v_index]; quote!( __cp_bCj7dq3Pud::ComputePvCount { field_amount: #field_amount, summed_pv_count: { 0 #( + <#field_tys as __cp_bCj7dq3Pud::PanicFmt>::PV_COUNT )* }, delimiter: #delimiter, }.call() ) }); let pv_count_init; let match_prefix; match ds.data_variant { DataVariant::Struct => { pv_count_init = field_counters.next().unwrap(); match_prefix = quote!(); } DataVariant::Enum => { pv_count_init = quote!( __cp_bCj7dq3Pud::utils::slice_max_usize(&[ #( #field_counters ),* ]) ); match_prefix = quote!(Self::); } DataVariant::Union => { return Err(syn::Error::new( Span::call_site(), "unions are not supported", )) } } let pv_count_init_lb = match &config.panicvals_lower_bound { Some(lb) => quote!(__cp_bCj7dq3Pud::utils::max_usize(#pv_count_init, #lb)), None => pv_count_init, }; let args_for_inherent_impl = ArgsForInherentImpl { comma_sep: Ident::new("COMMA_SEP", Span::call_site()), comma_term: Ident::new("COMMA_TERM", Span::call_site()), ds, delimiters: &delimiters, match_prefix, }; let single_impl_ihapvcs: ImplHeaderAndPvCountSelf; let vec_impl_ihapvcs: Vec; let impl_ihapvcs: &[ImplHeaderAndPvCountSelf]; if config.impls.is_empty() { let replaced_args = ds .generics .params .iter() .zip(&config.gen_params_props) .map(|(gp, gpp)| gpp.tokenize_arg(gp)); single_impl_ihapvcs = ImplHeaderAndPvCountSelf { impl_header: quote! { impl #impl_generics #name #ty_generics where #preds }, pvcount_self: quote!(#name<#(#replaced_args),*>), }; impl_ihapvcs = core::slice::from_ref(&single_impl_ihapvcs); } else { vec_impl_ihapvcs = config .impls .iter() .map( |ImplHeader { generics, self_args, }| { let (impl_generics, _, where_clause) = generics.split_for_impl(); let additional_preds = Punctuated::new(); let additional_preds = where_clause .map_or(&additional_preds, |x| &x.predicates) .into_iter(); let impl_header = quote! { impl #impl_generics #name #self_args where #( #additional_preds, )* #preds }; let replaced_args = self_args .args .iter() .zip(&config.gen_params_props) .map(|(ga, gpp)| gpp.tokenize_arg(ga)); let pvcount_self = quote!(#name<#(#replaced_args),*>); ImplHeaderAndPvCountSelf { impl_header, pvcount_self, } }, ) .collect(); impl_ihapvcs = &vec_impl_ihapvcs; } let impl_ihapvcs_mapped = impl_ihapvcs .iter() .map(|impl_ihapvc| emit_inherent_impl(&config, impl_ihapvc, &args_for_inherent_impl)); let ty_params = ds .generics .type_params() .zip( config .gen_params_props .iter() .filter(|x| matches!(x.kind, GenParamKind::Type)), ) .filter(|(_, prop)| matches!(prop.ignored, GenParamIgnorance::Included)) .map(|(t, _)| &t.ident); let ret = quote! { use #crate_path as __cp_bCj7dq3Pud; impl #impl_generics __cp_bCj7dq3Pud::PanicFmt for #name #ty_generics where #preds #(#ty_params: __cp_bCj7dq3Pud::PanicFmt,)* { type This = Self; type Kind = __cp_bCj7dq3Pud::IsCustomType; const PV_COUNT: __cp_bCj7dq3Pud::__::usize = #pv_count_init_lb; } #(#impl_ihapvcs_mapped)* }; let ret = quote!( const _: () = { #ret }; ); if config.debug_print { panic!("\n\n\n{}\n\n\n", ret); } Ok(ret) } struct ImplHeaderAndPvCountSelf { impl_header: TokenStream2, // The Self type with generic arguments replaced so that they can be used // to get the PV_COUNT associated constant pvcount_self: TokenStream2, } struct ArgsForInherentImpl<'a> { comma_sep: Ident, comma_term: Ident, ds: &'a DataStructure<'a>, delimiters: &'a [TokenStream2], match_prefix: TokenStream2, } fn emit_inherent_impl( Configuration { display_fmt, .. }: &Configuration<'_>, ImplHeaderAndPvCountSelf { impl_header, pvcount_self, }: &ImplHeaderAndPvCountSelf, ArgsForInherentImpl { comma_sep, comma_term, ds, delimiters, match_prefix, }: &ArgsForInherentImpl<'_>, ) -> TokenStream2 { let get_pv_count = quote!(<#pvcount_self as __cp_bCj7dq3Pud::PanicFmt>::PV_COUNT); let branches = ds.variants.iter().enumerate().map(|(v_index, v)| { let vname = v.name; let vsname = vname.to_string(); let last_field_pos = v.fields.len().saturating_sub(1); let field_names = v.fields.iter().map(|f| &f.ident); let field_patia = v.fields.iter().map(|f| &f.pattern_ident); let delimiter = &delimiters[v_index]; let field_fmt = v.fields.iter().map(|f| { let field_patib = &f.pattern_ident; let comma = if f.index.pos == last_field_pos { &comma_term } else { &comma_sep }; let field_name_colon = if let StructKind::Braced = v.kind { let fname = ::alloc::format!("{}: ", f.ident); quote!( &[__cp_bCj7dq3Pud::PanicVal::write_str(#fname)], ) } else { TokenStream2::new() }; quote!( #field_name_colon &__cp_bCj7dq3Pud::PanicFmt::PROOF .infer(#field_patib) .coerce(#field_patib) .to_panicvals(fmtarg), &__cp_bCj7dq3Pud::fmt::#comma .to_panicvals(fmtarg), ) }); if v.fields.is_empty() { quote!( #match_prefix #vname { #(#field_names: #field_patia,)* } => { __cp_bCj7dq3Pud::__::flatten_panicvals::<{#get_pv_count}>(&[&[ __cp_bCj7dq3Pud::PanicVal::write_str(#vsname) ]]) } ) } else { quote!(#match_prefix #vname { #(#field_names: #field_patia,)* } => { let (open, close) = #delimiter.get_open_and_close(); __cp_bCj7dq3Pud::__::flatten_panicvals::<{#get_pv_count}>(&[ &[ __cp_bCj7dq3Pud::PanicVal::write_str(#vsname), open.to_panicval(fmtarg) ], #( #field_fmt )* &close.to_panicvals(fmtarg.unindent()), ]) }) } }); let ondebug = quote! ( fmtarg = fmtarg.indent(); match self { #(#branches)* } ); let dofmt = match display_fmt { Some(display_fmt_) => quote!( match fmtarg.fmt_kind { __cp_bCj7dq3Pud::fmt::FmtKind::Display => (#display_fmt_)(self, fmtarg), _ => { #ondebug } } ), None => ondebug, }; quote!( #impl_header { pub const fn to_panicvals( &self, mut fmtarg: __cp_bCj7dq3Pud::FmtArg, ) -> [__cp_bCj7dq3Pud::PanicVal<'_>; #get_pv_count] { #dofmt } } ) } const_panic_proc_macros-0.2.12/src/lib.rs000064400000000000000000000010001046102023000164670ustar 00000000000000#![no_std] extern crate alloc; #[cfg(test)] extern crate std; use proc_macro::TokenStream as TokenStream1; use proc_macro2::TokenStream as TokenStream2; mod datastructure; mod derive_debug; mod syntax; mod utils; #[cfg(test)] mod test_utils; #[proc_macro_derive(PanicFmt, attributes(pfmt))] pub fn derive_const_debug(input: TokenStream1) -> TokenStream1 { syn::parse(input) .and_then(derive_debug::derive_constdebug_impl) .unwrap_or_else(|e| e.to_compile_error()) .into() } const_panic_proc_macros-0.2.12/src/syntax.rs000064400000000000000000000016631046102023000172660ustar 00000000000000use proc_macro2::TokenTree as TokenTree2; use syn::{parse::ParseStream, token::Impl, Generics, Ident}; use alloc::format; //////////////////////////////////////////////////////////////////////////////// pub(crate) struct ImplHeader { pub(crate) generics: Generics, pub(crate) self_args: syn::AngleBracketedGenericArguments, } impl ImplHeader { pub(crate) fn parse<'a>(name: &'a Ident, input: ParseStream<'_>) -> syn::Result { let _ = input.parse::()?; let mut generics = input.parse::()?; input.step(|cursor| match cursor.token_tree() { Some((TokenTree2::Ident(ident), cursor)) if *name == ident => Ok(((), cursor)), _ => Err(cursor.error(format!("expected `{}`", name))), })?; let self_args = input.parse()?; generics.where_clause = input.parse()?; Ok(Self { generics, self_args, }) } } const_panic_proc_macros-0.2.12/src/test_utils.rs000064400000000000000000000025171046102023000201360ustar 00000000000000use alloc::{string::String, vec::Vec}; pub(crate) fn remove_whitespaces(x: &str) -> String { x.chars().filter(|x| !x.is_whitespace()).collect() } pub trait StrExt { fn as_str(&self) -> &str; /// Checks that these needles exist consequtively in self. /// /// Example: `"hello world".consecutive_in_set(&["he", "wor"])` returns `true`. /// Example: `"hello world".consecutive_in_set(&["wor", "he"])` returns `false`. fn consecutive_in_self>(&self, needles: &[S]) -> bool { let mut rem = self.as_str(); for needle in needles { let needle: &str = needle.as_ref(); rem = match rem.find(needle) { Some(next) => &rem[next + needle.len()..], None => return false, }; } true } fn consecutive_unspace(&self, needles: &[&str]) -> bool { let rem = remove_whitespaces(self.as_str()); let needles = needles .iter() .map(|x| remove_whitespaces(x)) .collect::>(); ::std::dbg!(&needles); rem.consecutive_in_self(&needles) } } impl StrExt for str { #[inline(always)] fn as_str(&self) -> &str { self } } impl StrExt for alloc::string::String { #[inline(always)] fn as_str(&self) -> &str { self } } const_panic_proc_macros-0.2.12/src/utils.rs000064400000000000000000000021421046102023000170710ustar 00000000000000use syn::parse::{Parse, ParseBuffer, Peek}; use quote::TokenStreamExt; pub struct Empty(pub proc_macro2::Span); impl quote::ToTokens for Empty { fn to_tokens(&self, ts: &mut crate::TokenStream2) { ts.append_all(quote::quote_spanned!(self.0 => ())); } } pub(crate) trait SynResultExt { fn combine_err(&mut self, res: syn::Result); } impl SynResultExt for syn::Result { fn combine_err(&mut self, res: syn::Result) { if let Err(err) = res { match self { this @ Ok(_) => *this = Err(err), Err(e) => e.combine(err), } } } } pub(crate) trait ParseBufferExt { fn peek_parse(&self, f: F) -> Result, syn::Error> where F: FnOnce(X) -> P + Peek, P: Parse; } impl ParseBufferExt for ParseBuffer<'_> { fn peek_parse(&self, f: F) -> Result, syn::Error> where F: FnOnce(X) -> P + Peek, P: Parse, { if self.peek(f) { self.parse::

().map(Some) } else { Ok(None) } } }