Skip to content

Commit a260608

Browse files
committed
Improve privacy and reduce redundancy in IdentStr code
The original purpose of most of this refactoring was actually to cache the generated `TokenStream`s, since constantly regenerating these takes a long time (an extra ~20000ns per call) and these calls happen thousands of times. However, it turns out that: 1. It not valid to retain any TokenStream between different invocations of a proc-macro. Trying will cause the compiler to crash (rust-lang/rust#66003); 2. `syn::Ident` has some problem where it will also cause the compiler to crash if it ends up in thread-local storage (rust-lang/rust#80473) and upstream seems to want to stop any thread-local storage in proc-macros eventually (rust-lang/rust#56058). Being able to cache these tokens would provide a small but decent speedup (~3%), so it is unfortunate that this is not possible. Still, the formatting changes made while trying to implement a cache seem reasonable enough to keep in the tree.
1 parent 8e43cf4 commit a260608

File tree

3 files changed

+61
-46
lines changed

3 files changed

+61
-46
lines changed

binread_derive/src/codegen/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
mod read_options;
1+
#[macro_use]
22
pub(crate) mod sanitization;
3+
mod read_options;
34

45
use crate::parser::Input;
56
use proc_macro2::TokenStream;

binread_derive/src/codegen/read_options.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,12 @@ fn get_passed_args(field_attrs: &[StructField]) -> Vec<TokenStream> {
412412
.collect()
413413
}
414414

415-
const VARIABLE_NAME: IdentStr = IdentStr("variable_name");
416-
const ENDIAN: IdentStr = IdentStr("endian");
417-
const COUNT: IdentStr = IdentStr("count");
418-
const OFFSET: IdentStr = IdentStr("offset");
415+
ident_str! {
416+
VARIABLE_NAME = "variable_name";
417+
ENDIAN = "endian";
418+
COUNT = "count";
419+
OFFSET = "offset";
420+
}
419421

420422
fn get_endian_tokens(endian: &CondEndian) -> Option<(IdentStr, TokenStream)> {
421423
match endian {
@@ -890,7 +892,7 @@ fn save_restore_position(field_attrs: &[StructField]) -> (Vec<TokenStream>, Vec<
890892
.unzip()
891893
}
892894

893-
const SAVED_POSITION: IdentStr = IdentStr("__binread_generated_saved_position");
895+
ident_str!(SAVED_POSITION = "__binread_generated_saved_position");
894896

895897
fn get_possible_try_conversion(field_attrs: &[StructField]) -> Vec<TokenStream> {
896898
field_attrs

binread_derive/src/codegen/sanitization.rs

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,58 @@
22
use proc_macro2::{Ident, Span, TokenStream};
33
use quote::{quote, TokenStreamExt, ToTokens};
44

5+
macro_rules! ident_str {
6+
() => {};
7+
8+
($vis:vis $ident:ident = $path:expr; $($tail:tt)*) => {
9+
ident_str!($vis $ident = $path);
10+
ident_str!($($tail)*);
11+
};
12+
13+
($vis:vis $ident:ident = $path:expr) => {
14+
$vis const $ident: IdentStr = IdentStr::new($path);
15+
};
16+
}
17+
518
macro_rules! from_crate {
6-
($path:path) => { IdentStr(concat!("binread::", stringify!($path))) };
19+
($path:path) => { concat!("binread::", stringify!($path)) };
720
}
821

922
macro_rules! from_trait {
1023
() => { from_crate!(BinRead) };
11-
($path:path) => { IdentStr(concat!("binread::BinRead::", stringify!($path))) };
24+
($path:path) => { concat!("binread::BinRead::", stringify!($path)) };
1225
}
1326

14-
pub static TRAIT_NAME: IdentStr = from_trait!();
15-
16-
pub static BIN_ERROR: IdentStr = from_crate!(Error);
17-
pub static OPTIONS: IdentStr = from_crate!(ReadOptions);
18-
pub static READ_TRAIT: IdentStr = from_crate!(io::Read);
19-
pub static SEEK_TRAIT: IdentStr = from_crate!(io::Seek);
20-
pub static SEEK_FROM: IdentStr = from_crate!(io::SeekFrom);
21-
pub static BIN_RESULT: IdentStr = from_crate!(BinResult);
22-
pub static ENDIAN_ENUM: IdentStr = from_crate!(Endian);
23-
24-
pub static READ_METHOD: IdentStr = from_trait!(read_options);
25-
pub static AFTER_PARSE: IdentStr = from_trait!(after_parse);
26-
27-
pub static READER: IdentStr = IdentStr("__binread_generated_var_reader");
28-
pub static OPT: IdentStr = IdentStr("__binread_generated_var_options");
29-
pub static ARGS: IdentStr = IdentStr("__binread_generated_var_arguments");
30-
31-
pub static DEFAULT: IdentStr = IdentStr("core::default::Default::default");
32-
33-
pub static ASSERT_MAGIC: IdentStr = from_crate!(error::magic);
34-
pub static ASSERT: IdentStr = from_crate!(error::assert);
35-
36-
pub static WRITE_START_STRUCT: IdentStr = from_crate!(binary_template::write_start_struct);
37-
pub static WRITE_END_STRUCT: IdentStr = from_crate!(binary_template::write_end_struct);
38-
pub static WRITE_COMMENT: IdentStr = from_crate!(binary_template::write_comment);
39-
40-
pub static READ_METHOD_NOP: IdentStr = from_crate!(error::nop3);
41-
pub static READ_METHOD_DEFAULT: IdentStr = from_crate!(error::nop3_default);
42-
pub static AFTER_PARSE_NOP: IdentStr = from_crate!(error::nop5);
43-
pub static AFTER_PARSE_TRY: IdentStr = from_crate!(error::try_after_parse);
44-
pub static AFTER_PARSE_IDENTITY: IdentStr = from_crate!(error::identity_after_parse);
45-
pub static TRY_CONVERSION: IdentStr = from_crate!(error::try_conversion);
46-
47-
pub static TEMP: IdentStr = IdentStr("__binread_temp");
48-
pub static POS: IdentStr = IdentStr("__binread_generated_position_temp");
49-
pub static ERROR_BASKET: IdentStr = IdentStr("__binread_generated_error_basket");
50-
27+
ident_str! {
28+
pub(super) TRAIT_NAME = from_trait!();
29+
pub(super) BIN_ERROR = from_crate!(Error);
30+
pub(super) OPTIONS = from_crate!(ReadOptions);
31+
pub(super) READ_TRAIT = from_crate!(io::Read);
32+
pub(super) SEEK_TRAIT = from_crate!(io::Seek);
33+
pub(super) SEEK_FROM = from_crate!(io::SeekFrom);
34+
pub(super) BIN_RESULT = from_crate!(BinResult);
35+
pub(super) ENDIAN_ENUM = from_crate!(Endian);
36+
pub(super) READ_METHOD = from_trait!(read_options);
37+
pub(super) AFTER_PARSE = from_trait!(after_parse);
38+
pub(super) READER = "__binread_generated_var_reader";
39+
pub(super) OPT = "__binread_generated_var_options";
40+
pub(super) ARGS = "__binread_generated_var_arguments";
41+
pub(super) DEFAULT = "core::default::Default::default";
42+
pub(super) ASSERT_MAGIC = from_crate!(error::magic);
43+
pub(super) ASSERT = from_crate!(error::assert);
44+
pub(super) WRITE_START_STRUCT = from_crate!(binary_template::write_start_struct);
45+
pub(super) WRITE_END_STRUCT = from_crate!(binary_template::write_end_struct);
46+
pub(super) WRITE_COMMENT = from_crate!(binary_template::write_comment);
47+
pub(super) READ_METHOD_NOP = from_crate!(error::nop3);
48+
pub(super) READ_METHOD_DEFAULT = from_crate!(error::nop3_default);
49+
pub(super) AFTER_PARSE_NOP = from_crate!(error::nop5);
50+
pub(super) AFTER_PARSE_TRY = from_crate!(error::try_after_parse);
51+
pub(super) AFTER_PARSE_IDENTITY = from_crate!(error::identity_after_parse);
52+
pub(super) TRY_CONVERSION = from_crate!(error::try_conversion);
53+
pub(super) TEMP = "__binread_temp";
54+
pub(super) POS = "__binread_generated_position_temp";
55+
pub(super) ERROR_BASKET = "__binread_generated_error_basket";
56+
}
5157

5258
pub fn closure_wrap<T: ToTokens>(value: T) -> TokenStream {
5359
quote!(
@@ -58,7 +64,13 @@ pub fn closure_wrap<T: ToTokens>(value: T) -> TokenStream {
5864
/// A string wrapper that converts the str to a $path `TokenStream`, allowing
5965
/// for constant-time idents that can be shared across threads
6066
#[derive(Debug, Clone, Copy)]
61-
pub struct IdentStr(pub &'static str);
67+
pub struct IdentStr(&'static str);
68+
69+
impl IdentStr {
70+
pub(crate) const fn new(str: &'static str) -> Self {
71+
IdentStr(str)
72+
}
73+
}
6274

6375
impl ToTokens for IdentStr {
6476
fn to_tokens(&self, tokens: &mut TokenStream) {

0 commit comments

Comments
 (0)