use crate::storage::Storage;
use crate::NodeId;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct File {
ids: Vec<NodeId>,
contents: Vec<u8>,
boundaries: Vec<usize>,
}
impl File {
pub(crate) fn from_ids(ids: &[NodeId], storage: &Storage) -> File {
let mut contents = Vec::new();
let mut boundaries = Vec::new();
for id in ids {
boundaries.push(contents.len());
contents.extend_from_slice(storage.contents(id));
}
boundaries.push(contents.len());
File {
contents,
boundaries,
ids: ids.to_owned(),
}
}
pub fn from_bytes(bytes: &[u8]) -> File {
let contents = bytes.to_owned();
let mut boundaries = vec![0];
boundaries.extend(
bytes
.iter()
.enumerate()
.filter(|&(_, &b)| b == b'\n')
.map(|x| x.0 + 1),
);
if let Some(&last) = bytes.last() {
if last != b'\n' {
boundaries.push(bytes.len());
}
}
let ids = (0..(boundaries.len() as u64 - 1))
.map(NodeId::cur)
.collect();
File {
ids,
contents,
boundaries,
}
}
pub fn num_nodes(&self) -> usize {
self.ids.len()
}
pub fn node(&self, idx: usize) -> &[u8] {
let start = self.boundaries[idx];
let end = self.boundaries[idx + 1];
&self.contents[start..end]
}
pub fn node_id(&self, idx: usize) -> &NodeId {
&self.ids[idx]
}
pub fn as_bytes(&self) -> &[u8] {
&self.contents[..]
}
}
#[cfg(test)]
mod tests {
use super::File;
#[test]
fn from_bytes_empty() {
let f = File::from_bytes(b"");
assert_eq!(f.boundaries, vec![0]);
assert_eq!(f.num_nodes(), 0);
assert_eq!(f.ids.len(), 0);
}
#[test]
fn from_bytes_one_empty_line() {
let f = File::from_bytes(b"\n");
assert_eq!(f.boundaries, vec![0, 1]);
assert_eq!(f.num_nodes(), 1);
assert_eq!(f.ids.len(), 1);
}
#[test]
fn from_bytes_one_line_no_newline() {
let f = File::from_bytes(b"test");
assert_eq!(f.boundaries, vec![0, 4]);
assert_eq!(f.num_nodes(), 1);
assert_eq!(f.ids.len(), 1);
assert_eq!(f.node(0), b"test");
}
#[test]
fn from_bytes_one_line() {
let f = File::from_bytes(b"test\n");
assert_eq!(f.boundaries, vec![0, 5]);
assert_eq!(f.num_nodes(), 1);
assert_eq!(f.ids.len(), 1);
assert_eq!(f.node(0), b"test\n");
}
#[test]
fn from_bytes_two_lines() {
let f = File::from_bytes(b"test1\ntest2\n");
assert_eq!(f.boundaries, vec![0, 6, 12]);
assert_eq!(f.num_nodes(), 2);
assert_eq!(f.ids.len(), 2);
assert_eq!(f.node(0), b"test1\n");
assert_eq!(f.node(1), b"test2\n");
}
}