use chain_impl_mockchain::fragment::FragmentId;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "reason")]
pub enum FragmentRejectionReason {
FragmentAlreadyInLog,
FragmentInvalid,
PreviousFragmentInvalid,
PoolOverflow,
}
#[serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RejectedFragmentInfo {
#[serde_as(as = "DisplayFromStr")]
pub id: FragmentId,
#[serde(flatten)]
pub reason: FragmentRejectionReason,
}
#[serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FragmentsProcessingSummary {
#[serde_as(as = "Vec<DisplayFromStr>")]
pub accepted: Vec<FragmentId>,
pub rejected: Vec<RejectedFragmentInfo>,
}
impl FragmentRejectionReason {
pub fn is_error(&self) -> bool {
matches!(
self,
FragmentRejectionReason::FragmentInvalid
| FragmentRejectionReason::PreviousFragmentInvalid
| FragmentRejectionReason::PoolOverflow
)
}
}
impl FragmentsProcessingSummary {
pub fn is_error(&self) -> bool {
self.rejected.iter().any(|info| info.reason.is_error())
}
pub fn fragment_ids(&self) -> Vec<FragmentId> {
self.rejected
.iter()
.map(|info| &info.id)
.chain(self.accepted.iter())
.cloned()
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use quickcheck::{Arbitrary, Gen};
use quickcheck_macros::quickcheck;
impl Arbitrary for FragmentRejectionReason {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.next_u32() % 4 {
0 => FragmentRejectionReason::FragmentAlreadyInLog,
1 => FragmentRejectionReason::FragmentInvalid,
2 => FragmentRejectionReason::PreviousFragmentInvalid,
3 => FragmentRejectionReason::PoolOverflow,
_ => unreachable!(),
}
}
}
impl Arbitrary for RejectedFragmentInfo {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self {
id: Arbitrary::arbitrary(g),
reason: Arbitrary::arbitrary(g),
}
}
}
impl Arbitrary for FragmentsProcessingSummary {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self {
accepted: Arbitrary::arbitrary(g),
rejected: Arbitrary::arbitrary(g),
}
}
}
#[quickcheck]
fn fragments_processing_summary_serialization_sanity(
summary: FragmentsProcessingSummary,
) -> bool {
let json = serde_json::to_string(&summary).unwrap();
let deserialized_summary = serde_json::from_str(&json).unwrap();
summary == deserialized_summary
}
}