diff --git a/rust/treedirstate/Cargo.lock b/rust/treedirstate/Cargo.lock --- a/rust/treedirstate/Cargo.lock +++ b/rust/treedirstate/Cargo.lock @@ -7,11 +7,53 @@ ] [[package]] +name = "backtrace" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "cc" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "dbghelp-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "either" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -26,6 +68,14 @@ ] [[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "fuchsia-zircon" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -113,9 +163,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc-demangle" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "rusttreedirstate" version = "0.1.0" dependencies = [ + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "quickcheck 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -154,9 +210,15 @@ [metadata] "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" +"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" +"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" "checksum itertools 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c52051d3fd3b505796a0ee90f2e5ec43213808585e8adc4d0182492cf62751a" @@ -168,6 +230,7 @@ "checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" +"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" diff --git a/rust/treedirstate/Cargo.toml b/rust/treedirstate/Cargo.toml --- a/rust/treedirstate/Cargo.toml +++ b/rust/treedirstate/Cargo.toml @@ -10,6 +10,9 @@ name = "rusttreedirstate" crate-type = ["cdylib"] +[dependencies] +error-chain = "*" + [dev-dependencies] itertools = "0.7.2" quickcheck = "*" diff --git a/rust/treedirstate/src/errors.rs b/rust/treedirstate/src/errors.rs new file mode 100644 --- /dev/null +++ b/rust/treedirstate/src/errors.rs @@ -0,0 +1,16 @@ +// Copyright Facebook, Inc. 2017 +//! Errors. + +error_chain! { + errors { + InvalidStoreId(id: u64) { + description("invalid store id"), + display("invalid store id: {}", id), + } + } + foreign_links { + Io(::std::io::Error); + Utf8(::std::str::Utf8Error); + Utf8String(::std::string::FromUtf8Error); + } +} diff --git a/rust/treedirstate/src/lib.rs b/rust/treedirstate/src/lib.rs --- a/rust/treedirstate/src/lib.rs +++ b/rust/treedirstate/src/lib.rs @@ -12,6 +12,9 @@ //! The directory state also stores files that are in the working copy parent manifest but have //! been marked as removed. +#[macro_use] +extern crate error_chain; + #[cfg(test)] extern crate itertools; @@ -19,4 +22,8 @@ #[macro_use] extern crate quickcheck; +pub mod errors; +pub mod store; pub mod vecmap; + +pub use errors::*; diff --git a/rust/treedirstate/src/store.rs b/rust/treedirstate/src/store.rs new file mode 100644 --- /dev/null +++ b/rust/treedirstate/src/store.rs @@ -0,0 +1,103 @@ +// Copyright Facebook, Inc. 2017 +//! Trait defining an append-only storage system. + +use errors::*; +use std::borrow::Cow; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct BlockId(u64); + +/// Append-only storage. Blocks of data may be stored in an instance of a Store. Once written, +/// blocks are immutable. +pub trait Store { + /// Append a new block of data to the store. Returns the ID of the block. Note that blocks + /// may be buffered until `flush` is called. + fn append(&mut self, data: &[u8]) -> Result; + + /// Flush all appended blocks to the backing store. + fn flush(&mut self) -> Result<()>; +} + +/// Read-only view of a store. +pub trait StoreView { + /// Read a block of data from the store. Blocks are immutiable, so the result may be a + /// reference to the internal copy of the data in the store. + fn read<'a>(&'a self, id: BlockId) -> Result>; +} + +/// Null implementation of a store. This cannot be used to store new blocks of data, and returns +/// an error if any attempts to read are made. +pub struct NullStore; + +impl NullStore { + pub fn new() -> NullStore { + NullStore + } +} + +impl StoreView for NullStore { + fn read<'a>(&'a self, id: BlockId) -> Result> { + bail!(ErrorKind::InvalidStoreId(id.0)) + } +} + +#[cfg(test)] +pub mod tests { + use std::collections::HashMap; + use errors::*; + use store::{BlockId, Store, StoreView}; + use std::borrow::Cow; + + /// Define a Store to be used in tests. This doesn't store the data on disk, but rather + /// keeps it in memory in a hash map. + pub struct MapStore { + next_id: BlockId, + data: HashMap>, + } + + impl MapStore { + pub fn new() -> MapStore { + // Initial ID is set to 24 to simulate a header. + MapStore { + next_id: BlockId(24), + data: HashMap::new(), + } + } + } + + impl Store for MapStore { + fn append(&mut self, data: &[u8]) -> Result { + let id = self.next_id; + self.data.insert(id, data.to_vec()); + self.next_id.0 += data.len() as u64; + Ok(id) + } + + fn flush(&mut self) -> Result<()> { + Ok(()) + } + } + + impl StoreView for MapStore { + fn read<'a>(&'a self, id: BlockId) -> Result> { + match self.data.get(&id) { + Some(data) => Ok(Cow::from(data.as_slice())), + None => bail!(ErrorKind::InvalidStoreId(id.0)), + } + } + } + + #[test] + fn basic_test() { + let mut ms = MapStore::new(); + let key1 = ms.append("12345".as_bytes()).expect("append key1"); + let key2 = ms.append("67890".as_bytes()).expect("append key2"); + ms.flush().expect("flush"); + assert_eq!(ms.read(key2).unwrap(), "67890".as_bytes()); + assert_eq!(ms.read(key1).unwrap(), "12345".as_bytes()); + assert_eq!( + ms.read(BlockId(999)).unwrap_err().to_string(), + "invalid store id: 999" + ); + } +}