dtolnay / dtolnay/quote

Store Spanless Tokens as Strings

Open
#160 15 comments 1 reaction 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.