mirror of
https://github.com/RGBCube/cstree
synced 2025-07-27 09:07:44 +00:00
Make SyntaxNode
Send
and Sync
(#12)
This commit is contained in:
parent
4116ed0138
commit
fb463aef18
4 changed files with 175 additions and 0 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -15,6 +15,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
|
@ -27,10 +33,22 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cstree"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"fxhash",
|
||||
"lasso",
|
||||
"m_lexer",
|
||||
|
|
|
@ -25,6 +25,7 @@ features = ["derive"]
|
|||
m_lexer = "0.0.4"
|
||||
serde_json = "1.0.61"
|
||||
serde_test = "1.0.119"
|
||||
crossbeam-utils = "0.8"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -38,6 +38,9 @@ pub struct SyntaxNode<L: Language, D: 'static = (), R: 'static = ()> {
|
|||
data: *mut NodeData<L, D, R>,
|
||||
}
|
||||
|
||||
unsafe impl<L: Language, D: 'static, R: 'static> Send for SyntaxNode<L, D, R> {}
|
||||
unsafe impl<L: Language, D: 'static, R: 'static> Sync for SyntaxNode<L, D, R> {}
|
||||
|
||||
impl<L: Language, D, R> SyntaxNode<L, D, R> {
|
||||
pub fn debug(&self, resolver: &impl Resolver, recursive: bool) -> String {
|
||||
// NOTE: `fmt::Write` methods on `String` never fail
|
||||
|
|
153
tests/sendsync.rs
Normal file
153
tests/sendsync.rs
Normal file
|
@ -0,0 +1,153 @@
|
|||
#![allow(clippy::redundant_clone)]
|
||||
|
||||
#[allow(unused)]
|
||||
mod common;
|
||||
|
||||
use crossbeam_utils::thread::scope;
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use common::{build_recursive, Element, SyntaxNode};
|
||||
use cstree::GreenNodeBuilder;
|
||||
use lasso::Resolver;
|
||||
|
||||
fn build_tree<D>(root: &Element<'_>) -> SyntaxNode<D, impl Resolver> {
|
||||
let mut builder = GreenNodeBuilder::new();
|
||||
build_recursive(root, &mut builder, 0);
|
||||
let (node, interner) = builder.finish();
|
||||
SyntaxNode::new_root_with_resolver(node, interner.unwrap().into_resolver())
|
||||
}
|
||||
|
||||
fn two_level_tree() -> Element<'static> {
|
||||
use Element::*;
|
||||
Node(vec![
|
||||
Node(vec![Token("0.0"), Token("0.1")]),
|
||||
Node(vec![Token("1.0")]),
|
||||
Node(vec![Token("2.0"), Token("2.1"), Token("2.2")]),
|
||||
])
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn send() {
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<()>(&tree);
|
||||
let thread_tree = tree.clone();
|
||||
let thread = thread::spawn(move || {
|
||||
let leaf1_0 = thread_tree
|
||||
.children()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.children_with_tokens()
|
||||
.next()
|
||||
.unwrap();
|
||||
let leaf1_0 = leaf1_0.into_token().unwrap();
|
||||
leaf1_0.resolve_text(thread_tree.resolver().as_ref()).to_string()
|
||||
});
|
||||
assert_eq!(thread.join().unwrap(), "1.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn send_data() {
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<String>(&tree);
|
||||
let thread_tree = tree.clone();
|
||||
{
|
||||
let node2 = tree.children().nth(2).unwrap();
|
||||
assert_eq!(*node2.try_set_data("data".into()).unwrap(), "data");
|
||||
let data = node2.get_data().unwrap();
|
||||
assert_eq!(data.as_str(), "data");
|
||||
node2.set_data("payload".into());
|
||||
let data = node2.get_data().unwrap();
|
||||
assert_eq!(data.as_str(), "payload");
|
||||
}
|
||||
let t = thread::spawn(move || {
|
||||
let node2 = thread_tree.children().nth(2).unwrap();
|
||||
assert!(node2.try_set_data("already present".into()).is_err());
|
||||
let data = node2.get_data().unwrap();
|
||||
assert_eq!(data.as_str(), "payload");
|
||||
node2.set_data("new data".into());
|
||||
});
|
||||
// wait for t to finish
|
||||
t.join().unwrap();
|
||||
{
|
||||
let node2 = tree.children().nth(2).unwrap();
|
||||
let data = node2.get_data().unwrap();
|
||||
assert_eq!(data.as_str(), "new data");
|
||||
node2.clear_data();
|
||||
// re-use `data` after node data was cleared
|
||||
assert_eq!(data.as_str(), "new data");
|
||||
}
|
||||
let thread_tree = tree.clone();
|
||||
thread::spawn(move || {
|
||||
let node2 = thread_tree.children().nth(2).unwrap();
|
||||
assert_eq!(node2.get_data(), None);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn sync() {
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<()>(&tree);
|
||||
let thread_tree = &tree;
|
||||
let result = scope(move |s| {
|
||||
s.spawn(move |_| {
|
||||
let leaf1_0 = thread_tree
|
||||
.children()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.children_with_tokens()
|
||||
.next()
|
||||
.unwrap();
|
||||
let leaf1_0 = leaf1_0.into_token().unwrap();
|
||||
leaf1_0.resolve_text(thread_tree.resolver().as_ref()).to_string()
|
||||
})
|
||||
.join()
|
||||
.unwrap()
|
||||
});
|
||||
assert_eq!(result.unwrap(), "1.0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn drop_send() {
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<()>(&tree);
|
||||
let thread_tree = tree.clone();
|
||||
let thread = thread::spawn(move || {
|
||||
drop(thread_tree);
|
||||
});
|
||||
thread.join().unwrap();
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
drop(tree);
|
||||
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<()>(&tree);
|
||||
let thread_tree = tree.clone();
|
||||
drop(tree);
|
||||
let thread = thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
drop(thread_tree);
|
||||
});
|
||||
thread.join().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
#[allow(clippy::drop_ref)]
|
||||
fn drop_sync() {
|
||||
let tree = two_level_tree();
|
||||
let tree = build_tree::<()>(&tree);
|
||||
let thread_tree = &tree;
|
||||
scope(move |s| {
|
||||
s.spawn(move |_| {
|
||||
drop(thread_tree);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
drop(tree);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue