@@ -1002,8 +1002,8 @@ pub mod span;
10021002pub mod __macro_support {
10031003 pub use crate :: callsite:: { Callsite , Registration } ;
10041004 use crate :: { collect:: Interest , Metadata } ;
1005- use core:: fmt;
10061005 use core:: sync:: atomic:: Ordering ;
1006+ use core:: { fmt, str} ;
10071007
10081008 #[ cfg( feature = "portable-atomic" ) ]
10091009 use portable_atomic:: AtomicU8 ;
@@ -1014,7 +1014,7 @@ pub mod __macro_support {
10141014 // Re-export the `core` functions that are used in macros. This allows
10151015 // a crate to be named `core` and avoid name clashes.
10161016 // See here: https://github.com/tokio-rs/tracing/issues/2761
1017- pub use core:: { concat, file, format_args, iter:: Iterator , line, option:: Option } ;
1017+ pub use core:: { concat, file, format_args, iter:: Iterator , line, option:: Option , stringify } ;
10181018
10191019 /// Callsite implementation used by macro-generated code.
10201020 ///
@@ -1202,6 +1202,66 @@ pub mod __macro_support {
12021202 . finish ( )
12031203 }
12041204 }
1205+
1206+ /// Implementation detail used for constructing FieldSet names from raw
1207+ /// identifiers. In `info!(..., r#type = "...")` the macro would end up
1208+ /// constructing a name equivalent to `FieldName(*b"type")`.
1209+ pub struct FieldName < const N : usize > ( [ u8 ; N ] ) ;
1210+
1211+ impl < const N : usize > FieldName < N > {
1212+ /// Convert `"prefix.r#keyword.suffix"` to `b"prefix.keyword.suffix"`.
1213+ pub const fn new ( input : & str ) -> Self {
1214+ let input = input. as_bytes ( ) ;
1215+ let mut output = [ 0u8 ; N ] ;
1216+ let mut read = 0 ;
1217+ let mut write = 0 ;
1218+ while read < input. len ( ) {
1219+ if read + 1 < input. len ( ) && input[ read] == b'r' && input[ read + 1 ] == b'#' {
1220+ read += 2 ;
1221+ }
1222+ output[ write] = input[ read] ;
1223+ read += 1 ;
1224+ write += 1 ;
1225+ }
1226+ assert ! ( write == N ) ;
1227+ Self ( output)
1228+ }
1229+
1230+ pub const fn as_str ( & self ) -> & str {
1231+ // SAFETY: Because of the private visibility of self.0, it must have
1232+ // been computed by Self::new. So these bytes are all of the bytes
1233+ // of some original valid UTF-8 string, but with "r#" substrings
1234+ // removed, which cannot have produced invalid UTF-8.
1235+ unsafe { str:: from_utf8_unchecked ( self . 0 . as_slice ( ) ) }
1236+ }
1237+ }
1238+
1239+ impl FieldName < 0 > {
1240+ /// For `"prefix.r#keyword.suffix"` compute `"prefix.keyword.suffix".len()`.
1241+ pub const fn len ( input : & str ) -> usize {
1242+ // Count occurrences of "r#"
1243+ let mut raw = 0 ;
1244+
1245+ let mut i = 0 ;
1246+ while i < input. len ( ) {
1247+ if input. as_bytes ( ) [ i] == b'#' {
1248+ raw += 1 ;
1249+ }
1250+ i += 1 ;
1251+ }
1252+
1253+ input. len ( ) - 2 * raw
1254+ }
1255+ }
1256+
1257+ impl < const N : usize > fmt:: Debug for FieldName < N > {
1258+ fn fmt ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1259+ formatter
1260+ . debug_tuple ( "FieldName" )
1261+ . field ( & self . as_str ( ) )
1262+ . finish ( )
1263+ }
1264+ }
12051265}
12061266
12071267#[ cfg( feature = "log" ) ]
0 commit comments