diff --git a/Cargo.lock b/Cargo.lock index 5f35f2872d..4666347f8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -683,6 +683,10 @@ dependencies = [ "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ra_arena" +version = "0.1.0" + [[package]] name = "ra_cli" version = "0.1.0" @@ -808,6 +812,7 @@ version = "0.1.0" dependencies = [ "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ra_arena 0.1.0", "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crates/ra_arena/Cargo.toml b/crates/ra_arena/Cargo.toml new file mode 100644 index 0000000000..9594e2d0f5 --- /dev/null +++ b/crates/ra_arena/Cargo.toml @@ -0,0 +1,5 @@ +[package] +edition = "2018" +name = "ra_arena" +version = "0.1.0" +authors = ["Aleksey Kladov "] diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs new file mode 100644 index 0000000000..44d9e826b1 --- /dev/null +++ b/crates/ra_arena/src/lib.rs @@ -0,0 +1,97 @@ +//! Yet another index-based arena. + +use std::{ + fmt, + marker::PhantomData, + ops::{Index, IndexMut}, +}; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RawId(u32); + +impl From for u32 { + fn from(raw: RawId) -> u32 { + raw.0 + } +} + +impl From for RawId { + fn from(id: u32) -> RawId { + RawId(id) + } +} + +impl fmt::Debug for RawId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for RawId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +#[derive(Clone, Debug)] +pub struct Arena { + data: Vec, + _ty: PhantomData, +} + +#[macro_export] +macro_rules! impl_arena_id { + ($name:ident) => { + impl $crate::ArenaId for $name { + fn from_raw(raw: $crate::RawId) -> Self { + $name(raw) + } + fn into_raw(self) -> $crate::RawId { + self.0 + } + } + }; +} + +pub trait ArenaId { + fn from_raw(raw: RawId) -> Self; + fn into_raw(self) -> RawId; +} + +impl Arena { + pub fn alloc(&mut self, value: T) -> ID { + let id = RawId(self.data.len() as u32); + self.data.push(value); + ID::from_raw(id) + } + pub fn iter<'a>(&'a self) -> impl Iterator { + self.data + .iter() + .enumerate() + .map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value)) + } +} + +impl Default for Arena { + fn default() -> Arena { + Arena { + data: Vec::new(), + _ty: PhantomData, + } + } +} + +impl Index for Arena { + type Output = T; + fn index(&self, idx: ID) -> &T { + let idx = idx.into_raw().0 as usize; + &self.data[idx] + } +} + +impl IndexMut for Arena { + fn index_mut(&mut self, idx: ID) -> &mut T { + let idx = idx.into_raw().0 as usize; + &mut self.data[idx] + } +} diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 06dd373c02..60d9671dee 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -350,7 +350,7 @@ fn on_notification( .write() .add_file_overlay(&path, params.text_document.text) { - subs.add_sub(FileId(file_id.0)); + subs.add_sub(FileId(file_id.0.into())); } return Ok(()); } @@ -379,7 +379,7 @@ fn on_notification( .to_file_path() .map_err(|()| format_err!("invalid uri: {}", uri))?; if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { - subs.remove_sub(FileId(file_id.0)); + subs.remove_sub(FileId(file_id.0.into())); } let params = req::PublishDiagnosticsParams { uri, diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index b5792f3b81..4e895a9a9e 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -337,7 +337,10 @@ pub fn handle_runnables( None => return Ok(None), }; let file_id = world.analysis().crate_root(crate_id)?; - let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0)); + let path = world + .vfs + .read() + .file2path(ra_vfs::VfsFile(file_id.0.into())); let res = world.workspaces.iter().find_map(|ws| { let tgt = ws.target_by_root(&path)?; let res = CargoTargetSpec { diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index c183c25afd..ebf2b15ccd 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -49,7 +49,7 @@ impl ServerWorldState { let (mut vfs, roots) = Vfs::new(roots); for r in roots { let is_local = vfs.root2path(r).starts_with(&root); - change.add_root(SourceRootId(r.0), is_local); + change.add_root(SourceRootId(r.0.into()), is_local); } let mut crate_graph = CrateGraph::default(); @@ -60,7 +60,7 @@ impl ServerWorldState { for tgt in pkg.targets(ws) { let root = tgt.root(ws); if let Some(file_id) = vfs.load(root) { - let file_id = FileId(file_id.0); + let file_id = FileId(file_id.0.into()); let crate_id = crate_graph.add_crate_root(file_id); if tgt.kind(ws) == TargetKind::Lib { pkg_to_lib_crate.insert(pkg, crate_id); @@ -113,14 +113,19 @@ impl ServerWorldState { if root_path.starts_with(&self.root) { self.roots_to_scan -= 1; for (file, path, text) in files { - change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + change.add_file( + SourceRootId(root.0.into()), + FileId(file.0.into()), + path, + text, + ); } } else { let files = files .into_iter() - .map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) + .map(|(vfsfile, path, text)| (FileId(vfsfile.0.into()), path, text)) .collect(); - libs.push((SourceRootId(root.0), files)); + libs.push((SourceRootId(root.0.into()), files)); } } VfsChange::AddFile { @@ -129,13 +134,18 @@ impl ServerWorldState { path, text, } => { - change.add_file(SourceRootId(root.0), FileId(file.0), path, text); + change.add_file( + SourceRootId(root.0.into()), + FileId(file.0.into()), + path, + text, + ); } VfsChange::RemoveFile { root, file, path } => { - change.remove_file(SourceRootId(root.0), FileId(file.0), path) + change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path) } VfsChange::ChangeFile { file, text } => { - change.change_file(FileId(file.0), text); + change.change_file(FileId(file.0.into()), text); } } } @@ -173,18 +183,18 @@ impl ServerWorld { .read() .path2file(&path) .ok_or_else(|| format_err!("unknown file: {}", path.display()))?; - Ok(FileId(file.0)) + Ok(FileId(file.0.into())) } pub fn file_id_to_uri(&self, id: FileId) -> Result { - let path = self.vfs.read().file2path(VfsFile(id.0)); + let path = self.vfs.read().file2path(VfsFile(id.0.into())); let url = Url::from_file_path(&path) .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; Ok(url) } pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result { - let base = self.vfs.read().root2path(VfsRoot(root.0)); + let base = self.vfs.read().root2path(VfsRoot(root.0.into())); let path = path.to_path(base); let url = Url::from_file_path(&path) .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml index 7c170cdfcd..e637063c97 100644 --- a/crates/ra_vfs/Cargo.toml +++ b/crates/ra_vfs/Cargo.toml @@ -12,6 +12,7 @@ crossbeam-channel = "0.3.5" log = "0.4.6" thread_worker = { path = "../thread_worker" } +ra_arena = { path = "../ra_arena" } [dev-dependencies] tempfile = "3" diff --git a/crates/ra_vfs/src/arena.rs b/crates/ra_vfs/src/arena.rs deleted file mode 100644 index 6b42ae26d2..0000000000 --- a/crates/ra_vfs/src/arena.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::{ - marker::PhantomData, - ops::{Index, IndexMut}, -}; - -#[derive(Clone, Debug)] -pub(crate) struct Arena { - data: Vec, - _ty: PhantomData, -} - -pub(crate) trait ArenaId { - fn from_u32(id: u32) -> Self; - fn to_u32(self) -> u32; -} - -impl Arena { - pub fn alloc(&mut self, value: T) -> ID { - let id = self.data.len() as u32; - self.data.push(value); - ID::from_u32(id) - } - pub fn iter<'a>(&'a self) -> impl Iterator { - self.data - .iter() - .enumerate() - .map(|(idx, value)| (ID::from_u32(idx as u32), value)) - } -} - -impl Default for Arena { - fn default() -> Arena { - Arena { - data: Vec::new(), - _ty: PhantomData, - } - } -} - -impl Index for Arena { - type Output = T; - fn index(&self, idx: ID) -> &T { - let idx = idx.to_u32() as usize; - &self.data[idx] - } -} - -impl IndexMut for Arena { - fn index_mut(&mut self, idx: ID) -> &mut T { - let idx = idx.to_u32() as usize; - &mut self.data[idx] - } -} diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 5bbc3e9935..cdea18d734 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs @@ -13,7 +13,6 @@ //! VFS is based on a concept of roots: a set of directories on the file system //! which are watched for changes. Typically, there will be a root for each //! Cargo package. -mod arena; mod io; use std::{ @@ -32,10 +31,7 @@ use relative_path::RelativePathBuf; use crossbeam_channel::Receiver; use walkdir::DirEntry; use thread_worker::WorkerHandle; - -use crate::{ - arena::{ArenaId, Arena}, -}; +use ra_arena::{Arena, RawId, impl_arena_id}; pub use crate::io::TaskResult as VfsTask; @@ -68,29 +64,13 @@ fn has_rs_extension(p: &Path) -> bool { p.extension() == Some(OsStr::new("rs")) } -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct VfsRoot(pub u32); +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct VfsRoot(pub RawId); +impl_arena_id!(VfsRoot); -impl ArenaId for VfsRoot { - fn from_u32(idx: u32) -> VfsRoot { - VfsRoot(idx) - } - fn to_u32(self) -> u32 { - self.0 - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct VfsFile(pub u32); - -impl ArenaId for VfsFile { - fn from_u32(idx: u32) -> VfsFile { - VfsFile(idx) - } - fn to_u32(self) -> u32 { - self.0 - } -} +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct VfsFile(pub RawId); +impl_arena_id!(VfsFile); struct VfsFileData { root: VfsRoot,