From ed2ac1713326df6b926062efcc6109a20cdf7c37 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 13 Aug 2018 14:24:22 +0300 Subject: smol_str to a crate --- crates/libeditor/Cargo.toml | 1 + crates/libeditor/src/lib.rs | 1 + crates/libeditor/src/symbols.rs | 3 +- crates/libsyntax2/Cargo.toml | 1 + crates/libsyntax2/src/ast/mod.rs | 9 ++- crates/libsyntax2/src/lib.rs | 4 +- crates/libsyntax2/src/smol_str.rs | 83 -------------------- crates/libsyntax2/src/yellow/green.rs | 17 ++-- crates/libsyntax2/src/yellow/syntax.rs | 6 ++ crates/server/src/main_loop/handlers.rs | 5 +- crates/smol_str/Cargo.toml | 6 ++ crates/smol_str/src/lib.rs | 132 ++++++++++++++++++++++++++++++++ 12 files changed, 173 insertions(+), 95 deletions(-) delete mode 100644 crates/libsyntax2/src/smol_str.rs create mode 100644 crates/smol_str/Cargo.toml create mode 100644 crates/smol_str/src/lib.rs diff --git a/crates/libeditor/Cargo.toml b/crates/libeditor/Cargo.toml index fe688bc20..1d210f3c1 100644 --- a/crates/libeditor/Cargo.toml +++ b/crates/libeditor/Cargo.toml @@ -9,4 +9,5 @@ itertools = "0.7.8" superslice = "0.1.0" libsyntax2 = { path = "../libsyntax2" } +smol_str = { path = "../smol_str" } assert_eq_text = { path = "../assert_eq_text" } diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs index 1e88f1471..e5933cbd6 100644 --- a/crates/libeditor/src/lib.rs +++ b/crates/libeditor/src/lib.rs @@ -1,6 +1,7 @@ extern crate libsyntax2; extern crate superslice; extern crate itertools; +extern crate smol_str; mod extend_selection; mod symbols; diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs index 5cd781c80..03f2313f7 100644 --- a/crates/libeditor/src/symbols.rs +++ b/crates/libeditor/src/symbols.rs @@ -1,3 +1,4 @@ +use smol_str::SmolStr; use libsyntax2::{ SyntaxKind, SyntaxNodeRef, SyntaxRoot, AstNode, ast::{self, NameOwner}, @@ -11,7 +12,7 @@ use TextRange; #[derive(Debug)] pub struct FileSymbol { pub parent: Option, - pub name: String, + pub name: SmolStr, pub name_range: TextRange, pub node_range: TextRange, pub kind: SyntaxKind, diff --git a/crates/libsyntax2/Cargo.toml b/crates/libsyntax2/Cargo.toml index 4c4040fe5..810952a0f 100644 --- a/crates/libsyntax2/Cargo.toml +++ b/crates/libsyntax2/Cargo.toml @@ -10,6 +10,7 @@ text_unit = "0.1.2" itertools = "0.7.5" drop_bomb = "0.1.4" parking_lot = "0.6.0" +smol_str = { path = "../smol_str" } [dev-dependencies] assert_eq_text = { path = "../assert_eq_text" } diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 56bc099fe..e9362d048 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs @@ -1,6 +1,9 @@ mod generated; use std::sync::Arc; + +use smol_str::SmolStr; + use { SyntaxNode, SyntaxRoot, TreeRoot, SyntaxError, SyntaxKind::*, @@ -64,7 +67,9 @@ impl Function { } impl Name { - pub fn text(&self) -> String { - self.syntax().text() + pub fn text(&self) -> SmolStr { + let ident = self.syntax().first_child() + .unwrap(); + ident.leaf_text().unwrap() } } diff --git a/crates/libsyntax2/src/lib.rs b/crates/libsyntax2/src/lib.rs index ca33618a0..feef542c4 100644 --- a/crates/libsyntax2/src/lib.rs +++ b/crates/libsyntax2/src/lib.rs @@ -21,10 +21,11 @@ //#![warn(unreachable_pub)] // rust-lang/rust#47816 extern crate itertools; -extern crate text_unit; extern crate unicode_xid; extern crate drop_bomb; extern crate parking_lot; +extern crate smol_str; +extern crate text_unit; pub mod algo; pub mod ast; @@ -35,7 +36,6 @@ mod grammar; mod parser_impl; mod syntax_kinds; -mod smol_str; mod yellow; /// Utilities for simple uses of the parser. pub mod utils; diff --git a/crates/libsyntax2/src/smol_str.rs b/crates/libsyntax2/src/smol_str.rs deleted file mode 100644 index abf69dce7..000000000 --- a/crates/libsyntax2/src/smol_str.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::{sync::Arc}; - -const INLINE_CAP: usize = 22; -const WS_TAG: u8 = (INLINE_CAP + 1) as u8; - -#[derive(Clone, Debug)] -pub(crate) enum SmolStr { - Heap(Arc), - Inline { - len: u8, - buf: [u8; INLINE_CAP], - }, -} - -impl SmolStr { - pub fn new(text: &str) -> SmolStr { - let len = text.len(); - if len <= INLINE_CAP { - let mut buf = [0; INLINE_CAP]; - buf[..len].copy_from_slice(text.as_bytes()); - return SmolStr::Inline { len: len as u8, buf }; - } - - let newlines = text.bytes().take_while(|&b| b == b'\n').count(); - let spaces = text[newlines..].bytes().take_while(|&b| b == b' ').count(); - if newlines + spaces == len && newlines <= N_NEWLINES && spaces <= N_SPACES { - let mut buf = [0; INLINE_CAP]; - buf[0] = newlines as u8; - buf[1] = spaces as u8; - return SmolStr::Inline { len: WS_TAG, buf }; - } - - SmolStr::Heap( - text.to_string().into_boxed_str().into() - ) - } - - pub fn as_str(&self) -> &str { - match self { - SmolStr::Heap(data) => &*data, - SmolStr::Inline { len, buf } => { - if *len == WS_TAG { - let newlines = buf[0] as usize; - let spaces = buf[1] as usize; - assert!(newlines <= N_NEWLINES && spaces <= N_SPACES); - return &WS[N_NEWLINES - newlines..N_NEWLINES + spaces] - } - - let len = *len as usize; - let buf = &buf[..len]; - unsafe { ::std::str::from_utf8_unchecked(buf) } - } - } - } -} - -const N_NEWLINES: usize = 32; -const N_SPACES: usize = 128; -const WS: &str = - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n "; - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg(target_pointer_width = "64")] - fn smol_str_is_smol() { - assert_eq!(::std::mem::size_of::(), 8 + 8 + 8) - } - - #[test] - fn test_round_trip() { - let mut text = String::new(); - for n in 0..256 { - let smol = SmolStr::new(&text); - assert_eq!(smol.as_str(), text.as_str()); - text.push_str(&n.to_string()); - } - } -} - diff --git a/crates/libsyntax2/src/yellow/green.rs b/crates/libsyntax2/src/yellow/green.rs index f505b26d7..700f2704f 100644 --- a/crates/libsyntax2/src/yellow/green.rs +++ b/crates/libsyntax2/src/yellow/green.rs @@ -1,8 +1,8 @@ use std::sync::Arc; -use { - SyntaxKind, TextUnit, - smol_str::SmolStr, -}; + +use smol_str::SmolStr; + +use {SyntaxKind, TextUnit}; #[derive(Clone, Debug)] pub(crate) enum GreenNode { @@ -31,7 +31,7 @@ impl GreenNode { pub fn text_len(&self) -> TextUnit { match self { - GreenNode::Leaf { text, ..} => TextUnit::of_str(text.as_str()), + GreenNode::Leaf { text, .. } => TextUnit::of_str(text.as_str()), GreenNode::Branch(b) => b.text_len(), } } @@ -54,6 +54,13 @@ impl GreenNode { } } } + + pub fn leaf_text(&self) -> Option { + match self { + GreenNode::Leaf { text, .. } => Some(text.clone()), + GreenNode::Branch(_) => None, + } + } } #[derive(Clone, Debug)] diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs index 00f76e51c..b264e008a 100644 --- a/crates/libsyntax2/src/yellow/syntax.rs +++ b/crates/libsyntax2/src/yellow/syntax.rs @@ -1,5 +1,7 @@ use std::{fmt, sync::Arc}; +use smol_str::SmolStr; + use { yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr}, SyntaxKind::{self, *}, @@ -116,6 +118,10 @@ impl SyntaxNode { self.first_child().is_none() } + pub fn leaf_text(&self) -> Option { + self.red().green().leaf_text() + } + fn red(&self) -> &RedNode { unsafe { self.red.get(&self.root) } } diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index d4ae2a368..14dcafc38 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -50,9 +50,10 @@ pub fn handle_document_symbol( let mut res: Vec = Vec::new(); for symbol in libeditor::file_symbols(&file) { + let name = symbol.name.to_string(); let doc_symbol = DocumentSymbol { - name: symbol.name.clone(), - detail: Some(symbol.name), + name: name.clone(), + detail: Some(name), kind: symbol.kind.conv(), deprecated: None, range: symbol.node_range.conv_with(&line_index), diff --git a/crates/smol_str/Cargo.toml b/crates/smol_str/Cargo.toml new file mode 100644 index 000000000..83ca12f62 --- /dev/null +++ b/crates/smol_str/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "smol_str" +version = "0.1.0" +authors = ["Aleksey Kladov "] + +[dependencies] diff --git a/crates/smol_str/src/lib.rs b/crates/smol_str/src/lib.rs new file mode 100644 index 000000000..4d5fef593 --- /dev/null +++ b/crates/smol_str/src/lib.rs @@ -0,0 +1,132 @@ +use std::{sync::Arc, ops::Deref}; + +#[derive(Clone, Debug)] +pub struct SmolStr(Repr); + +impl SmolStr { + pub fn new(text: &str) -> SmolStr { + SmolStr(Repr::new(text)) + } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } + + pub fn to_string(&self) -> String { + self.as_str().to_string() + } +} + +impl Deref for SmolStr { + type Target = str; + + fn deref(&self) -> &str { + self.as_str() + } +} + +impl PartialEq for SmolStr { + fn eq(&self, other: &str) -> bool { + self.as_str() == other + } +} + +impl PartialEq for str { + fn eq(&self, other: &SmolStr) -> bool { + other == self + } +} + +impl<'a> PartialEq<&'a str> for SmolStr { + fn eq(&self, other: &&'a str) -> bool { + self == *other + } +} + +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &SmolStr) -> bool { + *self == other + } +} + +const INLINE_CAP: usize = 22; +const WS_TAG: u8 = (INLINE_CAP + 1) as u8; + +#[derive(Clone, Debug)] +enum Repr { + Heap(Arc), + Inline { + len: u8, + buf: [u8; INLINE_CAP], + }, +} + +impl Repr { + fn new(text: &str) -> Repr { + let len = text.len(); + if len <= INLINE_CAP { + let mut buf = [0; INLINE_CAP]; + buf[..len].copy_from_slice(text.as_bytes()); + return Repr::Inline { len: len as u8, buf }; + } + + let newlines = text.bytes().take_while(|&b| b == b'\n').count(); + let spaces = text[newlines..].bytes().take_while(|&b| b == b' ').count(); + if newlines + spaces == len && newlines <= N_NEWLINES && spaces <= N_SPACES { + let mut buf = [0; INLINE_CAP]; + buf[0] = newlines as u8; + buf[1] = spaces as u8; + return Repr::Inline { len: WS_TAG, buf }; + } + + Repr::Heap( + text.to_string().into_boxed_str().into() + ) + } + + fn as_str(&self) -> &str { + match self { + Repr::Heap(data) => &*data, + Repr::Inline { len, buf } => { + if *len == WS_TAG { + let newlines = buf[0] as usize; + let spaces = buf[1] as usize; + assert!(newlines <= N_NEWLINES && spaces <= N_SPACES); + return &WS[N_NEWLINES - newlines..N_NEWLINES + spaces]; + } + + let len = *len as usize; + let buf = &buf[..len]; + unsafe { ::std::str::from_utf8_unchecked(buf) } + } + } + } +} + +const N_NEWLINES: usize = 32; +const N_SPACES: usize = 128; +const WS: &str = + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n "; + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(target_pointer_width = "64")] + fn smol_str_is_smol() { + assert_eq!(::std::mem::size_of::(), 8 + 8 + 8) + } + + #[test] + fn test_round_trip() { + let mut text = String::new(); + for n in 0..256 { + let smol = SmolStr::new(&text); + assert_eq!(smol.as_str(), text.as_str()); + text.push_str(&n.to_string()); + } + } +} + -- cgit v1.2.3