aboutsummaryrefslogtreecommitdiff
path: root/libanalysis
diff options
context:
space:
mode:
Diffstat (limited to 'libanalysis')
-rw-r--r--libanalysis/Cargo.toml9
-rw-r--r--libanalysis/src/lib.rs107
2 files changed, 116 insertions, 0 deletions
diff --git a/libanalysis/Cargo.toml b/libanalysis/Cargo.toml
new file mode 100644
index 000000000..bde5043e8
--- /dev/null
+++ b/libanalysis/Cargo.toml
@@ -0,0 +1,9 @@
1[package]
2name = "libanalysis"
3version = "0.1.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5
6[dependencies]
7failure = "0.1.2"
8parking_lot = "0.6.3"
9libsyntax2 = { path = "../" }
diff --git a/libanalysis/src/lib.rs b/libanalysis/src/lib.rs
new file mode 100644
index 000000000..07e7d567d
--- /dev/null
+++ b/libanalysis/src/lib.rs
@@ -0,0 +1,107 @@
1extern crate failure;
2extern crate libsyntax2;
3extern crate parking_lot;
4
5use std::{
6 fs,
7 sync::Arc,
8 collections::hash_map::HashMap,
9 path::{PathBuf, Path},
10};
11use parking_lot::RwLock;
12use libsyntax2::ast;
13
14pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
15
16pub struct WorldState {
17 data: Arc<WorldData>
18}
19
20pub struct World {
21 data: Arc<WorldData>,
22}
23
24impl WorldState {
25 pub fn new() -> WorldState {
26 WorldState {
27 data: Arc::new(WorldData::default())
28 }
29 }
30
31 pub fn snapshot(&self) -> World {
32 World { data: self.data.clone() }
33 }
34
35 pub fn change_overlay(&mut self, path: PathBuf, text: Option<String>) {
36 let data = self.data_mut();
37 data.file_map.get_mut().remove(&path);
38 data.fs_map.get_mut().remove(&path);
39 if let Some(text) = text {
40 data.mem_map.insert(path, Arc::new(text));
41 } else {
42 data.mem_map.remove(&path);
43 }
44 }
45
46 fn data_mut(&mut self) -> &mut WorldData {
47 if Arc::get_mut(&mut self.data).is_none() {
48 let fs_map = self.data.fs_map.read().clone();
49 let file_map = self.data.file_map.read().clone();
50 self.data = Arc::new(WorldData {
51 mem_map: self.data.mem_map.clone(),
52 fs_map: RwLock::new(fs_map),
53 file_map: RwLock::new(file_map),
54 });
55 }
56 Arc::get_mut(&mut self.data).unwrap()
57 }
58}
59
60
61impl World {
62 pub fn file_syntax(&self, path: &Path) -> Result<ast::File> {
63 {
64 let guard = self.data.file_map.read();
65 if let Some(file) = guard.get(path) {
66 return Ok(file.clone());
67 }
68 }
69
70 let file = self.with_file_text(path, ast::File::parse)?;
71 let mut guard = self.data.file_map.write();
72 let file = guard.entry(path.to_owned())
73 .or_insert(file)
74 .clone();
75 Ok(file)
76 }
77
78 fn with_file_text<F: FnOnce(&str) -> R, R>(&self, path: &Path, f: F) -> Result<R> {
79 if let Some(text) = self.data.mem_map.get(path) {
80 return Ok(f(&*text));
81 }
82
83 {
84 let guard = self.data.fs_map.read();
85 if let Some(text) = guard.get(path) {
86 return Ok(f(&*text));
87 }
88 }
89
90 let text = fs::read_to_string(path)?;
91 {
92 let mut guard = self.data.fs_map.write();
93 guard.entry(path.to_owned())
94 .or_insert_with(|| Arc::new(text));
95 }
96 let guard = self.data.fs_map.read();
97 Ok(f(&guard[path]))
98 }
99}
100
101
102#[derive(Default)]
103struct WorldData {
104 mem_map: HashMap<PathBuf, Arc<String>>,
105 fs_map: RwLock<HashMap<PathBuf, Arc<String>>>,
106 file_map: RwLock<HashMap<PathBuf, ast::File>>,
107}