littlefs2 0.3.1

Idiomatic Rust API for littlefs
Documentation
//! Traits and types for core I/O functionality.

pub mod prelude;

use littlefs2_sys as ll;

/// The `Read` trait allows for reading bytes from a file.
pub trait Read {
    /// Read at most buf.len() bytes.
    /// Upon success, return how many bytes were read.
    fn read(&self, buf: &mut [u8]) -> Result<usize>;

    fn read_exact(&self, buf: &mut [u8]) -> Result<()> {
        // Same assumption as for `read_to_end`.
        let len = self.read(buf)?;
        if len == buf.len() {
            Ok(())
        } else {
            // TODO: Decide whether to add an equivalent of `ErrorKind::UnexpectedEof`
            Err(Error::Io)
        }
    }

}

/** The `Write` trait allows for writing bytes to a file.

By analogy with `std::io::Write`, we also define a `flush()`
method. In the current implementation, writes are final and
flush has no effect.
*/
pub trait Write {
    /// Write at most data.len() bytes.
    /// The file will not necessarily be updated unless
    /// flush is called as there is a cache.
    /// Upon success, return how many bytes were written.
    fn write(&self, data: &[u8]) -> Result<usize>;

    /// Write out all pending writes to storage.
    fn flush(&self) -> Result<()>;

    fn write_all(&self, mut buf: &[u8]) -> Result<()> {
        while !buf.is_empty() {
            match self.write(buf) {
                Ok(0) => {
                    // failed to write whole buffer
                    return Err(Error::Io)
                }
                Ok(n) => buf = &buf[n..],
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

/** Enumeration of possible methods to seek within an I/O object.

Use the [`Seek`](../io/trait.Seek.html) trait.
*/
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub enum SeekFrom {
    Start(u32),
    End(i32),
    Current(i32),
}

impl SeekFrom {
    pub(crate) fn off(self) -> i32 {
        match self {
            SeekFrom::Start(u) => u as i32,
            SeekFrom::End(i) => i,
            SeekFrom::Current(i) => i,
        }
    }

    pub(crate) fn whence(self) -> i32 {
        match self {
            SeekFrom::Start(_) => 0,
            SeekFrom::End(_) => 2,
            SeekFrom::Current(_) => 1,
        }
    }
}

/** The `Seek` trait provides a cursor which can be moved within a file.

It is possible to seek relative to either end or the current offset.
*/
pub trait Seek {
    /// Seek to an offset in bytes.
    /// If successful, returns the new position from start of file.
    fn seek(&self, pos: SeekFrom) -> Result<usize>;
}

pub type Result<T> = core::result::Result<T, Error>;

/// Definition of errors that might be returned by filesystem functionality.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Error {
    /// Error code was >=0, operation was successful.
    Success,
    /// Input / output error occurred.
    Io,
    /// File or filesystem was corrupt.
    Corruption,
    /// No entry found with that name.
    NoSuchEntry,
    /// File or directory already exists.
    EntryAlreadyExisted,
    /// Path name is not a directory.
    PathNotDir,
    /// Path specification is to a directory.
    PathIsDir,
    /// Directory was not empty.
    DirNotEmpty,
    /// Bad file descriptor.
    BadFileDescriptor,
    /// File is too big.
    FileTooBig,
    /// Incorrect value specified to function.
    Invalid,
    /// No space left available for operation.
    NoSpace,
    /// No memory available for completing request.
    NoMemory,
    /// No attribute or data available
    NoAttribute,
    /// Filename too long
    FilenameTooLong,
    /// Unknown error occurred, integer code specified.
    Unknown(i32),
}

impl From<crate::path::Error> for Error {
    fn from(_error: crate::path::Error) -> Self {
        Error::Io
    }
}

impl From<i32> for Error {
    fn from(error_code: i32) -> Error {
        match error_code {
            n if n >= 0 => Error::Success,
            // negative codes
            ll::lfs_error_LFS_ERR_IO => Error::Io,
            ll::lfs_error_LFS_ERR_CORRUPT => Error::Corruption,
            ll::lfs_error_LFS_ERR_NOENT => Error::NoSuchEntry,
            ll::lfs_error_LFS_ERR_EXIST => Error::EntryAlreadyExisted,
            ll::lfs_error_LFS_ERR_NOTDIR => Error::PathNotDir,
            ll::lfs_error_LFS_ERR_ISDIR => Error::PathIsDir,
            ll::lfs_error_LFS_ERR_NOTEMPTY => Error::DirNotEmpty,
            ll::lfs_error_LFS_ERR_BADF => Error::BadFileDescriptor,
            ll::lfs_error_LFS_ERR_FBIG => Error::FileTooBig,
            ll::lfs_error_LFS_ERR_INVAL => Error::Invalid,
            ll::lfs_error_LFS_ERR_NOSPC => Error::NoSpace,
            ll::lfs_error_LFS_ERR_NOMEM => Error::NoMemory,
            ll::lfs_error_LFS_ERR_NOATTR => Error::NoAttribute,
            ll::lfs_error_LFS_ERR_NAMETOOLONG => Error::FilenameTooLong,
            // positive codes should always indicate success
            _ => Error::Unknown(error_code),
        }
    }
}

pub fn result_from<T>(return_value: T, error_code: ll::lfs_error) -> Result<T> {
    let error: Error = error_code.into();
    match error {
        Error::Success => Ok(return_value),
        _ => Err(error)
    }
}