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