- `length::Length` was renamed as `size::Size` to better reflect the
 purpose
 - `sector::Size` was renamed as `sector::SectorSize`
 - lifetime names were given meaning (etc. `'vol`, `'inode`)
 - `Volume` and `Length` were changed to be generic over `S:
 SectorSize`, instead of `Idx` and now use `Address<S>` as the only
 addressing (indexing) type
This commit is contained in:
Szymon Walter 2018-03-22 09:37:22 +01:00
parent e0e2807425
commit 36f13bea2a
8 changed files with 243 additions and 267 deletions

109
src/fs.rs
View file

@ -6,18 +6,18 @@ use core::nonzero::NonZero;
use alloc::Vec; use alloc::Vec;
use error::Error; use error::Error;
use sector::{Address, Size}; use sector::{Address, SectorSize};
use volume::{Volume, VolumeSlice}; use volume::{Volume, VolumeSlice};
use sys::superblock::Superblock; use sys::superblock::Superblock;
use sys::block_group::BlockGroupDescriptor; use sys::block_group::BlockGroupDescriptor;
use sys::inode::Inode as RawInode; use sys::inode::Inode as RawInode;
struct Struct<T, S: Size> { struct Struct<T, S: SectorSize> {
pub inner: T, pub inner: T,
pub offset: Address<S>, pub offset: Address<S>,
} }
impl<T, S: Size> From<(T, Address<S>)> for Struct<T, S> { impl<T, S: SectorSize> From<(T, Address<S>)> for Struct<T, S> {
#[inline] #[inline]
fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> { fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> {
Struct { inner, offset } Struct { inner, offset }
@ -25,13 +25,13 @@ impl<T, S: Size> From<(T, Address<S>)> for Struct<T, S> {
} }
/// Safe wrapper for raw sys structs /// Safe wrapper for raw sys structs
pub struct Ext2<S: Size, V: Volume<u8, Address<S>>> { pub struct Ext2<S: SectorSize, V: Volume<u8, S>> {
volume: V, volume: V,
superblock: Struct<Superblock, S>, superblock: Struct<Superblock, S>,
block_groups: Struct<Vec<BlockGroupDescriptor>, S>, block_groups: Struct<Vec<BlockGroupDescriptor>, S>,
} }
impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> { impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
pub fn new(volume: V) -> Result<Ext2<S, V>, Error> { pub fn new(volume: V) -> Result<Ext2<S, V>, Error> {
let superblock = unsafe { Struct::from(Superblock::find(&volume)?) }; let superblock = unsafe { Struct::from(Superblock::find(&volume)?) };
let block_groups_offset = Address::with_block_size( let block_groups_offset = Address::with_block_size(
@ -87,10 +87,10 @@ impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> {
Ok(()) Ok(())
} }
pub fn read_inode<'a>( pub fn read_inode<'vol>(
&'a self, &'vol self,
buf: &mut [u8], buf: &mut [u8],
inode: &Inode<'a, S, V>, inode: &Inode<'vol, S, V>,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
let total_size = inode.size(); let total_size = inode.size();
let block_size = self.block_size(); let block_size = self.block_size();
@ -113,30 +113,30 @@ impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> {
Ok(offset) Ok(offset)
} }
pub fn write_inode<'a>( pub fn write_inode<'vol>(
&'a self, &'vol self,
_inode: &(Inode<'a, S, V>, Address<S>), _inode: &(Inode<'vol, S, V>, Address<S>),
_buf: &[u8], _buf: &[u8],
) -> Result<usize, Error> { ) -> Result<usize, Error> {
unimplemented!() unimplemented!()
} }
pub fn root_inode<'a>(&'a self) -> (Inode<'a, S, V>, Address<S>) { pub fn root_inode<'vol>(&'vol self) -> (Inode<'vol, S, V>, Address<S>) {
self.inode_nth(2).unwrap() self.inode_nth(2).unwrap()
} }
pub fn inode_nth<'a>( pub fn inode_nth<'vol>(
&'a self, &'vol self,
index: usize, index: usize,
) -> Option<(Inode<'a, S, V>, Address<S>)> { ) -> Option<(Inode<'vol, S, V>, Address<S>)> {
self.inodes_nth(index).next() self.inodes_nth(index).next()
} }
pub fn inodes<'a>(&'a self) -> Inodes<'a, S, V> { pub fn inodes<'vol>(&'vol self) -> Inodes<'vol, S, V> {
self.inodes_nth(1) self.inodes_nth(1)
} }
pub fn inodes_nth<'a>(&'a self, index: usize) -> Inodes<'a, S, V> { pub fn inodes_nth<'vol>(&'vol self, index: usize) -> Inodes<'vol, S, V> {
assert!(index > 0, "inodes are 1-indexed"); assert!(index > 0, "inodes are 1-indexed");
Inodes { Inodes {
fs: self, fs: self,
@ -162,9 +162,9 @@ impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> {
(self.superblock().rev_major, self.superblock().rev_minor) (self.superblock().rev_major, self.superblock().rev_minor)
} }
pub fn inode_size<'a>(&'a self) -> usize { pub fn inode_size<'vol>(&'vol self) -> usize {
if self.version().0 == 0 { if self.version().0 == 0 {
mem::size_of::<Inode<'a, S, V>>() mem::size_of::<Inode<'vol, S, V>>()
} else { } else {
// note: inodes bigger than 128 are not supported // note: inodes bigger than 128 are not supported
self.superblock().inode_size as usize self.superblock().inode_size as usize
@ -214,15 +214,15 @@ impl<S: Size, V: Volume<u8, Address<S>>> Ext2<S, V> {
} }
} }
impl<S: Size, V: Volume<u8, Address<S>>> Debug for Ext2<S, V> { impl<S: SectorSize, V: Volume<u8, S>> Debug for Ext2<S, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Ext2<{}>", S::SIZE) write!(f, "Ext2<{}>", S::SIZE)
} }
} }
pub struct Inodes<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> { pub struct Inodes<'vol, S: 'vol + SectorSize, V: 'vol + Volume<u8, S>> {
fs: &'a Ext2<S, V>, fs: &'vol Ext2<S, V>,
block_groups: &'a [BlockGroupDescriptor], block_groups: &'vol [BlockGroupDescriptor],
log_block_size: u32, log_block_size: u32,
inode_size: usize, inode_size: usize,
inodes_per_group: usize, inodes_per_group: usize,
@ -230,10 +230,10 @@ pub struct Inodes<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> {
index: usize, index: usize,
} }
impl<'a, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator impl<'vol, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
for Inodes<'a, S, V> for Inodes<'vol, S, V>
{ {
type Item = (Inode<'a, S, V>, Address<S>); type Item = (Inode<'vol, S, V>, Address<S>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.index < self.inodes_count { if self.index < self.inodes_count {
@ -260,24 +260,26 @@ impl<'a, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Inode<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> { pub struct Inode<'vol, S: 'vol + SectorSize, V: 'vol + Volume<u8, S>> {
fs: &'a Ext2<S, V>, fs: &'vol Ext2<S, V>,
inner: RawInode, inner: RawInode,
} }
impl<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> Inode<'a, S, V> { impl<'vol, S: 'vol + SectorSize, V: 'vol + Volume<u8, S>> Inode<'vol, S, V> {
pub fn new(fs: &'a Ext2<S, V>, inner: RawInode) -> Inode<'a, S, V> { pub fn new(fs: &'vol Ext2<S, V>, inner: RawInode) -> Inode<'vol, S, V> {
Inode { fs, inner } Inode { fs, inner }
} }
pub fn blocks<'b>(&'b self) -> InodeBlocks<'a, 'b, S, V> { pub fn blocks<'inode>(&'inode self) -> InodeBlocks<'vol, 'inode, S, V> {
InodeBlocks { InodeBlocks {
inode: self, inode: self,
index: 0, index: 0,
} }
} }
pub fn directory<'b>(&'b self) -> Option<Directory<'a, 'b, S, V>> { pub fn directory<'inode>(
&'inode self,
) -> Option<Directory<'vol, 'inode, S, V>> {
use sys::inode::TypePerm; use sys::inode::TypePerm;
if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } { if unsafe { self.inner.type_perm.contains(TypePerm::DIRECTORY) } {
Some(Directory { Some(Directory {
@ -313,7 +315,7 @@ impl<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> Inode<'a, S, V> {
// - that's n/4 blocks with n/4 pointers each = (n/4)^2 // - that's n/4 blocks with n/4 pointers each = (n/4)^2
// number of blocks in triply table: (block_size/4)^3 // number of blocks in triply table: (block_size/4)^3
fn block_index<S: Size, V: Volume<u8, Address<S>>>( fn block_index<S: SectorSize, V: Volume<u8, S>>(
volume: &V, volume: &V,
block: u32, block: u32,
index: usize, index: usize,
@ -437,16 +439,20 @@ impl<'a, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> Inode<'a, S, V> {
} }
} }
pub struct InodeBlocks<'a: 'b, 'b, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> pub struct InodeBlocks<
{ 'vol: 'inode,
inode: &'b Inode<'a, S, V>, 'inode,
S: 'vol + SectorSize,
V: 'vol + Volume<u8, S>,
> {
inode: &'inode Inode<'vol, S, V>,
index: usize, index: usize,
} }
impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
for InodeBlocks<'a, 'b, S, V> for InodeBlocks<'vol, 'inode, S, V>
{ {
type Item = Result<(VolumeSlice<'a, u8, Address<S>>, Address<S>), Error>; type Item = Result<(VolumeSlice<'vol, u8, S>, Address<S>), Error>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let block = self.inode.try_block(self.index); let block = self.inode.try_block(self.index);
@ -473,17 +479,22 @@ impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator
} }
} }
pub struct Directory<'a: 'b, 'b, S: 'a + Size, V: 'a + Volume<u8, Address<S>>> { pub struct Directory<
blocks: InodeBlocks<'a, 'b, S, V>, 'vol: 'inode,
'inode,
S: 'vol + SectorSize,
V: 'vol + Volume<u8, S>,
> {
blocks: InodeBlocks<'vol, 'inode, S, V>,
offset: usize, offset: usize,
buffer: Option<VolumeSlice<'a, u8, Address<S>>>, buffer: Option<VolumeSlice<'vol, u8, S>>,
block_size: usize, block_size: usize,
} }
impl<'a, 'b, S: Size, V: 'a + Volume<u8, Address<S>>> Iterator impl<'vol, 'inode, S: SectorSize, V: 'vol + Volume<u8, S>> Iterator
for Directory<'a, 'b, S, V> for Directory<'vol, 'inode, S, V>
{ {
type Item = Result<DirectoryEntry<'a>, Error>; type Item = Result<DirectoryEntry<'vol>, Error>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.buffer.is_none() || self.offset >= self.block_size { if self.buffer.is_none() || self.offset >= self.block_size {
@ -533,7 +544,7 @@ mod tests {
use std::fs::File; use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use sector::{Address, Size, Size512}; use sector::{Address, SectorSize, Size512};
use volume::Volume; use volume::Volume;
use super::{Ext2, Inode}; use super::{Ext2, Inode};
@ -675,9 +686,9 @@ mod tests {
fn walkdir() { fn walkdir() {
use std::str; use std::str;
fn walk<'a, S: Size, V: Volume<u8, Address<S>>>( fn walk<'vol, S: SectorSize, V: Volume<u8, S>>(
fs: &'a Ext2<S, V>, fs: &'vol Ext2<S, V>,
inode: Inode<'a, S, V>, inode: Inode<'vol, S, V>,
name: String, name: String,
) { ) {
inode.directory().map(|dir| { inode.directory().map(|dir| {

View file

@ -4,7 +4,7 @@ use core::ops::{Add, Sub};
use core::fmt::{self, Debug, Display, LowerHex}; use core::fmt::{self, Debug, Display, LowerHex};
use core::iter::Step; use core::iter::Step;
pub trait Size: Clone + Copy + PartialOrd { pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd {
// log_sector_size = log_2(sector_size) // log_sector_size = log_2(sector_size)
const LOG_SIZE: u32; const LOG_SIZE: u32;
const SIZE: usize = 1 << Self::LOG_SIZE; const SIZE: usize = 1 << Self::LOG_SIZE;
@ -13,37 +13,37 @@ pub trait Size: Clone + Copy + PartialOrd {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size512; pub struct Size512;
impl Size for Size512 { impl SectorSize for Size512 {
const LOG_SIZE: u32 = 9; const LOG_SIZE: u32 = 9;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size1024; pub struct Size1024;
impl Size for Size1024 { impl SectorSize for Size1024 {
const LOG_SIZE: u32 = 10; const LOG_SIZE: u32 = 10;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size2048; pub struct Size2048;
impl Size for Size2048 { impl SectorSize for Size2048 {
const LOG_SIZE: u32 = 11; const LOG_SIZE: u32 = 11;
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Size4096; pub struct Size4096;
impl Size for Size4096 { impl SectorSize for Size4096 {
const LOG_SIZE: u32 = 12; const LOG_SIZE: u32 = 12;
} }
/// Address in a physical sector /// Address in a physical sector
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Address<S: Size> { pub struct Address<S: SectorSize> {
sector: u32, sector: u32,
offset: u32, offset: u32,
_phantom: PhantomData<S>, _phantom: PhantomData<S>,
} }
impl<S: Size> Address<S> { impl<S: SectorSize> Address<S> {
pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address<S> { pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address<S> {
assert!((offset as usize) < S::SIZE, "offset out of sector bounds"); assert!((offset as usize) < S::SIZE, "offset out of sector bounds");
let _phantom = PhantomData; let _phantom = PhantomData;
@ -96,7 +96,7 @@ impl<S: Size> Address<S> {
} }
} }
impl<S: Size> Step for Address<S> { impl<S: SectorSize> Step for Address<S> {
fn steps_between(start: &Self, end: &Self) -> Option<usize> { fn steps_between(start: &Self, end: &Self) -> Option<usize> {
if end.sector >= start.sector { if end.sector >= start.sector {
Some(end.sector as usize - start.sector as usize) Some(end.sector as usize - start.sector as usize)
@ -128,7 +128,7 @@ impl<S: Size> Step for Address<S> {
} }
} }
impl<S: Size> Debug for Address<S> { impl<S: SectorSize> Debug for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let name = format!("Address<{}>", S::SIZE); let name = format!("Address<{}>", S::SIZE);
f.debug_struct(&name) f.debug_struct(&name)
@ -138,19 +138,19 @@ impl<S: Size> Debug for Address<S> {
} }
} }
impl<S: Size> Display for Address<S> { impl<S: SectorSize> Display for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.sector, self.offset) write!(f, "{}:{}", self.sector, self.offset)
} }
} }
impl<S: Size> LowerHex for Address<S> { impl<S: SectorSize> LowerHex for Address<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}:{:x}", self.sector, self.offset) write!(f, "{:x}:{:x}", self.sector, self.offset)
} }
} }
impl<S: Size> From<u64> for Address<S> { impl<S: SectorSize> From<u64> for Address<S> {
fn from(idx: u64) -> Address<S> { fn from(idx: u64) -> Address<S> {
let sector = idx >> S::LOG_SIZE; let sector = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK as u64; let offset = idx & S::OFFSET_MASK as u64;
@ -158,7 +158,7 @@ impl<S: Size> From<u64> for Address<S> {
} }
} }
impl<S: Size> From<usize> for Address<S> { impl<S: SectorSize> From<usize> for Address<S> {
fn from(idx: usize) -> Address<S> { fn from(idx: usize) -> Address<S> {
let sector = idx >> S::LOG_SIZE; let sector = idx >> S::LOG_SIZE;
let offset = idx & S::OFFSET_MASK as usize; let offset = idx & S::OFFSET_MASK as usize;
@ -166,7 +166,7 @@ impl<S: Size> From<usize> for Address<S> {
} }
} }
impl<S: Size> Add for Address<S> { impl<S: SectorSize> Add for Address<S> {
type Output = Address<S>; type Output = Address<S>;
fn add(self, rhs: Address<S>) -> Address<S> { fn add(self, rhs: Address<S>) -> Address<S> {
Address::new( Address::new(
@ -176,7 +176,7 @@ impl<S: Size> Add for Address<S> {
} }
} }
impl<S: Size> Sub for Address<S> { impl<S: SectorSize> Sub for Address<S> {
type Output = Address<S>; type Output = Address<S>;
fn sub(self, rhs: Address<S>) -> Address<S> { fn sub(self, rhs: Address<S>) -> Address<S> {
Address::new( Address::new(

View file

@ -4,7 +4,7 @@ use core::fmt::{self, Debug};
use alloc::Vec; use alloc::Vec;
use error::Error; use error::Error;
use sector::{Address, Size}; use sector::{Address, SectorSize};
use volume::Volume; use volume::Volume;
/// The Block Group Descriptor Table contains a descriptor for each block group /// The Block Group Descriptor Table contains a descriptor for each block group
@ -52,7 +52,7 @@ impl Debug for BlockGroupDescriptor {
} }
impl BlockGroupDescriptor { impl BlockGroupDescriptor {
pub unsafe fn find_descriptor<S: Size, V: Volume<u8, Address<S>>>( pub unsafe fn find_descriptor<S: SectorSize, V: Volume<u8, S>>(
haystack: &V, haystack: &V,
offset: Address<S>, offset: Address<S>,
) -> Result<(BlockGroupDescriptor, Address<S>), Error> { ) -> Result<(BlockGroupDescriptor, Address<S>), Error> {
@ -73,7 +73,7 @@ impl BlockGroupDescriptor {
Ok(descr) Ok(descr)
} }
pub unsafe fn find_descriptor_table<S: Size, V: Volume<u8, Address<S>>>( pub unsafe fn find_descriptor_table<S: SectorSize, V: Volume<u8, S>>(
haystack: &V, haystack: &V,
offset: Address<S>, offset: Address<S>,
count: usize, count: usize,

View file

@ -2,7 +2,7 @@ use core::mem;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use error::Error; use error::Error;
use sector::{Address, Size}; use sector::{Address, SectorSize};
use volume::Volume; use volume::Volume;
/// An inode is a structure on the disk that represents a file, directory, /// An inode is a structure on the disk that represents a file, directory,
@ -97,7 +97,7 @@ impl Debug for Inode {
} }
impl Inode { impl Inode {
pub unsafe fn find_inode<S: Size, V: Volume<u8, Address<S>>>( pub unsafe fn find_inode<S: SectorSize, V: Volume<u8, S>>(
haystack: &V, haystack: &V,
offset: Address<S>, offset: Address<S>,
size: usize, size: usize,

View file

@ -2,7 +2,7 @@ use core::mem;
use core::fmt::{self, Debug}; use core::fmt::{self, Debug};
use error::Error; use error::Error;
use sector::{Address, Size}; use sector::{Address, SectorSize};
use volume::Volume; use volume::Volume;
/// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a
@ -106,7 +106,7 @@ pub struct Superblock {
/// First non-reserved inode in file system. /// First non-reserved inode in file system.
pub first_inode: u32, pub first_inode: u32,
/// Size of each inode structure in bytes. /// SectorSize of each inode structure in bytes.
pub inode_size: u16, pub inode_size: u16,
/// Block group that this superblock is part of (if backup copy) /// Block group that this superblock is part of (if backup copy)
pub block_group: u16, pub block_group: u16,
@ -195,7 +195,7 @@ impl Debug for Superblock {
} }
impl Superblock { impl Superblock {
pub unsafe fn find<S: Size, V: Volume<u8, Address<S>>>( pub unsafe fn find<S: SectorSize, V: Volume<u8, S>>(
haystack: &V, haystack: &V,
) -> Result<(Superblock, Address<S>), Error> { ) -> Result<(Superblock, Address<S>), Error> {
let offset = Address::from(1024_usize); let offset = Address::from(1024_usize);

View file

@ -1,97 +0,0 @@
use core::fmt::{self, Debug, Display};
use core::cmp::Ordering;
#[derive(Clone, Copy, Debug, Hash)]
pub enum Length<Idx> {
Unbounded,
Bounded(Idx),
}
impl<Idx: Copy> Length<Idx> {
pub fn try_len(&self) -> Option<Idx> {
match *self {
Length::Unbounded => None,
Length::Bounded(n) => Some(n),
}
}
pub unsafe fn len(&self) -> Idx {
match *self {
Length::Unbounded => panic!(
"attempt to convert `Length::Unbounded` to `Length::Idx`"
),
Length::Bounded(n) => n,
}
}
}
impl<Idx> Length<Idx> {
pub fn is_bounded(&self) -> bool {
match *self {
Length::Unbounded => false,
Length::Bounded(_) => true,
}
}
}
impl<Idx: Debug> Display for Length<Idx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
impl<Idx: PartialEq> PartialEq for Length<Idx> {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Length::Unbounded, _) => false,
(_, &Length::Unbounded) => false,
(&Length::Bounded(ref a), &Length::Bounded(ref b)) => a.eq(b),
}
}
fn ne(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Length::Unbounded, _) => false,
(_, &Length::Unbounded) => false,
(&Length::Bounded(ref a), &Length::Bounded(ref b)) => a.ne(b),
}
}
}
impl<Idx: PartialEq> PartialEq<Idx> for Length<Idx> {
fn eq(&self, rhs: &Idx) -> bool {
match *self {
Length::Unbounded => false,
Length::Bounded(ref n) => n.eq(rhs),
}
}
fn ne(&self, rhs: &Idx) -> bool {
match *self {
Length::Unbounded => false,
Length::Bounded(ref n) => n.eq(rhs),
}
}
}
impl<Idx: PartialOrd> PartialOrd for Length<Idx> {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
match (self, rhs) {
(&Length::Unbounded, &Length::Unbounded) => None,
(&Length::Unbounded, _) => Some(Ordering::Greater),
(_, &Length::Unbounded) => Some(Ordering::Less),
(&Length::Bounded(ref a), &Length::Bounded(ref b)) => {
a.partial_cmp(b)
}
}
}
}
impl<Idx: PartialOrd> PartialOrd<Idx> for Length<Idx> {
fn partial_cmp(&self, rhs: &Idx) -> Option<Ordering> {
match *self {
Length::Unbounded => Some(Ordering::Greater),
Length::Bounded(ref n) => n.partial_cmp(rhs),
}
}
}

View file

@ -7,62 +7,47 @@ use alloc::boxed::Box;
use alloc::borrow::{Cow, ToOwned}; use alloc::borrow::{Cow, ToOwned};
use error::Error; use error::Error;
use sector::{Address, Size}; use sector::{Address, SectorSize};
pub mod length; pub mod size;
use self::length::Length; use self::size::Size;
pub trait Volume<T, Idx> pub trait Volume<T: Clone, S: SectorSize> {
where
[T]: ToOwned,
Idx: PartialEq + PartialOrd,
{
type Error: Into<Error>; type Error: Into<Error>;
fn size(&self) -> Length<Idx>; fn size(&self) -> Size<S>;
fn commit( fn commit(
&mut self, &mut self,
slice: Option<VolumeCommit<T, Idx>>, slice: Option<VolumeCommit<T, S>>,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<Idx>, range: Range<Address<S>>,
) -> VolumeSlice<'a, T, Idx>; ) -> VolumeSlice<'a, T, S>;
fn slice<'a>( fn slice<'a>(
&'a self, &'a self,
range: Range<Idx>, range: Range<Address<S>>,
) -> Result<VolumeSlice<'a, T, Idx>, Self::Error>; ) -> Result<VolumeSlice<'a, T, S>, Self::Error>;
} }
pub struct VolumeSlice<'a, T: 'a, Idx> pub struct VolumeSlice<'a, T: 'a + Clone, S: SectorSize> {
where
[T]: ToOwned,
{
inner: Cow<'a, [T]>, inner: Cow<'a, [T]>,
index: Idx, index: Address<S>,
} }
impl<T, Idx: Default> VolumeSlice<'static, T, Idx> impl<T: Clone, S: SectorSize> VolumeSlice<'static, T, S> {
where pub fn with_static(inner: &'static [T]) -> VolumeSlice<'static, T, S> {
[T]: ToOwned,
{
pub fn with_static(inner: &'static [T]) -> VolumeSlice<'static, T, Idx> {
VolumeSlice { VolumeSlice {
inner: Cow::Borrowed(inner), inner: Cow::Borrowed(inner),
index: Idx::default(), index: Address::new(0, 0),
} }
} }
}
impl<T, Idx> VolumeSlice<'static, T, Idx>
where
[T]: ToOwned,
{
pub fn new_owned( pub fn new_owned(
inner: <[T] as ToOwned>::Owned, inner: <[T] as ToOwned>::Owned,
index: Idx, index: Address<S>,
) -> VolumeSlice<'static, T, Idx> { ) -> VolumeSlice<'static, T, S> {
VolumeSlice { VolumeSlice {
inner: Cow::Owned(inner), inner: Cow::Owned(inner),
index, index,
@ -70,11 +55,8 @@ where
} }
} }
impl<'a, T, Idx> VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> {
where pub fn new(inner: &'a [T], index: Address<S>) -> VolumeSlice<'a, T, S> {
[T]: ToOwned,
{
pub fn new(inner: &'a [T], index: Idx) -> VolumeSlice<'a, T, Idx> {
VolumeSlice { VolumeSlice {
inner: Cow::Borrowed(inner), inner: Cow::Borrowed(inner),
index, index,
@ -88,13 +70,13 @@ where
} }
} }
pub fn at_index(&self) -> &Idx { pub fn address(&self) -> Address<S> {
&self.index self.index
} }
} }
impl<'a, Idx: Copy> VolumeSlice<'a, u8, Idx> { impl<'a, S: SectorSize> VolumeSlice<'a, u8, S> {
pub unsafe fn dynamic_cast<T: Copy>(&self) -> (T, Idx) { pub unsafe fn dynamic_cast<T: Copy>(&self) -> (T, Address<S>) {
assert!(self.inner.len() >= mem::size_of::<T>()); assert!(self.inner.len() >= mem::size_of::<T>());
let index = self.index; let index = self.index;
let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()); let cast = mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap());
@ -103,8 +85,8 @@ impl<'a, Idx: Copy> VolumeSlice<'a, u8, Idx> {
pub fn from_cast<T: Copy>( pub fn from_cast<T: Copy>(
cast: &'a T, cast: &'a T,
index: Idx, index: Address<S>,
) -> VolumeSlice<'a, u8, Idx> { ) -> VolumeSlice<'a, u8, S> {
let len = mem::size_of::<T>(); let len = mem::size_of::<T>();
let ptr = cast as *const T as *const u8; let ptr = cast as *const T as *const u8;
let slice = unsafe { slice::from_raw_parts(ptr, len) }; let slice = unsafe { slice::from_raw_parts(ptr, len) };
@ -112,11 +94,8 @@ impl<'a, Idx: Copy> VolumeSlice<'a, u8, Idx> {
} }
} }
impl<'a, T, Idx> VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> {
where pub fn commit(self) -> Option<VolumeCommit<T, S>> {
[T]: ToOwned<Owned = Vec<T>>,
{
pub fn commit(self) -> Option<VolumeCommit<T, Idx>> {
if self.is_mutated() { if self.is_mutated() {
Some(VolumeCommit::new(self.inner.into_owned(), self.index)) Some(VolumeCommit::new(self.inner.into_owned(), self.index))
} else { } else {
@ -125,29 +104,19 @@ where
} }
} }
impl<'a, T, Idx> AsRef<[T]> for VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> AsRef<[T]> for VolumeSlice<'a, T, S> {
where
[T]: ToOwned,
{
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.inner.as_ref() self.inner.as_ref()
} }
} }
impl<'a, T, Idx> AsMut<[T]> for VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> AsMut<[T]> for VolumeSlice<'a, T, S> {
where
[T]: ToOwned,
<[T] as ToOwned>::Owned: AsMut<[T]>,
{
fn as_mut(&mut self) -> &mut [T] { fn as_mut(&mut self) -> &mut [T] {
self.inner.to_mut().as_mut() self.inner.to_mut().as_mut()
} }
} }
impl<'a, T, Idx> Deref for VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> Deref for VolumeSlice<'a, T, S> {
where
[T]: ToOwned,
{
type Target = [T]; type Target = [T];
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -155,32 +124,28 @@ where
} }
} }
impl<'a, T, Idx> DerefMut for VolumeSlice<'a, T, Idx> impl<'a, T: Clone, S: SectorSize> DerefMut for VolumeSlice<'a, T, S> {
where
[T]: ToOwned,
<[T] as ToOwned>::Owned: AsMut<[T]>,
{
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut() self.as_mut()
} }
} }
pub struct VolumeCommit<T, Idx> { pub struct VolumeCommit<T, S: SectorSize> {
inner: Vec<T>, inner: Vec<T>,
index: Idx, index: Address<S>,
} }
impl<T, Idx: Default> VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> VolumeCommit<T, S> {
pub fn with_vec(inner: Vec<T>) -> VolumeCommit<T, Idx> { pub fn with_vec(inner: Vec<T>) -> VolumeCommit<T, S> {
VolumeCommit { VolumeCommit {
inner, inner,
index: Idx::default(), index: Address::new(0, 0),
} }
} }
} }
impl<T, Idx> VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> VolumeCommit<T, S> {
pub fn new(inner: Vec<T>, index: Idx) -> VolumeCommit<T, Idx> { pub fn new(inner: Vec<T>, index: Address<S>) -> VolumeCommit<T, S> {
VolumeCommit { inner, index } VolumeCommit { inner, index }
} }
@ -188,24 +153,24 @@ impl<T, Idx> VolumeCommit<T, Idx> {
self.inner self.inner
} }
pub fn at_index(&self) -> &Idx { pub fn address(&self) -> Address<S> {
&self.index self.index
} }
} }
impl<T, Idx> AsRef<[T]> for VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> AsRef<[T]> for VolumeCommit<T, S> {
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.inner.as_ref() self.inner.as_ref()
} }
} }
impl<T, Idx> AsMut<[T]> for VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> AsMut<[T]> for VolumeCommit<T, S> {
fn as_mut(&mut self) -> &mut [T] { fn as_mut(&mut self) -> &mut [T] {
self.inner.as_mut() self.inner.as_mut()
} }
} }
impl<T, Idx> Deref for VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> Deref for VolumeCommit<T, S> {
type Target = [T]; type Target = [T];
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -213,7 +178,7 @@ impl<T, Idx> Deref for VolumeCommit<T, Idx> {
} }
} }
impl<T, Idx> DerefMut for VolumeCommit<T, Idx> { impl<T: Clone, S: SectorSize> DerefMut for VolumeCommit<T, S> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut() self.as_mut()
} }
@ -221,26 +186,23 @@ impl<T, Idx> DerefMut for VolumeCommit<T, Idx> {
macro_rules! impl_slice { macro_rules! impl_slice {
(@inner $volume:ty $( , $lt:lifetime )* ) => { (@inner $volume:ty $( , $lt:lifetime )* ) => {
impl<$( $lt, )* S: Size, T> Volume<T, Address<S>> impl<$( $lt, )* T: Clone, S: SectorSize> Volume<T, S>
for $volume for $volume
where
T: Clone,
[T]: ToOwned,
{ {
type Error = Error; type Error = Error;
fn size(&self) -> Length<Address<S>> { fn size(&self) -> Size<S> {
Length::Bounded( Size::Bounded(
Address::from(<Self as AsRef<[T]>>::as_ref(self).len()) Address::from(<Self as AsRef<[T]>>::as_ref(self).len())
) )
} }
fn commit( fn commit(
&mut self, &mut self,
slice: Option<VolumeCommit<T, Address<S>>>, slice: Option<VolumeCommit<T, S>>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
slice.map(|slice| { slice.map(|slice| {
let index = slice.at_index().into_index() as usize; let index = slice.address().into_index() as usize;
let end = index + slice.as_ref().len(); let end = index + slice.as_ref().len();
// XXX: it would be much better to drop the contents of dst // XXX: it would be much better to drop the contents of dst
// and move the contents of slice instead of cloning // and move the contents of slice instead of cloning
@ -254,7 +216,7 @@ macro_rules! impl_slice {
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<Address<S>>, range: Range<Address<S>>,
) -> VolumeSlice<'a, T, Address<S>> { ) -> VolumeSlice<'a, T, S> {
let index = range.start; let index = range.start;
let range = range.start.into_index() as usize let range = range.start.into_index() as usize
..range.end.into_index() as usize; ..range.end.into_index() as usize;
@ -267,7 +229,7 @@ macro_rules! impl_slice {
fn slice<'a>( fn slice<'a>(
&'a self, &'a self,
range: Range<Address<S>>, range: Range<Address<S>>,
) -> Result<VolumeSlice<'a, T, Address<S>>, Self::Error> { ) -> Result<VolumeSlice<'a, T, S>, Self::Error> {
if self.size() >= range.end { if self.size() >= range.end {
unsafe { Ok(self.slice_unchecked(range)) } unsafe { Ok(self.slice_unchecked(range)) }
} else { } else {
@ -299,16 +261,16 @@ mod file {
use std::fs::File; use std::fs::File;
use std::cell::RefCell; use std::cell::RefCell;
use sector::{Address, Size}; use sector::{Address, SectorSize};
use super::{Volume, VolumeCommit, VolumeSlice}; use super::{Volume, VolumeCommit, VolumeSlice};
use super::length::Length; use super::size::Size;
impl<S: Size> Volume<u8, Address<S>> for RefCell<File> { impl<S: SectorSize> Volume<u8, S> for RefCell<File> {
type Error = io::Error; type Error = io::Error;
fn size(&self) -> Length<Address<S>> { fn size(&self) -> Size<S> {
Length::Bounded( Size::Bounded(
self.borrow() self.borrow()
.metadata() .metadata()
.map(|data| Address::from(data.len())) .map(|data| Address::from(data.len()))
@ -318,11 +280,11 @@ mod file {
fn commit( fn commit(
&mut self, &mut self,
slice: Option<VolumeCommit<u8, Address<S>>>, slice: Option<VolumeCommit<u8, S>>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
slice slice
.map(|slice| { .map(|slice| {
let index = *slice.at_index(); let index = slice.address();
let mut refmut = self.borrow_mut(); let mut refmut = self.borrow_mut();
refmut refmut
.seek(SeekFrom::Start(index.into_index())) .seek(SeekFrom::Start(index.into_index()))
@ -335,7 +297,7 @@ mod file {
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<Address<S>>, range: Range<Address<S>>,
) -> VolumeSlice<'a, u8, Address<S>> { ) -> VolumeSlice<'a, u8, S> {
let index = range.start; let index = range.start;
let len = range.end - range.start; let len = range.end - range.start;
let mut vec = Vec::with_capacity(len.into_index() as usize); let mut vec = Vec::with_capacity(len.into_index() as usize);
@ -353,7 +315,7 @@ mod file {
fn slice<'a>( fn slice<'a>(
&'a self, &'a self,
range: Range<Address<S>>, range: Range<Address<S>>,
) -> Result<VolumeSlice<'a, u8, Address<S>>, Self::Error> { ) -> Result<VolumeSlice<'a, u8, S>, Self::Error> {
let index = range.start; let index = range.start;
let mut vec = Vec::with_capacity((range.end - range.start) let mut vec = Vec::with_capacity((range.end - range.start)
.into_index() .into_index()

100
src/volume/size.rs Normal file
View file

@ -0,0 +1,100 @@
use core::fmt::{self, Display};
use core::cmp::Ordering;
use sector::{Address, SectorSize};
#[derive(Clone, Copy, Debug, Hash)]
pub enum Size<S: SectorSize> {
Unbounded,
Bounded(Address<S>),
}
impl<S: SectorSize> Size<S> {
pub fn try_len(&self) -> Option<Address<S>> {
match *self {
Size::Unbounded => None,
Size::Bounded(n) => Some(n),
}
}
pub unsafe fn len(&self) -> Address<S> {
match *self {
Size::Unbounded => panic!(
"attempt to convert `Size::Unbounded` to a concrete length"
),
Size::Bounded(n) => n,
}
}
}
impl<S: SectorSize> Size<S> {
pub fn is_bounded(&self) -> bool {
match *self {
Size::Unbounded => false,
Size::Bounded(_) => true,
}
}
}
impl<S: SectorSize> Display for Size<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Size::Unbounded => write!(f, "Unbounded"),
Size::Bounded(n) => write!(f, "Bounded({})", n),
}
}
}
impl<S: SectorSize> PartialEq for Size<S> {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Size::Unbounded, _) => false,
(_, &Size::Unbounded) => false,
(&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.eq(b),
}
}
fn ne(&self, rhs: &Self) -> bool {
match (self, rhs) {
(&Size::Unbounded, _) => false,
(_, &Size::Unbounded) => false,
(&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.ne(b),
}
}
}
impl<S: SectorSize> PartialEq<Address<S>> for Size<S> {
fn eq(&self, rhs: &Address<S>) -> bool {
match *self {
Size::Unbounded => false,
Size::Bounded(ref n) => n.eq(rhs),
}
}
fn ne(&self, rhs: &Address<S>) -> bool {
match *self {
Size::Unbounded => false,
Size::Bounded(ref n) => n.eq(rhs),
}
}
}
impl<S: SectorSize> PartialOrd for Size<S> {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
match (self, rhs) {
(&Size::Unbounded, &Size::Unbounded) => None,
(&Size::Unbounded, _) => Some(Ordering::Greater),
(_, &Size::Unbounded) => Some(Ordering::Less),
(&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.partial_cmp(b),
}
}
}
impl<S: SectorSize> PartialOrd<Address<S>> for Size<S> {
fn partial_cmp(&self, rhs: &Address<S>) -> Option<Ordering> {
match *self {
Size::Unbounded => Some(Ordering::Greater),
Size::Bounded(ref n) => n.partial_cmp(rhs),
}
}
}