use alloc::vec::Vec;
use crate::types::{Error, Result};
pub(crate) const LFS_TYPE_REG: u16 = 0x001;
pub(crate) const LFS_TYPE_DIR: u16 = 0x002;
pub(crate) const LFS_TYPE_SUPERBLOCK: u16 = 0x0ff;
pub(crate) const LFS_TYPE_DIRSTRUCT: u16 = 0x200;
pub(crate) const LFS_TYPE_INLINESTRUCT: u16 = 0x201;
pub(crate) const LFS_TYPE_CTZSTRUCT: u16 = 0x202;
pub(crate) const LFS_TYPE_USERATTR: u16 = 0x300;
pub(crate) const LFS_TYPE_CREATE: u16 = 0x401;
pub(crate) const LFS_TYPE_DELETE: u16 = 0x4ff;
pub(crate) const LFS_TYPE_SOFTTAIL: u16 = 0x600;
pub(crate) const LFS_TYPE_HARDTAIL: u16 = 0x601;
pub(crate) const LFS_TYPE_MOVESTATE: u16 = 0x7ff;
pub(crate) const LFS_TYPE_CCRC_MASK: u16 = 0x780;
pub(crate) const LFS_TYPE_CCRC_VALUE: u16 = 0x500;
pub(crate) const LFS_TYPE_FCRC: u16 = 0x5ff;
pub(crate) const LFS_NULL: u32 = 0xffff_ffff;
#[derive(Debug, Clone)]
pub(crate) struct Entry {
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) tag: Tag,
pub(crate) data: Vec<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Tag(pub(crate) u32);
impl Tag {
pub(crate) fn new(type3: u16, id: u16, size: u16) -> Self {
Self(((type3 as u32) << 20) | ((id as u32) << 10) | size as u32)
}
pub(crate) fn is_valid(self) -> bool {
self.0 & 0x8000_0000 == 0
}
pub(crate) fn is_delete(self) -> bool {
self.size() == 0x3ff
}
pub(crate) fn type3(self) -> u16 {
((self.0 & 0x7ff0_0000) >> 20) as u16
}
pub(crate) fn id(self) -> u16 {
((self.0 & 0x000f_fc00) >> 10) as u16
}
pub(crate) fn size(self) -> u16 {
(self.0 & 0x0000_03ff) as u16
}
pub(crate) fn dsize(self) -> Result<usize> {
if self.is_delete() {
Ok(4)
} else {
Ok(4 + self.size() as usize)
}
}
pub(crate) fn is_ccrc(self) -> bool {
(self.type3() & LFS_TYPE_CCRC_MASK) == LFS_TYPE_CCRC_VALUE
}
pub(crate) fn lookup_mask(self) -> Self {
let is_unique = self.0 & 0x1000_0000 == 0;
let is_attr = self.0 & 0x4000_0000 == 0;
Self(
((if is_unique { 0x7ff } else { 0x700 }) << 20)
| ((if is_attr { 0x3ff } else { 0 }) << 10),
)
}
pub(crate) fn matches(self, mask: Tag, want: Tag) -> bool {
(self.0 & mask.0) == (want.0 & mask.0)
}
}
pub(crate) fn le32(data: &[u8]) -> Result<u32> {
let bytes: [u8; 4] = data.try_into().map_err(|_| Error::Corrupt)?;
Ok(u32::from_le_bytes(bytes))
}
pub(crate) fn be32(data: &[u8]) -> Result<u32> {
let bytes: [u8; 4] = data.try_into().map_err(|_| Error::Corrupt)?;
Ok(u32::from_be_bytes(bytes))
}
pub(crate) fn seq_after(a: u32, b: u32) -> bool {
(a.wrapping_sub(b) & 0x8000_0000) == 0
}
pub(crate) fn ctz(x: u32) -> u32 {
x.trailing_zeros()
}
pub(crate) fn popc(x: u32) -> u32 {
x.count_ones()
}
pub(crate) fn npw2(x: u32) -> u32 {
if x <= 1 {
0
} else {
u32::BITS - (x - 1).leading_zeros()
}
}
pub(crate) fn crc32(mut crc: u32, data: &[u8]) -> u32 {
const RTABLE: [u32; 16] = [
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158,
0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4,
0xa00ae278, 0xbdbdf21c,
];
for byte in data {
crc = (crc >> 4) ^ RTABLE[((crc ^ (*byte as u32)) & 0xf) as usize];
crc = (crc >> 4) ^ RTABLE[((crc ^ ((*byte as u32) >> 4)) & 0xf) as usize];
}
crc
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn crc_matches_known_littlefs_vector() {
assert_eq!(crc32(0xffff_ffff, b"littlefs"), 0x5a11_385b);
}
}