Store Spanless Tokens as Strings
- Dominant language
- Rust
- Stars
- 1.6k
- Forks
- 113
- PR merge metrics
- No merged PRs in 30d
Description
Thanks for the awesome crate! 🎉 For the [WinRT crate](https://github.com/microsoft/winrt-rs) we generate _a lot_ of code, and so performance is a concern. We noticed that when using the `quote!` macro a lot of destructors and clone implementations were being called. This is because the `quote!` macro conservatively borrows the variables it interpolates calling `ToTokens::to_tokens` on these variables which takes `&self`. This is presumably to support allowing interpolation of the same variable multiple times which definitely seems like a good default. However, this can be quite expensive to constantly clone and destroy the temporary variables that are only needed inside of the `quote!` macro. This might not be possible to avoid with some values like Strings, but we have many temporary `TokenStreams` where this cloning can be avoided.
As a workaround, I created a wrapper type which implements `ToTokens` and effectively moves the value it wraps into the resulting `TokenStream` like so:
```rust
use std::cell::RefCell;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
struct TokenStreamWrapper(RefCell>);
impl TokenStreamWrapper {
fn new(stream: TokenStream) -> Self {
Self(RefCell::new(Some(stream)))
}
}
impl ToTokens for TokenStreamWrapper {
fn to_tokens(&self, tokens: &mut TokenStream) {
let stream = self.0.replace(None).unwrap();
tokens.extend(stream)
}
}
```
This dramatically reduces the amount of times we run destructors. Is this the best way to tackle this issue? Would it be good for `quote` to have an API that allowed for this in cases where performance is needed?
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.