Expand description
Everything related to the devices.
§Devices
In this crate, a Device is a structure capable of storing a fixed number of contiguous bytes. Each byte is
located at a unique Address, which is used to describe Slices. When a Slice is mutated, it can be
committed into a Commit, which can be write back on the Device.
To avoid manipulating only Slices and Commits, which is quite heavy, you can manipulate a Device through
the provided metehods read_from_bytes and write_to_bytes.
If needed for the Filesystem usage, the device may be able to give the current time.
§How to implement a device?
§Derived automatically
The easiest way for an object to implement Device is to make it implements the traits Read, Write and
Seek from deku::no_std_io or no_std_io2 (which is the same crate
re-exported). The advantage of such requirements is that in a std environment, those traits are exactly the
ones of std::io, which is helpful not to define twice the same functions.
use std::error::Error;
use std::fmt::Display;
use deku::DekuRead;
use deku::no_std_io::{Read, Seek, SeekFrom, Write};
use efs::dev::Device;
use efs::dev::address::Address;
use efs::fs::file::Base;
struct Foo {} // Foo is our device
impl Read for Foo {
fn read(&mut self, buf: &mut [u8]) -> deku::no_std_io::Result<usize> {
buf.fill(1);
Ok(buf.len())
}
}
impl Write for Foo {
fn write(&mut self, buf: &[u8]) -> deku::no_std_io::Result<usize> {
Ok(buf.len())
}
fn flush(&mut self) -> deku::no_std_io::Result<()> {
Ok(())
}
}
impl Seek for Foo {
fn seek(&mut self, _pos: SeekFrom) -> deku::no_std_io::Result<u64> {
Ok(0)
}
}
#[derive(Debug, PartialEq, Eq, DekuRead)]
struct Bar {
a: u8,
b: u32,
}
let mut foo = Foo {};
// Now `foo` implements `Device,
// thus we can use all the methods from the `Device` trait.
assert_eq!(foo.read_from_bytes::<Bar>(Address::new(0), 5).unwrap(), Bar {
a: 0x1,
b: 0x0101_0101
});Moreover, when using the std feature, the devices derived automatically will use std_now for the
implementation of the Device::now method.
§By hand
To implement a device, you need to provide three methods:
-
sizewhich returns the size of the device in bytes -
commitwhich commits aCommitcreated from a mutatedSliceof the device -
now(optional) which returns the current time.
To help you, here is an example of how those methods can be used:
use std::vec;
use efs::dev::address::Address;
use efs::dev::{Device, Wrapper};
// Here, our device is a `Wrapper<Vec<usize>>`
let mut device = Wrapper::new(vec![0_u8; 1024]);
// We take a slice of the device: `slice` now contains a reference to the
// objects between the indices 256 (included) and 512 (not included) of the
// device.
let mut slice = device.slice(Address::from(256_u64)..Address::from(512_u64)).unwrap();
// We modify change each elements `0` to a `1` in the slice.
slice.iter_mut().for_each(|element| *element = 1);
// We commit the changes of slice: now this slice cannot be changed anymore.
let commit = slice.commit();
assert!(device.commit(commit).is_ok());
for (idx, &x) in device.iter().enumerate() {
assert_eq!(x, u8::from((256..512).contains(&idx)));
}Moreover, your implementation of a device should only returns deku::no_std_io::Error error in case of a
read/write fail.
Modules§
Structs§
- Commit
- Commited slice of a device, filled with objects of type
T. - Slice
- Slice of a device, filled with objects of type
T. - Wrapper
- Wrapper structure to be able to use
Vec,Boxandarrayas devices.
Traits§
- Device
- General interface for devices containing a file system.