use crate::error::Error;
use ic_stable_structures::BoundedStorable;
use serde::{Deserialize, Serialize};
pub const FILE_CHUNK_SIZE: usize = 4096;
pub const MAX_FILE_NAME: usize = 255;
pub type Node = u64;
pub type FileSize = u64;
pub type FileChunkIndex = u32;
#[derive(Clone, Debug)]
pub struct FileChunk {
pub bytes: [u8; FILE_CHUNK_SIZE],
}
impl Default for FileChunk {
fn default() -> Self {
Self {
bytes: [0; FILE_CHUNK_SIZE],
}
}
}
impl ic_stable_structures::Storable for FileChunk {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
std::borrow::Cow::Borrowed(&self.bytes)
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
Self {
bytes: bytes.as_ref().try_into().unwrap(),
}
}
}
impl ic_stable_structures::BoundedStorable for FileChunk {
const MAX_SIZE: u32 = FILE_CHUNK_SIZE as u32;
const IS_FIXED_SIZE: bool = true;
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Metadata {
pub node: Node,
pub file_type: FileType,
pub link_count: u64,
pub size: FileSize,
pub times: Times,
pub first_dir_entry: Option<DirEntryIndex>,
pub last_dir_entry: Option<DirEntryIndex>,
}
impl ic_stable_structures::Storable for Metadata {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
let mut buf = vec![];
ciborium::ser::into_writer(&self, &mut buf).unwrap();
assert!(Self::MAX_SIZE >= buf.len() as u32, "Metadata size assertion fails: Self::MAX_SIZE = {}, buf.len() = {}", Self::MAX_SIZE, buf.len());
std::borrow::Cow::Owned(buf)
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
ciborium::de::from_reader(bytes.as_ref()).unwrap()
}
}
impl ic_stable_structures::BoundedStorable for Metadata {
const MAX_SIZE: u32 = 144;
const IS_FIXED_SIZE: bool = true;
}
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FileType {
Directory,
#[default]
RegularFile,
SymbolicLink,
}
impl TryFrom<u8> for FileType {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
3 => Ok(FileType::Directory),
4 => Ok(FileType::RegularFile),
7 => Ok(FileType::SymbolicLink),
_ => Err(Error::InvalidFileType),
}
}
}
impl From<FileType> for u8 {
fn from(val: FileType) -> Self {
match val {
FileType::Directory => 3,
FileType::RegularFile => 4,
FileType::SymbolicLink => 7,
}
}
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub struct Times {
pub accessed: u64,
pub modified: u64,
pub created: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FileName {
pub length: u8,
#[serde(
deserialize_with = "deserialize_file_name",
serialize_with = "serialize_file_name"
)]
pub bytes: [u8; MAX_FILE_NAME],
}
fn serialize_file_name<S>(bytes: &[u8; MAX_FILE_NAME], serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_bytes::Bytes::new(bytes).serialize(serializer)
}
fn deserialize_file_name<'de, D>(deserializer: D) -> Result<[u8; MAX_FILE_NAME], D::Error>
where
D: serde::Deserializer<'de>,
{
let bytes: Vec<u8> = serde_bytes::deserialize(deserializer).unwrap();
let len = bytes.len();
let bytes_array: [u8; MAX_FILE_NAME] = bytes
.try_into()
.map_err(|_| serde::de::Error::invalid_length(len, &"expected MAX_FILE_NAME bytes"))?;
Ok(bytes_array)
}
impl Default for FileName {
fn default() -> Self {
Self {
length: 0,
bytes: [0; MAX_FILE_NAME],
}
}
}
impl FileName {
pub fn new(name: &str) -> Result<Self, Error> {
let name = name.as_bytes();
let len = name.len();
if len > MAX_FILE_NAME {
return Err(Error::NameTooLong);
}
let mut bytes = [0; MAX_FILE_NAME];
bytes[0..len].copy_from_slice(name);
Ok(Self {
length: len as u8,
bytes,
})
}
}
pub type DirEntryIndex = u32;
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct DirEntry {
pub name: FileName,
pub node: Node,
pub next_entry: Option<DirEntryIndex>,
pub prev_entry: Option<DirEntryIndex>,
}
impl ic_stable_structures::Storable for DirEntry {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
let mut buf = vec![];
ciborium::ser::into_writer(&self, &mut buf).unwrap();
assert!(Self::MAX_SIZE >= buf.len() as u32, "DirEntry size assertion fails: Self::MAX_SIZE = {}, buf.len() = {}", Self::MAX_SIZE, buf.len());
std::borrow::Cow::Owned(buf)
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
ciborium::de::from_reader(bytes.as_ref()).unwrap()
}
}
impl ic_stable_structures::BoundedStorable for DirEntry {
const MAX_SIZE: u32 = 320;
const IS_FIXED_SIZE: bool = true;
}