From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/rowan/src/green/builder.rs | 119 ++++++++++++ vendor/rowan/src/green/element.rs | 89 +++++++++ vendor/rowan/src/green/node.rs | 361 +++++++++++++++++++++++++++++++++++ vendor/rowan/src/green/node_cache.rs | 157 +++++++++++++++ vendor/rowan/src/green/token.rs | 145 ++++++++++++++ 5 files changed, 871 insertions(+) create mode 100644 vendor/rowan/src/green/builder.rs create mode 100644 vendor/rowan/src/green/element.rs create mode 100644 vendor/rowan/src/green/node.rs create mode 100644 vendor/rowan/src/green/node_cache.rs create mode 100644 vendor/rowan/src/green/token.rs (limited to 'vendor/rowan/src/green') diff --git a/vendor/rowan/src/green/builder.rs b/vendor/rowan/src/green/builder.rs new file mode 100644 index 000000000..1dbc8bb08 --- /dev/null +++ b/vendor/rowan/src/green/builder.rs @@ -0,0 +1,119 @@ +use crate::{ + cow_mut::CowMut, + green::{node_cache::NodeCache, GreenElement, GreenNode, SyntaxKind}, + NodeOrToken, +}; + +/// A checkpoint for maybe wrapping a node. See `GreenNodeBuilder::checkpoint` for details. +#[derive(Clone, Copy, Debug)] +pub struct Checkpoint(usize); + +/// A builder for a green tree. +#[derive(Default, Debug)] +pub struct GreenNodeBuilder<'cache> { + cache: CowMut<'cache, NodeCache>, + parents: Vec<(SyntaxKind, usize)>, + children: Vec<(u64, GreenElement)>, +} + +impl GreenNodeBuilder<'_> { + /// Creates new builder. + pub fn new() -> GreenNodeBuilder<'static> { + GreenNodeBuilder::default() + } + + /// Reusing `NodeCache` between different `GreenNodeBuilder`s saves memory. + /// It allows to structurally share underlying trees. + pub fn with_cache(cache: &mut NodeCache) -> GreenNodeBuilder<'_> { + GreenNodeBuilder { + cache: CowMut::Borrowed(cache), + parents: Vec::new(), + children: Vec::new(), + } + } + + /// Adds new token to the current branch. + #[inline] + pub fn token(&mut self, kind: SyntaxKind, text: &str) { + let (hash, token) = self.cache.token(kind, text); + self.children.push((hash, token.into())); + } + + /// Start new node and make it current. + #[inline] + pub fn start_node(&mut self, kind: SyntaxKind) { + let len = self.children.len(); + self.parents.push((kind, len)); + } + + /// Finish current branch and restore previous + /// branch as current. + #[inline] + pub fn finish_node(&mut self) { + let (kind, first_child) = self.parents.pop().unwrap(); + let (hash, node) = self.cache.node(kind, &mut self.children, first_child); + self.children.push((hash, node.into())); + } + + /// Prepare for maybe wrapping the next node. + /// The way wrapping works is that you first of all get a checkpoint, + /// then you place all tokens you want to wrap, and then *maybe* call + /// `start_node_at`. + /// Example: + /// ```rust + /// # use rowan::{GreenNodeBuilder, SyntaxKind}; + /// # const PLUS: SyntaxKind = SyntaxKind(0); + /// # const OPERATION: SyntaxKind = SyntaxKind(1); + /// # struct Parser; + /// # impl Parser { + /// # fn peek(&self) -> Option { None } + /// # fn parse_expr(&mut self) {} + /// # } + /// # let mut builder = GreenNodeBuilder::new(); + /// # let mut parser = Parser; + /// let checkpoint = builder.checkpoint(); + /// parser.parse_expr(); + /// if parser.peek() == Some(PLUS) { + /// // 1 + 2 = Add(1, 2) + /// builder.start_node_at(checkpoint, OPERATION); + /// parser.parse_expr(); + /// builder.finish_node(); + /// } + /// ``` + #[inline] + pub fn checkpoint(&self) -> Checkpoint { + Checkpoint(self.children.len()) + } + + /// Wrap the previous branch marked by `checkpoint` in a new branch and + /// make it current. + #[inline] + pub fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) { + let Checkpoint(checkpoint) = checkpoint; + assert!( + checkpoint <= self.children.len(), + "checkpoint no longer valid, was finish_node called early?" + ); + + if let Some(&(_, first_child)) = self.parents.last() { + assert!( + checkpoint >= first_child, + "checkpoint no longer valid, was an unmatched start_node_at called?" + ); + } + + self.parents.push((kind, checkpoint)); + } + + /// Complete tree building. Make sure that + /// `start_node_at` and `finish_node` calls + /// are paired! + #[inline] + pub fn finish(mut self) -> GreenNode { + assert_eq!(self.children.len(), 1); + match self.children.pop().unwrap().1 { + NodeOrToken::Node(node) => node, + NodeOrToken::Token(_) => panic!(), + } + } +} diff --git a/vendor/rowan/src/green/element.rs b/vendor/rowan/src/green/element.rs new file mode 100644 index 000000000..2d1ce1f61 --- /dev/null +++ b/vendor/rowan/src/green/element.rs @@ -0,0 +1,89 @@ +use std::borrow::Cow; + +use crate::{ + green::{GreenNode, GreenToken, SyntaxKind}, + GreenNodeData, NodeOrToken, TextSize, +}; + +use super::GreenTokenData; + +pub(super) type GreenElement = NodeOrToken; +pub(crate) type GreenElementRef<'a> = NodeOrToken<&'a GreenNodeData, &'a GreenTokenData>; + +impl From for GreenElement { + #[inline] + fn from(node: GreenNode) -> GreenElement { + NodeOrToken::Node(node) + } +} + +impl<'a> From<&'a GreenNode> for GreenElementRef<'a> { + #[inline] + fn from(node: &'a GreenNode) -> GreenElementRef<'a> { + NodeOrToken::Node(node) + } +} + +impl From for GreenElement { + #[inline] + fn from(token: GreenToken) -> GreenElement { + NodeOrToken::Token(token) + } +} + +impl From> for GreenElement { + #[inline] + fn from(cow: Cow<'_, GreenNodeData>) -> Self { + NodeOrToken::Node(cow.into_owned()) + } +} + +impl<'a> From<&'a GreenToken> for GreenElementRef<'a> { + #[inline] + fn from(token: &'a GreenToken) -> GreenElementRef<'a> { + NodeOrToken::Token(token) + } +} + +impl GreenElementRef<'_> { + pub fn to_owned(self) -> GreenElement { + match self { + NodeOrToken::Node(it) => NodeOrToken::Node(it.to_owned()), + NodeOrToken::Token(it) => NodeOrToken::Token(it.to_owned()), + } + } +} + +impl GreenElement { + /// Returns kind of this element. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.as_deref().kind() + } + + /// Returns the length of the text covered by this element. + #[inline] + pub fn text_len(&self) -> TextSize { + self.as_deref().text_len() + } +} + +impl GreenElementRef<'_> { + /// Returns kind of this element. + #[inline] + pub fn kind(&self) -> SyntaxKind { + match self { + NodeOrToken::Node(it) => it.kind(), + NodeOrToken::Token(it) => it.kind(), + } + } + + /// Returns the length of the text covered by this element. + #[inline] + pub fn text_len(self) -> TextSize { + match self { + NodeOrToken::Node(it) => it.text_len(), + NodeOrToken::Token(it) => it.text_len(), + } + } +} diff --git a/vendor/rowan/src/green/node.rs b/vendor/rowan/src/green/node.rs new file mode 100644 index 000000000..e94dc01cf --- /dev/null +++ b/vendor/rowan/src/green/node.rs @@ -0,0 +1,361 @@ +use std::{ + borrow::{Borrow, Cow}, + fmt, + iter::{self, FusedIterator}, + mem::{self, ManuallyDrop}, + ops, ptr, slice, +}; + +use countme::Count; + +use crate::{ + arc::{Arc, HeaderSlice, ThinArc}, + green::{GreenElement, GreenElementRef, SyntaxKind}, + utility_types::static_assert, + GreenToken, NodeOrToken, TextRange, TextSize, +}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(super) struct GreenNodeHead { + kind: SyntaxKind, + text_len: TextSize, + _c: Count, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) enum GreenChild { + Node { rel_offset: TextSize, node: GreenNode }, + Token { rel_offset: TextSize, token: GreenToken }, +} +#[cfg(target_pointer_width = "64")] +static_assert!(mem::size_of::() == mem::size_of::() * 2); + +type Repr = HeaderSlice; +type ReprThin = HeaderSlice; +#[repr(transparent)] +pub struct GreenNodeData { + data: ReprThin, +} + +impl PartialEq for GreenNodeData { + fn eq(&self, other: &Self) -> bool { + self.header() == other.header() && self.slice() == other.slice() + } +} + +/// Internal node in the immutable tree. +/// It has other nodes and tokens as children. +#[derive(Clone, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct GreenNode { + ptr: ThinArc, +} + +impl ToOwned for GreenNodeData { + type Owned = GreenNode; + + #[inline] + fn to_owned(&self) -> GreenNode { + unsafe { + let green = GreenNode::from_raw(ptr::NonNull::from(self)); + let green = ManuallyDrop::new(green); + GreenNode::clone(&green) + } + } +} + +impl Borrow for GreenNode { + #[inline] + fn borrow(&self) -> &GreenNodeData { + &*self + } +} + +impl From> for GreenNode { + #[inline] + fn from(cow: Cow<'_, GreenNodeData>) -> Self { + cow.into_owned() + } +} + +impl fmt::Debug for GreenNodeData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GreenNode") + .field("kind", &self.kind()) + .field("text_len", &self.text_len()) + .field("n_children", &self.children().len()) + .finish() + } +} + +impl fmt::Debug for GreenNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenNodeData = &*self; + fmt::Debug::fmt(data, f) + } +} + +impl fmt::Display for GreenNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenNodeData = &*self; + fmt::Display::fmt(data, f) + } +} + +impl fmt::Display for GreenNodeData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for child in self.children() { + write!(f, "{}", child)?; + } + Ok(()) + } +} + +impl GreenNodeData { + #[inline] + fn header(&self) -> &GreenNodeHead { + &self.data.header + } + + #[inline] + fn slice(&self) -> &[GreenChild] { + self.data.slice() + } + + /// Kind of this node. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.header().kind + } + + /// Returns the length of the text covered by this node. + #[inline] + pub fn text_len(&self) -> TextSize { + self.header().text_len + } + + /// Children of this node. + #[inline] + pub fn children(&self) -> Children<'_> { + Children { raw: self.slice().iter() } + } + + pub(crate) fn child_at_range( + &self, + rel_range: TextRange, + ) -> Option<(usize, TextSize, GreenElementRef<'_>)> { + let idx = self + .slice() + .binary_search_by(|it| { + let child_range = it.rel_range(); + TextRange::ordering(child_range, rel_range) + }) + // XXX: this handles empty ranges + .unwrap_or_else(|it| it.saturating_sub(1)); + let child = &self.slice().get(idx).filter(|it| it.rel_range().contains_range(rel_range))?; + Some((idx, child.rel_offset(), child.as_ref())) + } + + #[must_use] + pub fn replace_child(&self, index: usize, new_child: GreenElement) -> GreenNode { + let mut replacement = Some(new_child); + let children = self.children().enumerate().map(|(i, child)| { + if i == index { + replacement.take().unwrap() + } else { + child.to_owned() + } + }); + GreenNode::new(self.kind(), children) + } + #[must_use] + pub fn insert_child(&self, index: usize, new_child: GreenElement) -> GreenNode { + // https://github.com/rust-lang/rust/issues/34433 + self.splice_children(index..index, iter::once(new_child)) + } + #[must_use] + pub fn remove_child(&self, index: usize) -> GreenNode { + self.splice_children(index..=index, iter::empty()) + } + #[must_use] + pub fn splice_children(&self, range: R, replace_with: I) -> GreenNode + where + R: ops::RangeBounds, + I: IntoIterator, + { + let mut children: Vec<_> = self.children().map(|it| it.to_owned()).collect(); + children.splice(range, replace_with); + GreenNode::new(self.kind(), children) + } +} + +impl ops::Deref for GreenNode { + type Target = GreenNodeData; + + #[inline] + fn deref(&self) -> &GreenNodeData { + unsafe { + let repr: &Repr = &self.ptr; + let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); + mem::transmute::<&ReprThin, &GreenNodeData>(repr) + } + } +} + +impl GreenNode { + /// Creates new Node. + #[inline] + pub fn new(kind: SyntaxKind, children: I) -> GreenNode + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let mut text_len: TextSize = 0.into(); + let children = children.into_iter().map(|el| { + let rel_offset = text_len; + text_len += el.text_len(); + match el { + NodeOrToken::Node(node) => GreenChild::Node { rel_offset, node }, + NodeOrToken::Token(token) => GreenChild::Token { rel_offset, token }, + } + }); + + let data = ThinArc::from_header_and_iter( + GreenNodeHead { kind, text_len: 0.into(), _c: Count::new() }, + children, + ); + + // XXX: fixup `text_len` after construction, because we can't iterate + // `children` twice. + let data = { + let mut data = Arc::from_thin(data); + Arc::get_mut(&mut data).unwrap().header.text_len = text_len; + Arc::into_thin(data) + }; + + GreenNode { ptr: data } + } + + #[inline] + pub(crate) fn into_raw(this: GreenNode) -> ptr::NonNull { + let green = ManuallyDrop::new(this); + let green: &GreenNodeData = &*green; + ptr::NonNull::from(&*green) + } + + #[inline] + pub(crate) unsafe fn from_raw(ptr: ptr::NonNull) -> GreenNode { + let arc = Arc::from_raw(&ptr.as_ref().data as *const ReprThin); + let arc = mem::transmute::, ThinArc>(arc); + GreenNode { ptr: arc } + } +} + +impl GreenChild { + #[inline] + pub(crate) fn as_ref(&self) -> GreenElementRef { + match self { + GreenChild::Node { node, .. } => NodeOrToken::Node(node), + GreenChild::Token { token, .. } => NodeOrToken::Token(token), + } + } + #[inline] + pub(crate) fn rel_offset(&self) -> TextSize { + match self { + GreenChild::Node { rel_offset, .. } | GreenChild::Token { rel_offset, .. } => { + *rel_offset + } + } + } + #[inline] + fn rel_range(&self) -> TextRange { + let len = self.as_ref().text_len(); + TextRange::at(self.rel_offset(), len) + } +} + +#[derive(Debug, Clone)] +pub struct Children<'a> { + pub(crate) raw: slice::Iter<'a, GreenChild>, +} + +// NB: forward everything stable that iter::Slice specializes as of Rust 1.39.0 +impl ExactSizeIterator for Children<'_> { + #[inline(always)] + fn len(&self) -> usize { + self.raw.len() + } +} + +impl<'a> Iterator for Children<'a> { + type Item = GreenElementRef<'a>; + + #[inline] + fn next(&mut self) -> Option> { + self.raw.next().map(GreenChild::as_ref) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.raw.size_hint() + } + + #[inline] + fn count(self) -> usize + where + Self: Sized, + { + self.raw.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.raw.nth(n).map(GreenChild::as_ref) + } + + #[inline] + fn last(mut self) -> Option + where + Self: Sized, + { + self.next_back() + } + + #[inline] + fn fold(mut self, init: Acc, mut f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } +} + +impl<'a> DoubleEndedIterator for Children<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.raw.next_back().map(GreenChild::as_ref) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.raw.nth_back(n).map(GreenChild::as_ref) + } + + #[inline] + fn rfold(mut self, init: Acc, mut f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } +} + +impl FusedIterator for Children<'_> {} diff --git a/vendor/rowan/src/green/node_cache.rs b/vendor/rowan/src/green/node_cache.rs new file mode 100644 index 000000000..c73f3e696 --- /dev/null +++ b/vendor/rowan/src/green/node_cache.rs @@ -0,0 +1,157 @@ +use hashbrown::hash_map::RawEntryMut; +use rustc_hash::FxHasher; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +use crate::{ + green::GreenElementRef, GreenNode, GreenNodeData, GreenToken, GreenTokenData, NodeOrToken, + SyntaxKind, +}; + +use super::element::GreenElement; + +type HashMap = hashbrown::HashMap>; + +#[derive(Debug)] +struct NoHash(T); + +/// Interner for GreenTokens and GreenNodes +// XXX: the impl is a bit tricky. As usual when writing interners, we want to +// store all values in one HashSet. +// +// However, hashing trees is fun: hash of the tree is recursively defined. We +// maintain an invariant -- if the tree is interned, then all of its children +// are interned as well. +// +// That means that computing the hash naively is wasteful -- we just *know* +// hashes of children, and we can re-use those. +// +// So here we use *raw* API of hashbrown and provide the hashes manually, +// instead of going via a `Hash` impl. Our manual `Hash` and the +// `#[derive(Hash)]` are actually different! At some point we had a fun bug, +// where we accidentally mixed the two hashes, which made the cache much less +// efficient. +// +// To fix that, we additionally wrap the data in `NoHash` wrapper, to make sure +// we don't accidentally use the wrong hash! +#[derive(Default, Debug)] +pub struct NodeCache { + nodes: HashMap, ()>, + tokens: HashMap, ()>, +} + +fn token_hash(token: &GreenTokenData) -> u64 { + let mut h = FxHasher::default(); + token.kind().hash(&mut h); + token.text().hash(&mut h); + h.finish() +} + +fn node_hash(node: &GreenNodeData) -> u64 { + let mut h = FxHasher::default(); + node.kind().hash(&mut h); + for child in node.children() { + match child { + NodeOrToken::Node(it) => node_hash(it), + NodeOrToken::Token(it) => token_hash(it), + } + .hash(&mut h) + } + h.finish() +} + +fn element_id(elem: GreenElementRef<'_>) -> *const () { + match elem { + NodeOrToken::Node(it) => it as *const GreenNodeData as *const (), + NodeOrToken::Token(it) => it as *const GreenTokenData as *const (), + } +} + +impl NodeCache { + pub(crate) fn node( + &mut self, + kind: SyntaxKind, + children: &mut Vec<(u64, GreenElement)>, + first_child: usize, + ) -> (u64, GreenNode) { + let build_node = move |children: &mut Vec<(u64, GreenElement)>| { + GreenNode::new(kind, children.drain(first_child..).map(|(_, it)| it)) + }; + + let children_ref = &children[first_child..]; + if children_ref.len() > 3 { + let node = build_node(children); + return (0, node); + } + + let hash = { + let mut h = FxHasher::default(); + kind.hash(&mut h); + for &(hash, _) in children_ref { + if hash == 0 { + let node = build_node(children); + return (0, node); + } + hash.hash(&mut h); + } + h.finish() + }; + + // Green nodes are fully immutable, so it's ok to deduplicate them. + // This is the same optimization that Roslyn does + // https://github.com/KirillOsenkov/Bliki/wiki/Roslyn-Immutable-Trees + // + // For example, all `#[inline]` in this file share the same green node! + // For `libsyntax/parse/parser.rs`, measurements show that deduping saves + // 17% of the memory for green nodes! + let entry = self.nodes.raw_entry_mut().from_hash(hash, |node| { + node.0.kind() == kind && node.0.children().len() == children_ref.len() && { + let lhs = node.0.children(); + let rhs = children_ref.iter().map(|(_, it)| it.as_deref()); + + let lhs = lhs.map(element_id); + let rhs = rhs.map(element_id); + + lhs.eq(rhs) + } + }); + + let node = match entry { + RawEntryMut::Occupied(entry) => { + drop(children.drain(first_child..)); + entry.key().0.clone() + } + RawEntryMut::Vacant(entry) => { + let node = build_node(children); + entry.insert_with_hasher(hash, NoHash(node.clone()), (), |n| node_hash(&n.0)); + node + } + }; + + (hash, node) + } + + pub(crate) fn token(&mut self, kind: SyntaxKind, text: &str) -> (u64, GreenToken) { + let hash = { + let mut h = FxHasher::default(); + kind.hash(&mut h); + text.hash(&mut h); + h.finish() + }; + + let entry = self + .tokens + .raw_entry_mut() + .from_hash(hash, |token| token.0.kind() == kind && token.0.text() == text); + + let token = match entry { + RawEntryMut::Occupied(entry) => entry.key().0.clone(), + RawEntryMut::Vacant(entry) => { + let token = GreenToken::new(kind, text); + entry.insert_with_hasher(hash, NoHash(token.clone()), (), |t| token_hash(&t.0)); + token + } + }; + + (hash, token) + } +} diff --git a/vendor/rowan/src/green/token.rs b/vendor/rowan/src/green/token.rs new file mode 100644 index 000000000..1a4548a43 --- /dev/null +++ b/vendor/rowan/src/green/token.rs @@ -0,0 +1,145 @@ +use std::{ + borrow::Borrow, + fmt, + mem::{self, ManuallyDrop}, + ops, ptr, +}; + +use countme::Count; + +use crate::{ + arc::{Arc, HeaderSlice, ThinArc}, + green::SyntaxKind, + TextSize, +}; + +#[derive(PartialEq, Eq, Hash)] +struct GreenTokenHead { + kind: SyntaxKind, + _c: Count, +} + +type Repr = HeaderSlice; +type ReprThin = HeaderSlice; +#[repr(transparent)] +pub struct GreenTokenData { + data: ReprThin, +} + +impl PartialEq for GreenTokenData { + fn eq(&self, other: &Self) -> bool { + self.kind() == other.kind() && self.text() == other.text() + } +} + +/// Leaf node in the immutable tree. +#[derive(PartialEq, Eq, Hash, Clone)] +#[repr(transparent)] +pub struct GreenToken { + ptr: ThinArc, +} + +impl ToOwned for GreenTokenData { + type Owned = GreenToken; + + #[inline] + fn to_owned(&self) -> GreenToken { + unsafe { + let green = GreenToken::from_raw(ptr::NonNull::from(self)); + let green = ManuallyDrop::new(green); + GreenToken::clone(&green) + } + } +} + +impl Borrow for GreenToken { + #[inline] + fn borrow(&self) -> &GreenTokenData { + &*self + } +} + +impl fmt::Debug for GreenTokenData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GreenToken") + .field("kind", &self.kind()) + .field("text", &self.text()) + .finish() + } +} + +impl fmt::Debug for GreenToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenTokenData = &*self; + fmt::Debug::fmt(data, f) + } +} + +impl fmt::Display for GreenToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenTokenData = &*self; + fmt::Display::fmt(data, f) + } +} + +impl fmt::Display for GreenTokenData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.text()) + } +} + +impl GreenTokenData { + /// Kind of this Token. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.data.header.kind + } + + /// Text of this Token. + #[inline] + pub fn text(&self) -> &str { + unsafe { std::str::from_utf8_unchecked(self.data.slice()) } + } + + /// Returns the length of the text covered by this token. + #[inline] + pub fn text_len(&self) -> TextSize { + TextSize::of(self.text()) + } +} + +impl GreenToken { + /// Creates new Token. + #[inline] + pub fn new(kind: SyntaxKind, text: &str) -> GreenToken { + let head = GreenTokenHead { kind, _c: Count::new() }; + let ptr = ThinArc::from_header_and_iter(head, text.bytes()); + GreenToken { ptr } + } + #[inline] + pub(crate) fn into_raw(this: GreenToken) -> ptr::NonNull { + let green = ManuallyDrop::new(this); + let green: &GreenTokenData = &*green; + ptr::NonNull::from(&*green) + } + + #[inline] + pub(crate) unsafe fn from_raw(ptr: ptr::NonNull) -> GreenToken { + let arc = Arc::from_raw(&ptr.as_ref().data as *const ReprThin); + let arc = mem::transmute::, ThinArc>(arc); + GreenToken { ptr: arc } + } +} + +impl ops::Deref for GreenToken { + type Target = GreenTokenData; + + #[inline] + fn deref(&self) -> &GreenTokenData { + unsafe { + let repr: &Repr = &self.ptr; + let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); + mem::transmute::<&ReprThin, &GreenTokenData>(repr) + } + } +} -- cgit v1.2.3