extract area to a crate

This commit is contained in:
Aleksey Kladov 2019-01-04 16:01:06 +03:00
parent 821fa7a50a
commit 291d578938
9 changed files with 142 additions and 94 deletions

5
Cargo.lock generated
View file

@ -683,6 +683,10 @@ dependencies = [
"unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "ra_arena"
version = "0.1.0"
[[package]] [[package]]
name = "ra_cli" name = "ra_cli"
version = "0.1.0" version = "0.1.0"
@ -808,6 +812,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -0,0 +1,5 @@
[package]
edition = "2018"
name = "ra_arena"
version = "0.1.0"
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]

View file

@ -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<RawId> for u32 {
fn from(raw: RawId) -> u32 {
raw.0
}
}
impl From<u32> 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<ID: ArenaId, T> {
data: Vec<T>,
_ty: PhantomData<ID>,
}
#[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<ID: ArenaId, T> Arena<ID, T> {
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<Item = (ID, &'a T)> {
self.data
.iter()
.enumerate()
.map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
}
}
impl<ID: ArenaId, T> Default for Arena<ID, T> {
fn default() -> Arena<ID, T> {
Arena {
data: Vec::new(),
_ty: PhantomData,
}
}
}
impl<ID: ArenaId, T> Index<ID> for Arena<ID, T> {
type Output = T;
fn index(&self, idx: ID) -> &T {
let idx = idx.into_raw().0 as usize;
&self.data[idx]
}
}
impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
fn index_mut(&mut self, idx: ID) -> &mut T {
let idx = idx.into_raw().0 as usize;
&mut self.data[idx]
}
}

View file

@ -350,7 +350,7 @@ fn on_notification(
.write() .write()
.add_file_overlay(&path, params.text_document.text) .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(()); return Ok(());
} }
@ -379,7 +379,7 @@ fn on_notification(
.to_file_path() .to_file_path()
.map_err(|()| format_err!("invalid uri: {}", uri))?; .map_err(|()| format_err!("invalid uri: {}", uri))?;
if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { 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 { let params = req::PublishDiagnosticsParams {
uri, uri,

View file

@ -337,7 +337,10 @@ pub fn handle_runnables(
None => return Ok(None), None => return Ok(None),
}; };
let file_id = world.analysis().crate_root(crate_id)?; 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 res = world.workspaces.iter().find_map(|ws| {
let tgt = ws.target_by_root(&path)?; let tgt = ws.target_by_root(&path)?;
let res = CargoTargetSpec { let res = CargoTargetSpec {

View file

@ -49,7 +49,7 @@ impl ServerWorldState {
let (mut vfs, roots) = Vfs::new(roots); let (mut vfs, roots) = Vfs::new(roots);
for r in roots { for r in roots {
let is_local = vfs.root2path(r).starts_with(&root); 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(); let mut crate_graph = CrateGraph::default();
@ -60,7 +60,7 @@ impl ServerWorldState {
for tgt in pkg.targets(ws) { for tgt in pkg.targets(ws) {
let root = tgt.root(ws); let root = tgt.root(ws);
if let Some(file_id) = vfs.load(root) { 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); let crate_id = crate_graph.add_crate_root(file_id);
if tgt.kind(ws) == TargetKind::Lib { if tgt.kind(ws) == TargetKind::Lib {
pkg_to_lib_crate.insert(pkg, crate_id); pkg_to_lib_crate.insert(pkg, crate_id);
@ -113,14 +113,19 @@ impl ServerWorldState {
if root_path.starts_with(&self.root) { if root_path.starts_with(&self.root) {
self.roots_to_scan -= 1; self.roots_to_scan -= 1;
for (file, path, text) in files { 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 { } else {
let files = files let files = files
.into_iter() .into_iter()
.map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text)) .map(|(vfsfile, path, text)| (FileId(vfsfile.0.into()), path, text))
.collect(); .collect();
libs.push((SourceRootId(root.0), files)); libs.push((SourceRootId(root.0.into()), files));
} }
} }
VfsChange::AddFile { VfsChange::AddFile {
@ -129,13 +134,18 @@ impl ServerWorldState {
path, path,
text, 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 } => { 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 } => { 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() .read()
.path2file(&path) .path2file(&path)
.ok_or_else(|| format_err!("unknown file: {}", path.display()))?; .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<Url> { pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
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) let url = Url::from_file_path(&path)
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
Ok(url) Ok(url)
} }
pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> { pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
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 path = path.to_path(base);
let url = Url::from_file_path(&path) let url = Url::from_file_path(&path)
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?; .map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;

View file

@ -12,6 +12,7 @@ crossbeam-channel = "0.3.5"
log = "0.4.6" log = "0.4.6"
thread_worker = { path = "../thread_worker" } thread_worker = { path = "../thread_worker" }
ra_arena = { path = "../ra_arena" }
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"

View file

@ -1,53 +0,0 @@
use std::{
marker::PhantomData,
ops::{Index, IndexMut},
};
#[derive(Clone, Debug)]
pub(crate) struct Arena<ID: ArenaId, T> {
data: Vec<T>,
_ty: PhantomData<ID>,
}
pub(crate) trait ArenaId {
fn from_u32(id: u32) -> Self;
fn to_u32(self) -> u32;
}
impl<ID: ArenaId, T> Arena<ID, T> {
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<Item = (ID, &'a T)> {
self.data
.iter()
.enumerate()
.map(|(idx, value)| (ID::from_u32(idx as u32), value))
}
}
impl<ID: ArenaId, T> Default for Arena<ID, T> {
fn default() -> Arena<ID, T> {
Arena {
data: Vec::new(),
_ty: PhantomData,
}
}
}
impl<ID: ArenaId, T> Index<ID> for Arena<ID, T> {
type Output = T;
fn index(&self, idx: ID) -> &T {
let idx = idx.to_u32() as usize;
&self.data[idx]
}
}
impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
fn index_mut(&mut self, idx: ID) -> &mut T {
let idx = idx.to_u32() as usize;
&mut self.data[idx]
}
}

View file

@ -13,7 +13,6 @@
//! VFS is based on a concept of roots: a set of directories on the file system //! 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 //! which are watched for changes. Typically, there will be a root for each
//! Cargo package. //! Cargo package.
mod arena;
mod io; mod io;
use std::{ use std::{
@ -32,10 +31,7 @@ use relative_path::RelativePathBuf;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use walkdir::DirEntry; use walkdir::DirEntry;
use thread_worker::WorkerHandle; use thread_worker::WorkerHandle;
use ra_arena::{Arena, RawId, impl_arena_id};
use crate::{
arena::{ArenaId, Arena},
};
pub use crate::io::TaskResult as VfsTask; pub use crate::io::TaskResult as VfsTask;
@ -68,29 +64,13 @@ fn has_rs_extension(p: &Path) -> bool {
p.extension() == Some(OsStr::new("rs")) p.extension() == Some(OsStr::new("rs"))
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VfsRoot(pub u32); pub struct VfsRoot(pub RawId);
impl_arena_id!(VfsRoot);
impl ArenaId for VfsRoot { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
fn from_u32(idx: u32) -> VfsRoot { pub struct VfsFile(pub RawId);
VfsRoot(idx) impl_arena_id!(VfsFile);
}
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
}
}
struct VfsFileData { struct VfsFileData {
root: VfsRoot, root: VfsRoot,