diff options
Diffstat (limited to 'src/buffer.rs')
-rw-r--r-- | src/buffer.rs | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/src/buffer.rs b/src/buffer.rs index ec172259..43e77e97 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -16,6 +16,7 @@ use crate::Lifetime; use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; use std::marker::PhantomData; use std::ptr; +use std::slice; /// Internal type which is used instead of `TokenTree` to represent a token tree /// within a `TokenBuffer`. @@ -36,20 +37,30 @@ enum Entry { /// /// *This type is available only if Syn is built with the `"parsing"` feature.* pub struct TokenBuffer { - // NOTE: Do not derive clone on this - there are raw pointers inside which - // will be messed up. Moving the `TokenBuffer` itself is safe as the actual - // backing slices won't be moved. - data: Box<[Entry]>, + // NOTE: Do not implement clone on this - there are raw pointers inside + // these entries which will be messed up. Moving the `TokenBuffer` itself is + // safe as the data pointed to won't be moved. + ptr: *const Entry, + len: usize, +} + +impl Drop for TokenBuffer { + fn drop(&mut self) { + unsafe { + let slice = slice::from_raw_parts_mut(self.ptr as *mut Entry, self.len); + let _ = Box::from_raw(slice); + } + } } impl TokenBuffer { - // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT - // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE. + // NOTE: Do not mutate the Vec returned from this function once it returns; + // the address of its backing memory must remain stable. fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer { // Build up the entries list, recording the locations of any Groups // in the list to be processed later. let mut entries = Vec::new(); - let mut seqs = Vec::new(); + let mut groups = Vec::new(); for tt in stream { match tt { TokenTree::Ident(sym) => { @@ -63,8 +74,8 @@ impl TokenBuffer { } TokenTree::Group(g) => { // Record the index of the interesting entry, and store an - // `End(null)` there temporarially. - seqs.push((entries.len(), g)); + // `End(null)` there temporarily. + groups.push((entries.len(), g)); entries.push(Entry::End(ptr::null())); } } @@ -78,23 +89,28 @@ impl TokenBuffer { // constant address after this point, as we are going to store a raw // pointer into it. let mut entries = entries.into_boxed_slice(); - for (idx, group) in seqs { + for (idx, group) in groups { // We know that this index refers to one of the temporary // `End(null)` entries, and we know that the last entry is // `End(up)`, so the next index is also valid. - let seq_up = &entries[idx + 1] as *const Entry; + let group_up = unsafe { entries.as_ptr().add(idx + 1) }; // The end entry stored at the end of this Entry::Group should // point to the Entry which follows the Group in the list. - let inner = Self::inner_new(group.stream(), seq_up); + let inner = Self::inner_new(group.stream(), group_up); entries[idx] = Entry::Group(group, inner); } - TokenBuffer { data: entries } + let len = entries.len(); + let ptr = Box::into_raw(entries); + TokenBuffer { + ptr: ptr as *const Entry, + len, + } } /// Creates a `TokenBuffer` containing all the tokens from the input - /// `TokenStream`. + /// `proc_macro::TokenStream`. /// /// *This method is available only if Syn is built with both the `"parsing"` and /// `"proc-macro"` features.* @@ -102,20 +118,20 @@ impl TokenBuffer { not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), feature = "proc-macro" ))] - pub fn new(stream: pm::TokenStream) -> TokenBuffer { + pub fn new(stream: pm::TokenStream) -> Self { Self::new2(stream.into()) } /// Creates a `TokenBuffer` containing all the tokens from the input - /// `TokenStream`. - pub fn new2(stream: TokenStream) -> TokenBuffer { + /// `proc_macro2::TokenStream`. + pub fn new2(stream: TokenStream) -> Self { Self::inner_new(stream, ptr::null()) } /// Creates a cursor referencing the first token in the buffer and able to /// traverse until the end of the buffer. pub fn begin(&self) -> Cursor { - unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) } + unsafe { Cursor::create(self.ptr, self.ptr.add(self.len - 1)) } } } @@ -210,7 +226,7 @@ impl<'a> Cursor<'a> { // situations where we should immediately exit the span after // entering it are handled correctly. unsafe { - *self = Cursor::create(&buf.data[0], self.scope); + *self = Cursor::create(buf.ptr, self.scope); } } else { break; @@ -254,7 +270,7 @@ impl<'a> Cursor<'a> { } } - /// If the cursor is pointing at an `Punct`, returns it along with a cursor + /// If the cursor is pointing at a `Punct`, returns it along with a cursor /// pointing at the next `TokenTree`. pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> { self.ignore_none(); @@ -321,9 +337,7 @@ impl<'a> Cursor<'a> { Entry::Literal(lit) => lit.clone().into(), Entry::Ident(ident) => ident.clone().into(), Entry::Punct(op) => op.clone().into(), - Entry::End(..) => { - return None; - } + Entry::End(..) => return None, }; Some((tree, unsafe { self.bump() })) |