aboutsummaryrefslogtreecommitdiff
path: root/src/buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.rs')
-rw-r--r--src/buffer.rs60
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() }))