use super::{FileStructureError, GetFileNameTrait, file::File};
use crate::data_structures::{VerifierDataDecode, VerifierDataToTypeTrait, VerifierDataType};
use std::{
fs,
marker::PhantomData,
path::{Path, PathBuf},
sync::Arc,
};
#[derive(Clone)]
pub struct FileGroup<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> {
location: PathBuf,
indexes: Vec<usize>,
phantom: PhantomData<D>,
}
pub struct FileGroupFileIter<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> {
pub file_group: FileGroup<D>,
pos: usize,
}
pub struct FileGroupDataIter<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> {
pub file_group_iter: FileGroupFileIter<D>,
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> From<FileGroupFileIter<D>>
for FileGroupDataIter<D>
{
fn from(value: FileGroupFileIter<D>) -> Self {
Self {
file_group_iter: value,
}
}
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> Iterator for FileGroupFileIter<D> {
type Item = (usize, File<D>);
fn next(&mut self) -> Option<Self::Item> {
match self.is_over() {
true => None,
false => {
let res = (*self.current_index().unwrap(), self.current_file().unwrap());
self.pos += 1;
Some(res)
}
}
}
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> Iterator for FileGroupDataIter<D> {
type Item = (usize, Result<Arc<D>, FileStructureError>);
fn next(&mut self) -> Option<Self::Item> {
self.file_group_iter
.next()
.map(|(i, f)| (i, f.decode_verifier_data()))
}
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> FileGroupFileIter<D> {
pub fn new(file_group: &FileGroup<D>) -> Self {
FileGroupFileIter {
file_group: file_group.clone(),
pos: 0,
}
}
pub fn current_pos(&self) -> &usize {
&self.pos
}
pub fn current_index(&self) -> Option<&usize> {
match self.pos < self.file_group.get_numbers().len() {
true => Some(&self.file_group.get_numbers()[self.pos]),
false => None,
}
}
pub fn current_file(&self) -> Option<File<D>> {
self.current_index()
.map(|i| File::new(&self.file_group.location, Some(*i)))
}
fn is_over(&self) -> bool {
self.current_index().is_none()
}
}
impl<D: VerifierDataDecode + VerifierDataToTypeTrait + Clone> FileGroup<D> {
pub fn new(location: &Path) -> Self {
let mut res = Self {
location: location.to_path_buf(),
indexes: vec![],
phantom: PhantomData,
};
res.set_numbers();
res
}
fn set_numbers(&mut self) {
if self.location_exists() {
for e in fs::read_dir(&self.location).unwrap() {
let name = e.unwrap().file_name().to_str().unwrap().to_string();
let matching = Self::data_type().get_raw_file_name();
let matching_splitted: Vec<&str> = matching.split("{}").collect();
let tmp = name
.replace(matching_splitted[0], "")
.replace(matching_splitted[1], "")
.parse::<usize>();
if let Ok(i) = tmp {
self.indexes.push(i)
}
}
self.indexes.sort()
}
}
pub fn data_type() -> VerifierDataType {
D::data_type()
}
pub fn get_location(&self) -> &Path {
self.location.as_path()
}
pub fn get_file_name(&self) -> String {
Self::data_type().get_raw_file_name()
}
pub fn location_exists(&self) -> bool {
self.location.is_dir()
}
pub fn has_elements(&self) -> bool {
!self.indexes.is_empty()
}
pub fn get_paths(&self) -> Vec<PathBuf> {
self.iter_file()
.map(|(_, f)| f.path().to_path_buf())
.collect()
}
pub fn get_numbers(&self) -> &Vec<usize> {
&self.indexes
}
pub fn get_file_with_number(&self, number: usize) -> File<D> {
File::new(&self.location, Some(number))
}
pub fn iter_file(&self) -> FileGroupFileIter<D> {
FileGroupFileIter::new(self)
}
pub fn iter(&self) -> FileGroupDataIter<D> {
FileGroupDataIter::from(self.iter_file())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
config::test::test_datasets_context_path, consts::CONTROL_COMPONENT_ID_LIST,
data_structures::context::control_component_public_keys_payload::ControlComponentPublicKeysPayload,
};
#[test]
fn test_file_group() {
let location = test_datasets_context_path();
let fg = FileGroup::<ControlComponentPublicKeysPayload>::new(&location);
assert!(fg.location_exists());
assert!(fg.has_elements());
assert_eq!(fg.get_location(), location);
assert_eq!(fg.get_numbers(), &CONTROL_COMPONENT_ID_LIST);
for (i, f) in fg.iter_file() {
let name = format!("controlComponentPublicKeysPayload.{i}.json");
assert_eq!(f.path(), location.join(name));
}
}
#[test]
fn test_get_file_with_number() {
let location = test_datasets_context_path();
let fg = FileGroup::<ControlComponentPublicKeysPayload>::new(&location);
let f = fg.get_file_with_number(1);
assert_eq!(
f.path(),
location.join("controlComponentPublicKeysPayload.1.json")
);
}
#[test]
fn test_file_group_not_exist() {
let location = test_datasets_context_path().join("toto");
let fg = FileGroup::<ControlComponentPublicKeysPayload>::new(&location);
assert!(!fg.location_exists());
assert!(!fg.has_elements());
assert_eq!(fg.get_location(), location);
assert!(fg.get_numbers().is_empty());
assert!(fg.iter_file().next().is_none());
}
}