use super::{
CompletnessTestTrait, FileStructureError,
file::{File, create_file},
file_group::{FileGroup, FileGroupDataIter, FileGroupFileIter},
};
use crate::{
config::VerifierConfig,
consts::CONTROL_COMPONENT_ID_LIST,
data_structures::tally::{
control_component_ballot_box_payload::ControlComponentBallotBoxPayload,
control_component_shuffle_payload::ControlComponentShufflePayload, ech_0222::ECH0222,
tally_component_shuffle_payload::TallyComponentShufflePayload,
tally_component_votes_payload::TallyComponentVotesPayload,
},
};
use std::{
fs,
path::{Path, PathBuf},
sync::Arc,
};
pub struct TallyDirectory {
location: PathBuf,
ech_0222_file: File<ECH0222>,
bb_directories: Vec<BBDirectory>,
}
pub struct BBDirectory {
location: PathBuf,
tally_component_votes_payload_file: File<TallyComponentVotesPayload>,
tally_component_shuffle_payload_file: File<TallyComponentShufflePayload>,
control_component_ballot_box_payload_group: FileGroup<ControlComponentBallotBoxPayload>,
control_component_shuffle_payload_group: FileGroup<ControlComponentShufflePayload>,
}
pub trait TallyDirectoryTrait: CompletnessTestTrait + Send + Sync {
type BBDirType: BBDirectoryTrait;
fn ech_0222_file(&self) -> &File<ECH0222>;
fn ech_0222(&self) -> Result<Arc<ECH0222>, FileStructureError>;
fn bb_directories(&self) -> &[Self::BBDirType];
fn bb_directory_names(&self) -> Vec<String> {
self.bb_directories().iter().map(|d| d.name()).collect()
}
fn location(&self) -> &Path;
}
pub trait BBDirectoryTrait: CompletnessTestTrait + Send + Sync {
#[allow(dead_code)]
fn tally_component_votes_payload_file(&self) -> &File<TallyComponentVotesPayload>;
fn tally_component_shuffle_payload_file(&self) -> &File<TallyComponentShufflePayload>;
fn control_component_ballot_box_payload_group(
&self,
) -> &FileGroup<ControlComponentBallotBoxPayload>;
fn control_component_shuffle_payload_group(&self)
-> &FileGroup<ControlComponentShufflePayload>;
fn tally_component_votes_payload(
&self,
) -> Result<Arc<TallyComponentVotesPayload>, FileStructureError>;
fn tally_component_shuffle_payload(
&self,
) -> Result<Arc<TallyComponentShufflePayload>, FileStructureError>;
fn control_component_ballot_box_payload_iter(
&self,
) -> impl Iterator<
Item = (
usize,
Result<Arc<ControlComponentBallotBoxPayload>, FileStructureError>,
),
>;
fn control_component_shuffle_payload_iter(
&self,
) -> impl Iterator<
Item = (
usize,
Result<Arc<ControlComponentShufflePayload>, FileStructureError>,
),
>;
fn name(&self) -> String;
fn location(&self) -> &Path;
}
impl TallyDirectoryTrait for TallyDirectory {
type BBDirType = BBDirectory;
fn ech_0222_file(&self) -> &File<ECH0222> {
&self.ech_0222_file
}
fn ech_0222(&self) -> Result<Arc<ECH0222>, FileStructureError> {
self.ech_0222_file.decode_verifier_data()
}
fn bb_directories(&self) -> &[BBDirectory] {
&self.bb_directories
}
fn location(&self) -> &Path {
self.location.as_path()
}
}
impl CompletnessTestTrait for TallyDirectory {
fn test_completness(&self) -> Result<Vec<String>, FileStructureError> {
let mut missings = vec![];
if !self.ech_0222_file().exists() {
missings.push("ech_0222 does not exist".to_string())
}
if self.bb_directories().is_empty() {
missings.push("No bb directory found".to_string());
}
for d in self.bb_directories().iter() {
missings.extend(d.test_completness()?)
}
Ok(missings)
}
}
impl BBDirectoryTrait for BBDirectory {
fn tally_component_votes_payload_file(&self) -> &File<TallyComponentVotesPayload> {
&self.tally_component_votes_payload_file
}
fn tally_component_shuffle_payload_file(&self) -> &File<TallyComponentShufflePayload> {
&self.tally_component_shuffle_payload_file
}
fn control_component_ballot_box_payload_group(
&self,
) -> &FileGroup<ControlComponentBallotBoxPayload> {
&self.control_component_ballot_box_payload_group
}
fn control_component_shuffle_payload_group(
&self,
) -> &FileGroup<ControlComponentShufflePayload> {
&self.control_component_shuffle_payload_group
}
fn tally_component_votes_payload(
&self,
) -> Result<Arc<TallyComponentVotesPayload>, FileStructureError> {
self.tally_component_votes_payload_file
.decode_verifier_data()
}
fn tally_component_shuffle_payload(
&self,
) -> Result<Arc<TallyComponentShufflePayload>, FileStructureError> {
self.tally_component_shuffle_payload_file
.decode_verifier_data()
}
fn control_component_ballot_box_payload_iter(
&self,
) -> impl Iterator<
Item = (
usize,
Result<Arc<ControlComponentBallotBoxPayload>, FileStructureError>,
),
> {
FileGroupDataIter::from(FileGroupFileIter::new(
&self.control_component_ballot_box_payload_group,
))
}
fn control_component_shuffle_payload_iter(
&self,
) -> impl Iterator<
Item = (
usize,
Result<Arc<ControlComponentShufflePayload>, FileStructureError>,
),
> {
FileGroupDataIter::from(FileGroupFileIter::new(
&self.control_component_shuffle_payload_group,
))
}
fn name(&self) -> String {
self.location
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string()
}
fn location(&self) -> &Path {
self.location.as_path()
}
}
impl CompletnessTestTrait for BBDirectory {
fn test_completness(&self) -> Result<Vec<String>, FileStructureError> {
let mut missings = vec![];
if !self.tally_component_shuffle_payload_file().exists() {
missings.push(format!(
"{:?}/tally_component_shuffle_payload does not exist",
self.location().file_name().unwrap()
))
}
if !self.tally_component_shuffle_payload_file().exists() {
missings.push(format!(
"{:?}/tally_component_shuffle_payload does not exist",
self.location().file_name().unwrap()
))
}
if self
.control_component_ballot_box_payload_group()
.get_numbers()
!= &CONTROL_COMPONENT_ID_LIST
{
missings.push(format!(
"{:?}/control_component_ballot_box_payload missing. only these parts are present: {:?}",
self.location().file_name().unwrap(),
self
.control_component_ballot_box_payload_group()
.get_numbers()
))
}
if self.control_component_shuffle_payload_group().get_numbers()
!= &CONTROL_COMPONENT_ID_LIST
{
missings.push(format!(
"{:?}/control_component_shuffle_payload_group missing. only these parts are present: {:?}",
self.location().file_name().unwrap(),
self
.control_component_shuffle_payload_group()
.get_numbers()
))
}
Ok(missings)
}
}
impl TallyDirectory {
#[allow(clippy::redundant_clone)]
pub fn new(data_location: &Path) -> TallyDirectory {
let location = data_location.join(VerifierConfig::tally_dir_name());
let mut res = TallyDirectory {
location: location.to_path_buf(),
ech_0222_file: create_file!(location, Tally, VerifierTallyDataType::ECH0222),
bb_directories: vec![],
};
let bb_path = location.join(VerifierConfig::bb_dir_name());
if bb_path.is_dir() {
for re in fs::read_dir(&bb_path).unwrap() {
let e = re.unwrap().path();
if e.is_dir() {
res.bb_directories.push(BBDirectory::new(&e))
}
}
}
res
}
pub fn get_location(&self) -> &Path {
self.location.as_path()
}
}
impl BBDirectory {
pub fn new(location: &Path) -> Self {
Self {
location: location.to_path_buf(),
tally_component_votes_payload_file: create_file!(
location,
Tally,
VerifierTallyDataType::TallyComponentVotesPayload
),
tally_component_shuffle_payload_file: create_file!(
location,
Tally,
VerifierTallyDataType::TallyComponentShufflePayload
),
control_component_ballot_box_payload_group: FileGroup::new(location),
control_component_shuffle_payload_group: FileGroup::new(location),
}
}
pub fn get_location(&self) -> &Path {
self.location.as_path()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::config::test::test_datasets_path;
#[test]
fn test_completness() {
let dir = TallyDirectory::new(&test_datasets_path());
let c = dir.test_completness();
assert!(c.is_ok());
assert!(c.unwrap().is_empty());
}
}