]> git.lizzy.rs Git - rust.git/commitdiff
logging
authorAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 10 Aug 2018 14:49:45 +0000 (17:49 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 10 Aug 2018 14:49:45 +0000 (17:49 +0300)
18 files changed:
Cargo.toml
cli/src/main.rs
codeless/server/.gitignore [deleted file]
codeless/server/Cargo.toml
codeless/server/src/dispatch.rs
codeless/server/src/io.rs
codeless/server/src/main.rs
codeless/server/target/.rustc_info.json [deleted file]
codeless/server/target/debug/.cargo-lock [deleted file]
codeless/server/target/debug/libm.d [deleted file]
codeless/server/target/debug/libm.rmeta [deleted file]
codeless/src/extension.ts
libeditor/src/lib.rs
libeditor/tests/test.rs
src/yellow/green.rs
src/yellow/mod.rs
src/yellow/red.rs
src/yellow/syntax.rs

index 77f9c4a8d5154049ce18d0df17793b3315608c4a..55dd9165ca045a730a1335ae30ba76f7335d5b47 100644 (file)
@@ -5,7 +5,7 @@ authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
 license = "MIT OR Apache-2.0"
 
 [workspace]
-members = [ "tools", "cli", "libeditor", "libanalysis" ]
+members = [ "tools", "cli", "libeditor", "libanalysis", "codeless/server" ]
 
 [dependencies]
 unicode-xid = "0.1.0"
index f6c66743f7f6139107e129568d9c482a9c04caa1..45e0a1e4f726c8bcfbdee9332eb6d561eb44ce30 100644 (file)
@@ -10,7 +10,7 @@
 };
 use clap::{App, Arg, SubCommand};
 use tools::collect_tests;
-use libeditor::File;
+use libeditor::{ast, syntax_tree, symbols};
 
 type Result<T> = ::std::result::Result<T, failure::Error>;
 
