1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! The `Storage`, `Read`, `Write` and `Seek` driver.
#![allow(non_camel_case_types)]

use generic_array::ArrayLength;
use littlefs2_sys as ll;

use crate::{
    io::Result,
};

/// Users of this library provide a "storage driver" by implementing this trait.
///
/// The `write` method is assumed to be synchronized to storage immediately.
/// littlefs provides more flexibility - if required, this could also be exposed.
/// Do note that due to caches, files still must be synched. And unfortunately,
/// this can't be automatically done in `drop`, since it needs mut refs to both
/// filesystem and storage.
///
/// The `*_SIZE` types must be `generic_array::typenume::consts` such as `U256`.
///
/// Why? Currently, associated constants can not be used (as constants...) to define
/// arrays. This "will be fixed" as part of const generics.
/// Once that's done, we can get rid of `generic-array`s, and replace the
/// `*_SIZE` types with `usize`s.
pub trait Storage {

    // /// Error type for user-provided read/write/erase methods
    // type Error = usize;

    /// Minimum size of block read in bytes. Not in superblock
    const READ_SIZE: usize;

    /// Minimum size of block write in bytes. Not in superblock
    const WRITE_SIZE: usize;

    /// Size of an erasable block in bytes, as unsigned typenum.
    /// Must be a multiple of both `READ_SIZE` and `WRITE_SIZE`.
    /// At least 128 (https://git.io/JeHp9). Stored in superblock.
    const BLOCK_SIZE: usize;

    /// Number of erasable blocks.
    /// Hence storage capacity is `BLOCK_COUNT * BLOCK_SIZE`
    const BLOCK_COUNT: usize;

    /// Suggested values are 100-1000, higher is more performant but
    /// less wear-leveled.  Default of -1 disables wear-leveling.
    /// Value zero is invalid, must be positive or -1.
    const BLOCK_CYCLES: isize = -1;

    /// littlefs uses a read cache, a write cache, and one cache per per file.
    /// Must be a multiple of `READ_SIZE` and `WRITE_SIZE`.
    /// Must be a factor of `BLOCK_SIZE`.
    type CACHE_SIZE: ArrayLength<u8>;

    /// littlefs itself has a `LOOKAHEAD_SIZE`, which must be a multiple of 8,
    /// as it stores data in a bitmap. It also asks for 4-byte aligned buffers.
    /// Hence, we further restrict `LOOKAHEAD_SIZE` to be a multiple of 32.
    /// Our LOOKAHEADWORDS_SIZE is this multiple.
    type LOOKAHEADWORDS_SIZE: ArrayLength<u32>;
    // type LOOKAHEAD_SIZE: ArrayLength<u8>;

    ///// Maximum length of a filename plus one. Stored in superblock.
    ///// Should default to 255+1, but associated type defaults don't exist currently.
    ///// At most 1_022+1.
    /////
    ///// TODO: We can't actually change this - need to pass on as compile flag
    ///// to the C backend.
    //type FILENAME_MAX_PLUS_ONE: ArrayLength<u8>;

    // /// Maximum length of a path plus one. Necessary to convert Rust string slices
    // /// to C strings, which requires an allocation for the terminating
    // /// zero-byte. If in doubt, set to `FILENAME_MAX_PLUS_ONE`.
    // /// Must be larger than `FILENAME_MAX_PLUS_ONE`.
    // type PATH_MAX_PLUS_ONE: ArrayLength<u8>;

    ///// Maximum size of file. Stored in superblock.
    ///// Defaults to 2_147_483_647 (or u31, to avoid sign issues in the C code).
    ///// At most 2_147_483_647.
    /////
    ///// TODO: We can't actually change this - need to pass on as compile flag
    ///// to the C backend.
    //const FILEBYTES_MAX: usize = ll::LFS_FILE_MAX as _;

    ///// Maximum size of custom attributes.
    ///// Should default to 1_022, but associated type defaults don't exists currently.
    ///// At most 1_022.
    /////
    ///// TODO: We can't actually change this - need to pass on as compile flag
    ///// to the C backend.
    //type ATTRBYTES_MAX: ArrayLength<u8>;

    /// Read data from the storage device.
    /// Guaranteed to be called only with bufs of length a multiple of READ_SIZE.
    fn read(&self, off: usize, buf: &mut [u8]) -> Result<usize>;
    /// Write data to the storage device.
    /// Guaranteed to be called only with bufs of length a multiple of WRITE_SIZE.
    fn write(&mut self, off: usize, data: &[u8]) -> Result<usize>;
    /// Erase data from the storage device.
    /// Guaranteed to be called only with bufs of length a multiple of BLOCK_SIZE.
    fn erase(&mut self, off: usize, len: usize) -> Result<usize>;
    // /// Synchronize writes to the storage device.
    // fn sync(&mut self) -> Result<usize>;
}

// in the future, try to split the megatrait `Storage` into pieces
// like this?
mod future {
    // content of "superblock"
    pub trait DiskFormat {
        // version, upper/lower half-word contain major/minor
        // const DISK_FORMAT_VERSION: u32,

        // block_size, block_count
        const BLOCK_SIZE: usize;
        const BLOCK_COUNT: usize;

        // name_max, file_max, attr_max
        type FILENAME_MAX_PLUS_ONE;
        const FILEBYTES_MAX: usize = super::ll::LFS_FILE_MAX as _;
        type ATTRBYTES_MAX;
    }

    pub trait Driver {
        const READ_SIZE: usize;
        const WRITE_SIZE: usize;

        const BLOCK_SIZE: usize;
        const BLOCK_COUNT: usize;

        // fn read(&self, offset: usize, buf: &mut [u8]) -> Result<usize>;
        // fn write(&mut self, offset: usize, data: &[u8]) -> Result<usize>;
        // fn erase(&mut self, offset: usize, len: usize) -> Result<usize>;
    }

    pub trait MemoryUsage {
        // TODO: this supposedly influences whether files are inlined or not. Clarify
        type CACHE_SIZE;
        type LOOKAHEADWORDS_SIZE;
    }

    pub trait RuntimeParameters {
        const BLOCK_CYCLES: isize = -1;
    }
}