1 use std::{fmt, hash, mem::ManuallyDrop, ptr};
2 
3 use crate::{green::SyntaxKind, interning::Resolver, TextSize};
4 use lasso::Spur;
5 use triomphe::Arc;
6 
7 #[repr(align(2))] // to use 1 bit for pointer tagging. NB: this is an at-least annotation
8 #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
9 pub(super) struct GreenTokenData {
10     pub(super) kind:     SyntaxKind,
11     pub(super) text:     Spur,
12     pub(super) text_len: TextSize,
13 }
14 
15 /// Leaf node in the immutable "green" tree.
16 pub struct GreenToken {
17     ptr: ptr::NonNull<GreenTokenData>,
18 }
19 
20 unsafe impl Send for GreenToken {} // where GreenTokenData: Send + Sync
21 unsafe impl Sync for GreenToken {} // where GreenTokenData: Send + Sync
22 
23 impl GreenToken {
add_tag(ptr: ptr::NonNull<GreenTokenData>) -> ptr::NonNull<GreenTokenData>24     fn add_tag(ptr: ptr::NonNull<GreenTokenData>) -> ptr::NonNull<GreenTokenData> {
25         unsafe {
26             let ptr = ((ptr.as_ptr() as usize) | 1) as *mut GreenTokenData;
27             ptr::NonNull::new_unchecked(ptr)
28         }
29     }
30 
remove_tag(ptr: ptr::NonNull<GreenTokenData>) -> ptr::NonNull<GreenTokenData>31     fn remove_tag(ptr: ptr::NonNull<GreenTokenData>) -> ptr::NonNull<GreenTokenData> {
32         unsafe {
33             let ptr = ((ptr.as_ptr() as usize) & !1) as *mut GreenTokenData;
34             ptr::NonNull::new_unchecked(ptr)
35         }
36     }
37 
data(&self) -> &GreenTokenData38     fn data(&self) -> &GreenTokenData {
39         unsafe { &*Self::remove_tag(self.ptr).as_ptr() }
40     }
41 
42     /// Creates a new Token.
43     #[inline]
new(data: GreenTokenData) -> GreenToken44     pub(super) fn new(data: GreenTokenData) -> GreenToken {
45         let ptr = Arc::into_raw(Arc::new(data));
46         let ptr = ptr::NonNull::new(ptr as *mut _).unwrap();
47         GreenToken {
48             ptr: Self::add_tag(ptr),
49         }
50     }
51 
52     /// [`SyntaxKind`] of this Token.
53     #[inline]
kind(&self) -> SyntaxKind54     pub fn kind(&self) -> SyntaxKind {
55         self.data().kind
56     }
57 
58     /// The original source text of this Token.
59     #[inline]
text<'i, I>(&self, resolver: &'i I) -> &'i str where I: Resolver + ?Sized,60     pub fn text<'i, I>(&self, resolver: &'i I) -> &'i str
61     where
62         I: Resolver + ?Sized,
63     {
64         resolver.resolve(&self.data().text)
65     }
66 
67     /// Returns the length of text covered by this token.
68     #[inline]
text_len(&self) -> TextSize69     pub fn text_len(&self) -> TextSize {
70         self.data().text_len
71     }
72 }
73 
74 impl fmt::Debug for GreenToken {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result75     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76         let data = self.data();
77         f.debug_struct("GreenToken")
78             .field("kind", &data.kind)
79             .field("text", &data.text)
80             .finish()
81     }
82 }
83 
84 impl Clone for GreenToken {
clone(&self) -> Self85     fn clone(&self) -> Self {
86         let ptr = Self::remove_tag(self.ptr);
87         let ptr = unsafe {
88             let arc = ManuallyDrop::new(Arc::from_raw(ptr.as_ptr()));
89             Arc::into_raw(Arc::clone(&arc))
90         };
91         let ptr = unsafe { ptr::NonNull::new_unchecked(ptr as *mut _) };
92         GreenToken {
93             ptr: Self::add_tag(ptr),
94         }
95     }
96 }
97 
98 impl Eq for GreenToken {}
99 impl PartialEq for GreenToken {
eq(&self, other: &Self) -> bool100     fn eq(&self, other: &Self) -> bool {
101         self.data() == other.data()
102     }
103 }
104 
105 impl hash::Hash for GreenToken {
hash<H>(&self, state: &mut H) where H: hash::Hasher,106     fn hash<H>(&self, state: &mut H)
107     where
108         H: hash::Hasher,
109     {
110         self.data().hash(state)
111     }
112 }
113 
114 impl Drop for GreenToken {
drop(&mut self)115     fn drop(&mut self) {
116         unsafe {
117             Arc::from_raw(Self::remove_tag(self.ptr).as_ptr());
118         }
119     }
120 }
121