@@ -44,14 +44,14 @@ fn main() -> Result<()> {
             let file = file()?;
             let elapsed = start.elapsed();
             if !matches.is_present("no-dump") {
-                println!("{}", file.syntax_tree());
+                println!("{}", syntax_tree(&file));
             }
             eprintln!("parsing: {:?}", elapsed);
             ::std::mem::forget(file);
         }
         ("symbols", _) => {
             let file = file()?;
-            for s in file.symbols() {
+            for s in symbols(&file) {
                 println!("{:?}", s);
             }
         }
@@ -68,9 +68,9 @@ fn main() -> Result<()> {
     Ok(())
 }
 
-fn file() -> Result<File> {
+fn file() -> Result<ast::File> {
     let text = read_stdin()?;
-    Ok(File::new(&text))
+    Ok(ast::File::parse(&text))
 }
 
 fn read_stdin() -> Result<String> {
@@ -89,7 +89,7 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
         None => bail!("No test found at line {} at {}", line, file.display()),
         Some((_start_line, test)) => test,
     };
-    let file = File::new(&test.text);
-    let tree = file.syntax_tree();
+    let file = ast::File::parse(&test.text);
+    let tree = syntax_tree(&file);
     Ok((test.text, tree))
 }
diff --git a/codeless/server/.gitignore b/codeless/server/.gitignore
deleted file mode 100644 (file)
index 5a50b7f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/target/*
index 4c3dd345c97b634ad2aa4bf97f493f04461984f1..f5c32b8787b790a01b6406428c71501ade9efee7 100644 (file)
@@ -2,7 +2,6 @@
 name = "m"
 version = "0.1.0"
 authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
-[workspace]
 
 [dependencies]
 failure = "0.1.2"
@@ -12,5 +11,8 @@ serde = "1.0.71"
 serde_derive = "1.0.71"
 drop_bomb = "0.1.0"
 crossbeam-channel = "0.2.4"
+threadpool = "1.7.1"
+flexi_logger = "0.9.0"
+log = "0.4.3"
 libeditor = { path = "../../libeditor" }
 libanalysis = { path = "../../libanalysis" }
index a9476acdebc2c34f17cac804e16c00cb10b668d8..ee87fa6c3103cd8cdc8cd01ce806a60dde37c299 100644 (file)
@@ -24,8 +24,8 @@ impl<R: Request> Responder<R>
         R::Params: DeserializeOwned,
         R::Result: Serialize,
 {
-    pub fn respond_with(self, io: &mut Io, f: impl FnOnce() -> Result<R::Result>) -> Result<()> {
-        match f() {
+    pub fn response(self, io: &mut Io, resp: Result<R::Result>) -> Result<()> {
+        match resp {
             Ok(res) => self.result(io, res)?,
             Err(e) => {
                 self.error(io)?;
index b84103d6556f6f86cf21304c3d1a717fc02ee85b..5eafc6942259f9e13e190dce4a9538ad608c509e 100644 (file)
@@ -49,16 +49,21 @@ fn recv(&mut self) -> Result<RawMsg> {
         match self.chan.recv() {
             Some(msg) => Ok(msg),
             None => {
-                self.thread
-                    .take()
-                    .ok_or_else(|| format_err!("MsgReceiver thread panicked"))?
-                    .join()
-                    .map_err(|_| format_err!("MsgReceiver thread panicked"))??;
-                bail!("client disconnected")
+                self.cleanup()?;
+                unreachable!()
             }
         }
     }
 
+    fn cleanup(&mut self) -> Result<()> {
+        self.thread
+            .take()
+            .ok_or_else(|| format_err!("MsgReceiver thread panicked"))?
+            .join()
+            .map_err(|_| format_err!("MsgReceiver thread panicked"))??;
+        bail!("client disconnected")
+    }
+
     fn stop(self) -> Result<()> {
         // Can't really self.thread.join() here, b/c it might be
         // blocking on read
@@ -68,7 +73,7 @@ fn stop(self) -> Result<()> {
 
 struct MsgSender {
     chan: Sender<RawMsg>,
-    thread: Option<thread::JoinHandle<Result<()>>>,
+    thread: thread::JoinHandle<Result<()>>,
 }
 
 impl MsgSender {
@@ -76,28 +81,14 @@ fn send(&mut self, msg: RawMsg) {
         self.chan.send(msg)
     }
 
-    fn stop(mut self) -> Result<()> {
-        if let Some(thread) = self.thread.take() {
-            thread.join()
-                .map_err(|_| format_err!("MsgSender thread panicked"))??
-        }
+    fn stop(self) -> Result<()> {
+        drop(self.chan);
+        self.thread.join()
+            .map_err(|_| format_err!("MsgSender thread panicked"))??;
         Ok(())
     }
 }
 
-impl Drop for MsgSender {
-    fn drop(&mut self) {
-        if let Some(thread) = self.thread.take() {
-            let res = thread.join();
-            if thread::panicking() {
-                drop(res)
-            } else {
-                res.unwrap().unwrap()
-            }
-        }
-    }
-}
-
 pub struct Io {
     receiver: MsgReceiver,
     sender: MsgSender,
@@ -109,7 +100,7 @@ pub fn from_stdio() -> Io {
             let (tx, rx) = bounded(16);
             MsgSender {
                 chan: tx,
-                thread: Some(thread::spawn(move || {
+                thread: thread::spawn(move || {
                     let stdout = stdout();
                     let mut stdout = stdout.lock();
                     for msg in rx {
@@ -126,7 +117,7 @@ struct JsonRpc {
                         write_msg_text(&mut stdout, &text)?;
                     }
                     Ok(())
-                })),
+                }),
             }
         };
         let receiver = {
@@ -155,6 +146,14 @@ pub fn recv(&mut self) -> Result<RawMsg> {
         self.receiver.recv()
     }
 
+    pub fn receiver(&mut self) -> &mut Receiver<RawMsg> {
+        &mut self.receiver.chan
+    }
+
+    pub fn cleanup_receiver(&mut self) -> Result<()> {
+        self.receiver.cleanup()
+    }
+
     pub fn stop(self) -> Result<()> {
         self.receiver.stop()?;
         self.sender.stop()?;
@@ -190,10 +189,12 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> {
     buf.resize(size, 0);
     inp.read_exact(&mut buf)?;
     let buf = String::from_utf8(buf)?;
+    debug!("< {}", buf);
     Ok(Some(buf))
 }
 
 fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> {
+    debug!("> {}", msg);
     write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
     out.write_all(msg.as_bytes())?;
     out.flush()?;
index 11b6b70679d2b346fb706fa620e004ee386efa5b..92f6a400ca214d56d43d5684d0895d3091094f7d 100644 (file)
@@ -6,7 +6,12 @@
 extern crate serde_json;
 extern crate languageserver_types;
 extern crate drop_bomb;
+#[macro_use]
 extern crate crossbeam_channel;
+extern crate threadpool;
+#[macro_use]
+extern crate log;
+extern crate flexi_logger;
 extern crate libeditor;
 extern crate libanalysis;
 
 mod dispatch;
 
 use languageserver_types::InitializeResult;
+use threadpool::ThreadPool;
+use crossbeam_channel::{bounded, Sender, Receiver};
+use flexi_logger::Logger;
 use libanalysis::WorldState;
-use self::io::{Io, RawMsg};
+
+use ::{
+    io::{Io, RawMsg},
+};
 
 pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
 
 fn main() -> Result<()> {
+    Logger::with_env_or_str("m=trace")
+        .log_to_file()
+        .directory("log")
+        .start()?;
+    info!("starting server");
+    match ::std::panic::catch_unwind(|| main_inner()) {
+        Ok(res) => {
+            info!("shutting down: {:?}", res);
+            res
+        }
+        Err(_) => {
+            error!("server panicked");
+            bail!("server panicked")
+        },
+    }
+}
+
+fn main_inner() -> Result<()> {
     let mut io = Io::from_stdio();
-    initialize(&mut io)?;
-    io.stop()?;
-    Ok(())
+    let res = initialize(&mut io);
+    info!("shutting down IO...");
+    let io_res = io.stop();
+    info!("... IO is down");
+    match (res, io_res) {
+        (Ok(()), Ok(())) => Ok(()),
+        (res, Ok(())) => res,
+        (Ok(()), io_res) => io_res,
+        (res, Err(io_err)) => {
+            error!("shutdown error: {:?}", io_err);
+            res
+        }
+    }
 }
 
 fn initialize(io: &mut Io) -> Result<()> {
@@ -59,20 +98,69 @@ fn initialize(io: &mut Io) -> Result<()> {
     }
 }
 
+type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>;
+
 fn initialized(io: &mut Io) -> Result<()> {
-    eprintln!("initialized");
-    let world = WorldState::new();
+    let mut world = WorldState::new();
+    let mut pool = ThreadPool::new(4);
+    let (sender, receiver) = bounded::<Thunk>(16);
+    let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone());
+    info!("waiting for background jobs to finish...");
+    receiver.for_each(drop);
+    info!("...background jobs have finished");
+    res
+}
+
+fn main_loop(
+    io: &mut Io,
+    world: &mut WorldState,
+    pool: &mut ThreadPool,
+    sender: Sender<Thunk>,
+    receiver: Receiver<Thunk>,
+) -> Result<()> {
+    info!("server initialized, serving requests");
     loop {
-        match io.recv()? {
+        enum Event {
+            Msg(RawMsg),
+            Thunk(Thunk),
+            ReceiverDead,
+        }
+
+        let event = select! {
+            recv(io.receiver(), msg) => match msg {
+                Some(msg) => Event::Msg(msg),
+                None => Event::ReceiverDead,
+            },
+            recv(receiver, thunk) => Event::Thunk(thunk.unwrap()),
+        };
+
+        let msg = match event {
+            Event::ReceiverDead => {
+                io.cleanup_receiver()?;
+                unreachable!();
+            }
+            Event::Thunk(thunk) => {
+                thunk.call_box(io)?;
+                continue;
+            }
+            Event::Msg(msg) => msg,
+        };
+
+        match msg {
             RawMsg::Request(req) => {
-                let world = world.snapshot();
                 if let Some((params, resp)) = dispatch::expect::<req::SyntaxTree>(io, req)? {
-                    resp.respond_with(io, || {
-                        let path = params.text_document.uri.to_file_path()
-                            .map_err(|()| format_err!("invalid path"))?;
-                        let file = world.file_syntax(&path)?;
-                        Ok(libeditor::syntax_tree(&file))
-                    })?
+                    let world = world.snapshot();
+                    let sender = sender.clone();
+                    pool.execute(move || {
+                        let res: Result<String> = (|| {
+                            let path = params.text_document.uri.to_file_path()
+                                .map_err(|()| format_err!("invalid path"))?;
+                            let file = world.file_syntax(&path)?;
+                            Ok(libeditor::syntax_tree(&file))
+                        })();
+
+                        sender.send(Box::new(|io: &mut Io| resp.response(io, res)))
+                    });
                 }
             }
             msg => {
@@ -82,3 +170,13 @@ fn initialized(io: &mut Io) -> Result<()> {
     }
 }
 
+
+trait FnBox<A, R>: Send {
+    fn call_box(self: Box<Self>, a: A) -> R;
+}
+
+impl<A, R, F: FnOnce(A) -> R + Send> FnBox<A, R> for F {
+    fn call_box(self: Box<F>, a: A) -> R {
+        (*self)(a)
+    }
+}
diff --git a/codeless/server/target/.rustc_info.json b/codeless/server/target/.rustc_info.json
deleted file mode 100644 (file)
index a37ac20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{"rustc_fingerprint":11898242945176772229,"outputs":{"15337506775154344876":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1617349019360157463":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1164083562126845933":["rustc 1.28.0 (9634041f0 2018-07-30)\nbinary: rustc\ncommit-hash: 9634041f0e8c0f3191d2867311276f19d0a42564\ncommit-date: 2018-07-30\nhost: x86_64-unknown-linux-gnu\nrelease: 1.28.0\nLLVM version: 6.0\n",""]}}
\ No newline at end of file
diff --git a/codeless/server/target/debug/.cargo-lock b/codeless/server/target/debug/.cargo-lock
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/codeless/server/target/debug/libm.d b/codeless/server/target/debug/libm.d
deleted file mode 100644 (file)
index 04d8bb9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/home/matklad/projects/libsyntax2/codeless/server/target/debug/libm.rmeta: /home/matklad/projects/libsyntax2/codeless/server/src/caps.rs /home/matklad/projects/libsyntax2/codeless/server/src/dispatch.rs /home/matklad/projects/libsyntax2/codeless/server/src/io.rs /home/matklad/projects/libsyntax2/codeless/server/src/main.rs /home/matklad/projects/libsyntax2/codeless/server/src/req.rs /home/matklad/projects/libsyntax2/libanalysis/src/lib.rs /home/matklad/projects/libsyntax2/libeditor/src/extend_selection.rs /home/matklad/projects/libsyntax2/libeditor/src/lib.rs /home/matklad/projects/libsyntax2/src/algo/mod.rs /home/matklad/projects/libsyntax2/src/algo/walk.rs /home/matklad/projects/libsyntax2/src/ast/generated.rs /home/matklad/projects/libsyntax2/src/ast/mod.rs /home/matklad/projects/libsyntax2/src/grammar/attributes.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/atom.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/consts.rs /home/matklad/projects/libsyntax2/src/grammar/items/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/structs.rs /home/matklad/projects/libsyntax2/src/grammar/items/traits.rs /home/matklad/projects/libsyntax2/src/grammar/items/use_item.rs /home/matklad/projects/libsyntax2/src/grammar/mod.rs /home/matklad/projects/libsyntax2/src/grammar/params.rs /home/matklad/projects/libsyntax2/src/grammar/paths.rs /home/matklad/projects/libsyntax2/src/grammar/patterns.rs /home/matklad/projects/libsyntax2/src/grammar/type_args.rs /home/matklad/projects/libsyntax2/src/grammar/type_params.rs /home/matklad/projects/libsyntax2/src/grammar/types.rs /home/matklad/projects/libsyntax2/src/lexer/classes.rs /home/matklad/projects/libsyntax2/src/lexer/comments.rs /home/matklad/projects/libsyntax2/src/lexer/mod.rs /home/matklad/projects/libsyntax2/src/lexer/numbers.rs /home/matklad/projects/libsyntax2/src/lexer/ptr.rs /home/matklad/projects/libsyntax2/src/lexer/strings.rs /home/matklad/projects/libsyntax2/src/lib.rs /home/matklad/projects/libsyntax2/src/parser_api.rs /home/matklad/projects/libsyntax2/src/parser_impl/event.rs /home/matklad/projects/libsyntax2/src/parser_impl/input.rs /home/matklad/projects/libsyntax2/src/parser_impl/mod.rs /home/matklad/projects/libsyntax2/src/smol_str.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/generated.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/mod.rs /home/matklad/projects/libsyntax2/src/utils.rs /home/matklad/projects/libsyntax2/src/yellow/builder.rs /home/matklad/projects/libsyntax2/src/yellow/green.rs /home/matklad/projects/libsyntax2/src/yellow/mod.rs /home/matklad/projects/libsyntax2/src/yellow/red.rs /home/matklad/projects/libsyntax2/src/yellow/syntax.rs
diff --git a/codeless/server/target/debug/libm.rmeta b/codeless/server/target/debug/libm.rmeta
deleted file mode 100644 (file)
index e69de29..0000000
index 712d93e04073d08383f86b4cda65185313fc7b5d..c64065e6bfc6cbaf9682ec83b0204d4408c6d73d 100644 (file)
@@ -43,10 +43,8 @@ export function deactivate(): Thenable<void> {
 function startServer() {
     let run: Executable = {
         command: "cargo",
-        args: ["run"],
-        options: {
-            cwd: "./server"
-        }
+        args: ["run", "--package", "m"],
+        options: { cwd: "." }
     }
     let serverOptions: ServerOptions = {
         run,
index 817a2d15b80ba7a490df337b19f96c3b7e9f83b1..4e9631a8b89b6c47b6cdb9f472435e1c9d731667 100644 (file)
@@ -6,9 +6,8 @@
     SyntaxNodeRef, AstNode,
     algo::walk,
     SyntaxKind::*,
-    ast,
 };
-pub use libsyntax2::{TextRange, TextUnit};
+pub use libsyntax2::{TextRange, TextUnit, ast};
 
 #[derive(Debug)]
 pub struct HighlightedRange {
index ab8254d16aef4f6c140773a941fdb2a25100436d..2a84c50806bb58325cba3f5756d519d31d44fa63 100644 (file)
@@ -3,7 +3,7 @@
 
 use std::fmt;
 use itertools::Itertools;
-use libeditor::{File, TextRange};
+use libeditor::{ast, highlight, runnables, extend_selection, TextRange};
 
 #[test]
 fn test_extend_selection() {
@@ -12,9 +12,9 @@ fn test_extend_selection() {
 }
 "#);
     let range = TextRange::offset_len(18.into(), 0.into());
-    let range = file.extend_selection(range).unwrap();
+    let range = extend_selection(&file, range).unwrap();
     assert_eq!(range, TextRange::from_to(17.into(), 18.into()));
-    let range = file.extend_selection(range).unwrap();
+    let range = extend_selection(&file, range).unwrap();
     assert_eq!(range, TextRange::from_to(15.into(), 20.into()));
 }
 
@@ -25,7 +25,7 @@ fn test_highlighting() {
 fn main() {}
     println!("Hello, {}!", 92);
 "#);
-    let hls = file.highlight();
+    let hls = highlight(&file);
     dbg_eq(
         &hls,
         r#"[HighlightedRange { range: [1; 11), tag: "comment" },
@@ -49,7 +49,7 @@ fn test_foo() {}
 #[ignore]
 fn test_foo() {}
 "#);
-    let runnables = file.runnables();
+    let runnables = runnables(&file);
     dbg_eq(
         &runnables,
         r#"[Runnable { range: [1; 13), kind: Bin },
@@ -58,8 +58,8 @@ fn test_foo() {}
     )
 }
 
-fn file(text: &str) -> File {
-    File::new(text)
+fn file(text: &str) -> ast::File {
+    ast::File::parse(text)
 }
 
 fn dbg_eq(actual: &impl fmt::Debug, expected: &str) {
index 787968363b6ac87b572c4608dbe5bd006f360185..f505b26d7a2bf974986d1a1dd3b1e98e17a9cd28 100644 (file)
@@ -56,12 +56,6 @@ fn go(node: &GreenNode, buff: &mut String) {
     }
 }
 
-#[test]
-fn assert_send_sync() {
-    fn f<T: Send + Sync>() {}
-    f::<GreenNode>();
-}
-
 #[derive(Clone, Debug)]
 pub(crate) struct GreenBranch {
     text_len: TextUnit,
index 6129ecb99e1a6e8c7c66e47027a38f5344e02fbf..ff3bb221b229ffc59d85ea937053e06a65a7a0a7 100644 (file)
@@ -3,9 +3,60 @@
 mod red;
 mod syntax;
 
-pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError};
+use std::{
+    ops::Deref,
+    sync::Arc,
+    ptr,
+};
+pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError};
 pub(crate) use self::{
     builder::GreenBuilder,
     green::GreenNode,
     red::RedNode,
 };
+
+pub trait TreeRoot: Deref<Target=SyntaxRoot> + Clone + Send + Sync {}
+
+#[derive(Debug)]
+pub struct SyntaxRoot {
+    red: RedNode,
+    pub(crate) errors: Vec<SyntaxError>,
+}
+
+impl TreeRoot for Arc<SyntaxRoot> {}
+
+impl<'a> TreeRoot for &'a SyntaxRoot {}
+
+impl SyntaxRoot {
+    pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
+        SyntaxRoot {
+            red: RedNode::new_root(green),
+            errors,
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
+
+unsafe impl Send for RedPtr {}
+
+unsafe impl Sync for RedPtr {}
+
+impl RedPtr {
+    fn new(red: &RedNode) -> RedPtr {
+        RedPtr(red.into())
+    }
+
+    unsafe fn get<'a>(self, _root: &'a impl TreeRoot) -> &'a RedNode {
+        &*self.0.as_ptr()
+    }
+}
+
+#[test]
+fn assert_send_sync() {
+    fn f<T: Send + Sync>() {}
+    f::<GreenNode>();
+    f::<RedNode>();
+    f::<SyntaxNode>();
+}
index f57c4a9b779fc821d2d566e08b20174a10d22d8b..13ad44c65cf9f5c32d61f9a180e1175709202546 100644 (file)
@@ -1,7 +1,5 @@
-use std::ptr;
-
 use parking_lot::RwLock;
-use {yellow::GreenNode, TextUnit};
+use {yellow::{GreenNode, RedPtr}, TextUnit};
 
 #[derive(Debug)]
 pub(crate) struct RedNode {
@@ -12,7 +10,7 @@ pub(crate) struct RedNode {
 
 #[derive(Debug)]
 struct ParentData {
-    parent: ptr::NonNull<RedNode>,
+    parent: RedPtr,
     start_offset: TextUnit,
     index_in_parent: usize,
 }
@@ -24,7 +22,7 @@ pub fn new_root(green: GreenNode) -> RedNode {
 
     fn new_child(
         green: GreenNode,
-        parent: ptr::NonNull<RedNode>,
+        parent: RedPtr,
         start_offset: TextUnit,
         index_in_parent: usize,
     ) -> RedNode {
@@ -64,12 +62,12 @@ pub(crate) fn n_children(&self) -> usize {
         self.green.children().len()
     }
 
-    pub(crate) fn get_child(&self, idx: usize) -> Option<ptr::NonNull<RedNode>> {
+    pub(crate) fn get_child(&self, idx: usize) -> Option<RedPtr> {
         if idx >= self.n_children() {
             return None;
         }
         match &self.children.read()[idx] {
-            Some(child) => return Some(child.into()),
+            Some(child) => return Some(RedPtr::new(child)),
             None => (),
         };
         let green_children = self.green.children();
@@ -79,15 +77,15 @@ pub(crate) fn get_child(&self, idx: usize) -> Option<ptr::NonNull<RedNode>> {
             .map(|x| x.text_len())
             .sum::<TextUnit>();
         let child =
-            RedNode::new_child(green_children[idx].clone(), self.into(), start_offset, idx);
+            RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx);
         let mut children = self.children.write();
         if children[idx].is_none() {
             children[idx] = Some(child)
         }
-        Some(children[idx].as_ref().unwrap().into())
+        Some(RedPtr::new(children[idx].as_ref().unwrap()))
     }
 
-    pub(crate) fn parent(&self) -> Option<ptr::NonNull<RedNode>> {
+    pub(crate) fn parent(&self) -> Option<RedPtr> {
         Some(self.parent.as_ref()?.parent)
     }
     pub(crate) fn index_in_parent(&self) -> Option<usize> {
index 2ba9281fc257e9bf3834962ca7b9d4bcf1b02944..6e33310f1b7f269873ce215dd720fdeb09d85f19 100644 (file)
@@ -1,25 +1,23 @@
-use std::{fmt, ops::Deref, ptr, sync::Arc};
+use std::{fmt, sync::Arc};
 
 use {
-    yellow::{GreenNode, RedNode},
+    yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr},
     SyntaxKind::{self, *},
     TextRange, TextUnit,
 };
 
-pub trait TreeRoot: Deref<Target = SyntaxRoot> + Clone {}
-
-impl TreeRoot for Arc<SyntaxRoot> {}
-
-impl<'a> TreeRoot for &'a SyntaxRoot {}
 
 #[derive(Clone, Copy)]
 pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> {
     pub(crate) root: R,
     // Guaranteed to not dangle, because `root` holds a
     // strong reference to red's ancestor
-    red: ptr::NonNull<RedNode>,
+    red: RedPtr,
 }
 
+unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {}
+unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {}
+
 impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
     fn eq(&self, other: &SyntaxNode<R1>) -> bool {
         self.red == other.red
@@ -30,21 +28,6 @@ impl<R: TreeRoot> Eq for SyntaxNode<R> {}
 
 pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>;
 
-#[derive(Debug)]
-pub struct SyntaxRoot {
-    red: RedNode,
-    pub(crate) errors: Vec<SyntaxError>,
-}
-
-impl SyntaxRoot {
-    pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
-        SyntaxRoot {
-            red: RedNode::new_root(green),
-            errors,
-        }
-    }
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct SyntaxError {
     pub msg: String,
@@ -54,11 +37,8 @@ pub struct SyntaxError {
 impl SyntaxNode<Arc<SyntaxRoot>> {
     pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
         let root = Arc::new(root);
-        let red_weak = ptr::NonNull::from(&root.red);
-        SyntaxNode {
-            root,
-            red: red_weak,
-        }
+        let red = RedPtr::new(&root.red);
+        SyntaxNode { root, red }
     }
 }
 
@@ -66,7 +46,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
     pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> {
         SyntaxNode {
             root: &*self.root,
-            red: ptr::NonNull::clone(&self.red),
+            red: self.red,
         }
     }
 
@@ -120,7 +100,7 @@ pub fn is_leaf(&self) -> bool {
     }
 
     fn red(&self) -> &RedNode {
-        unsafe { self.red.as_ref() }
+        unsafe { self.red.get(&self.root) }
     }
 }