use crate::ffi::nfs::File as FfiFile;
use crate::nfs::errors::NfsError;
use chrono::{DateTime, NaiveDateTime, Utc};
use ffi_utils::{vec_clone_from_raw_parts, vec_into_raw_parts, ReprC};
use safe_nd::{IDataAddress, IDataKind};
use serde::{Deserialize, Serialize};
use xor_name::XorName;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct File {
size: u64,
created: DateTime<Utc>,
modified: DateTime<Utc>,
user_metadata: Vec<u8>,
data_map_name: XorName,
published: bool,
}
impl File {
pub fn new(user_metadata: Vec<u8>, published: bool) -> Self {
Self {
size: 0,
created: Utc::now(),
modified: Utc::now(),
user_metadata,
data_map_name: XorName::default(),
published,
}
}
pub fn into_repr_c(self) -> FfiFile {
let user_metadata = self.user_metadata().to_vec();
let (user_metadata, user_metadata_len) = vec_into_raw_parts(user_metadata);
FfiFile {
size: self.size(),
created_sec: self.created_time().timestamp(),
created_nsec: self.created_time().timestamp_subsec_nanos(),
modified_sec: self.modified_time().timestamp(),
modified_nsec: self.modified_time().timestamp_subsec_nanos(),
user_metadata,
user_metadata_len,
data_map_name: self.data_map_name().0,
published: self.published(),
}
}
pub fn created_time(&self) -> &DateTime<Utc> {
&self.created
}
pub fn modified_time(&self) -> &DateTime<Utc> {
&self.modified
}
pub fn data_map_name(&self) -> &XorName {
&self.data_map_name
}
pub fn size(&self) -> u64 {
self.size
}
pub fn user_metadata(&self) -> &[u8] {
&self.user_metadata
}
pub fn published(&self) -> bool {
self.published
}
pub fn data_address(&self) -> IDataAddress {
let kind = IDataKind::from_flag(self.published());
IDataAddress::from_kind(kind, *self.data_map_name())
}
pub fn set_data_map_name(&mut self, datamap_name: XorName) {
self.data_map_name = datamap_name;
}
pub fn set_size(&mut self, size: u64) {
self.size = size;
}
pub fn set_created_time(&mut self, created_time: DateTime<Utc>) {
self.created = created_time
}
pub fn set_modified_time(&mut self, modified_time: DateTime<Utc>) {
self.modified = modified_time
}
pub fn set_user_metadata(&mut self, user_metadata: Vec<u8>) {
self.user_metadata = user_metadata;
}
}
impl ReprC for File {
type C = *const FfiFile;
type Error = NfsError;
#[allow(unsafe_code)]
unsafe fn clone_from_repr_c(repr_c: Self::C) -> Result<Self, Self::Error> {
let user_metadata =
vec_clone_from_raw_parts((*repr_c).user_metadata, (*repr_c).user_metadata_len);
let created = convert_date_time((*repr_c).created_sec, (*repr_c).created_nsec)?;
let modified = convert_date_time((*repr_c).modified_sec, (*repr_c).modified_nsec)?;
let mut file = Self::new(user_metadata, (*repr_c).published);
file.set_size((*repr_c).size);
file.set_created_time(created);
file.set_modified_time(modified);
file.set_data_map_name(XorName((*repr_c).data_map_name));
Ok(file)
}
}
#[inline]
fn convert_date_time(sec: i64, nano_sec: u32) -> Result<DateTime<Utc>, NfsError> {
let naive = NaiveDateTime::from_timestamp_opt(sec, nano_sec)
.ok_or_else(|| NfsError::Unexpected("Invalid date format".to_string()))?;
Ok(DateTime::<Utc>::from_utc(naive, Utc))
}
#[cfg(test)]
mod tests {
use super::*;
use bincode::{deserialize, serialize};
use unwrap::unwrap;
#[test]
fn serialise_deserialise() {
let obj_before = File::new("{mime:\"application/json\"}".to_string().into_bytes(), true);
let serialised_data = unwrap!(serialize(&obj_before));
let obj_after = unwrap!(deserialize(&serialised_data));
assert_eq!(obj_before, obj_after);
}
}