#[cfg(feature = "alloc")]
#[allow(
unused_imports,
reason = "alloc prelude items; subset used per cfg/feature combination"
)]
use alloc::{borrow::ToOwned, string::String};
use thiserror::Error as ThisError;
#[derive(Debug, ThisError, PartialEq, Eq)]
pub enum CounterCodeError {
#[error("unknown counter code: '{0}'")]
UnknownCode(String),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum CounterCodeV1 {
ControllerIdxSigs,
WitnessIdxSigs,
NonTransReceiptCouples,
TransReceiptQuadruples,
FirstSeenReplayCouples,
TransIdxSigGroups,
SealSourceCouples,
TransLastIdxSigGroups,
SealSourceTriples,
PathedMaterialCouples,
BigPathedMaterialCouples,
GenericGroup,
BigGenericGroup,
BodyWithAttachmentGroup,
BigBodyWithAttachmentGroup,
AttachmentGroup,
BigAttachmentGroup,
NonNativeBodyGroup,
BigNonNativeBodyGroup,
ESSRPayloadGroup,
BigESSRPayloadGroup,
KERIACDCGenusVersion,
}
impl CounterCodeV1 {
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::ControllerIdxSigs => "-A",
Self::WitnessIdxSigs => "-B",
Self::NonTransReceiptCouples => "-C",
Self::TransReceiptQuadruples => "-D",
Self::FirstSeenReplayCouples => "-E",
Self::TransIdxSigGroups => "-F",
Self::SealSourceCouples => "-G",
Self::TransLastIdxSigGroups => "-H",
Self::SealSourceTriples => "-I",
Self::PathedMaterialCouples => "-L",
Self::BigPathedMaterialCouples => "--L",
Self::GenericGroup => "-T",
Self::BigGenericGroup => "--T",
Self::BodyWithAttachmentGroup => "-U",
Self::BigBodyWithAttachmentGroup => "--U",
Self::AttachmentGroup => "-V",
Self::BigAttachmentGroup => "--V",
Self::NonNativeBodyGroup => "-W",
Self::BigNonNativeBodyGroup => "--W",
Self::ESSRPayloadGroup => "-Z",
Self::BigESSRPayloadGroup => "--Z",
Self::KERIACDCGenusVersion => "-_AAA",
}
}
pub fn from_hard(hard: &str) -> Result<Self, CounterCodeError> {
match hard {
"-A" => Ok(Self::ControllerIdxSigs),
"-B" => Ok(Self::WitnessIdxSigs),
"-C" => Ok(Self::NonTransReceiptCouples),
"-D" => Ok(Self::TransReceiptQuadruples),
"-E" => Ok(Self::FirstSeenReplayCouples),
"-F" => Ok(Self::TransIdxSigGroups),
"-G" => Ok(Self::SealSourceCouples),
"-H" => Ok(Self::TransLastIdxSigGroups),
"-I" => Ok(Self::SealSourceTriples),
"-L" => Ok(Self::PathedMaterialCouples),
"--L" => Ok(Self::BigPathedMaterialCouples),
"-T" => Ok(Self::GenericGroup),
"--T" => Ok(Self::BigGenericGroup),
"-U" => Ok(Self::BodyWithAttachmentGroup),
"--U" => Ok(Self::BigBodyWithAttachmentGroup),
"-V" => Ok(Self::AttachmentGroup),
"--V" => Ok(Self::BigAttachmentGroup),
"-W" => Ok(Self::NonNativeBodyGroup),
"--W" => Ok(Self::BigNonNativeBodyGroup),
"-Z" => Ok(Self::ESSRPayloadGroup),
"--Z" => Ok(Self::BigESSRPayloadGroup),
"-_AAA" => Ok(Self::KERIACDCGenusVersion),
_ => Err(CounterCodeError::UnknownCode(hard.to_owned())),
}
}
#[must_use]
pub const fn hard_size(&self) -> usize {
match self {
Self::BigPathedMaterialCouples
| Self::BigGenericGroup
| Self::BigBodyWithAttachmentGroup
| Self::BigAttachmentGroup
| Self::BigNonNativeBodyGroup
| Self::BigESSRPayloadGroup => 3,
Self::KERIACDCGenusVersion => 5,
_ => 2,
}
}
#[must_use]
pub const fn soft_size(&self) -> usize {
match self {
Self::BigPathedMaterialCouples
| Self::BigGenericGroup
| Self::BigBodyWithAttachmentGroup
| Self::BigAttachmentGroup
| Self::BigNonNativeBodyGroup
| Self::BigESSRPayloadGroup => 5,
Self::KERIACDCGenusVersion => 3,
_ => 2,
}
}
#[must_use]
pub const fn full_size(&self) -> usize {
match self {
Self::BigPathedMaterialCouples
| Self::BigGenericGroup
| Self::BigBodyWithAttachmentGroup
| Self::BigAttachmentGroup
| Self::BigNonNativeBodyGroup
| Self::BigESSRPayloadGroup
| Self::KERIACDCGenusVersion => 8,
_ => 4,
}
}
#[must_use]
pub const fn to_big(&self) -> Option<Self> {
match self {
Self::PathedMaterialCouples => Some(Self::BigPathedMaterialCouples),
Self::GenericGroup => Some(Self::BigGenericGroup),
Self::BodyWithAttachmentGroup => Some(Self::BigBodyWithAttachmentGroup),
Self::AttachmentGroup => Some(Self::BigAttachmentGroup),
Self::NonNativeBodyGroup => Some(Self::BigNonNativeBodyGroup),
Self::ESSRPayloadGroup => Some(Self::BigESSRPayloadGroup),
_ => None,
}
}
#[must_use]
pub const fn is_big(&self) -> bool {
self.hard_size() == 3
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
#[case(CounterCodeV1::ControllerIdxSigs, "-A")]
#[case(CounterCodeV1::WitnessIdxSigs, "-B")]
#[case(CounterCodeV1::NonTransReceiptCouples, "-C")]
#[case(CounterCodeV1::TransReceiptQuadruples, "-D")]
#[case(CounterCodeV1::FirstSeenReplayCouples, "-E")]
#[case(CounterCodeV1::TransIdxSigGroups, "-F")]
#[case(CounterCodeV1::SealSourceCouples, "-G")]
#[case(CounterCodeV1::TransLastIdxSigGroups, "-H")]
#[case(CounterCodeV1::SealSourceTriples, "-I")]
#[case(CounterCodeV1::PathedMaterialCouples, "-L")]
#[case(CounterCodeV1::BigPathedMaterialCouples, "--L")]
#[case(CounterCodeV1::GenericGroup, "-T")]
#[case(CounterCodeV1::BigGenericGroup, "--T")]
#[case(CounterCodeV1::BodyWithAttachmentGroup, "-U")]
#[case(CounterCodeV1::BigBodyWithAttachmentGroup, "--U")]
#[case(CounterCodeV1::AttachmentGroup, "-V")]
#[case(CounterCodeV1::BigAttachmentGroup, "--V")]
#[case(CounterCodeV1::NonNativeBodyGroup, "-W")]
#[case(CounterCodeV1::BigNonNativeBodyGroup, "--W")]
#[case(CounterCodeV1::ESSRPayloadGroup, "-Z")]
#[case(CounterCodeV1::BigESSRPayloadGroup, "--Z")]
#[case(CounterCodeV1::KERIACDCGenusVersion, "-_AAA")]
fn from_hard_roundtrip(#[case] code: CounterCodeV1, #[case] wire: &str) {
assert_eq!(code.as_str(), wire);
assert_eq!(CounterCodeV1::from_hard(wire).unwrap(), code);
assert_eq!(CounterCodeV1::from_hard(code.as_str()).unwrap(), code);
}
#[rstest]
#[case("-J")]
#[case("-K")]
#[case("-0V")]
#[case("A")]
#[case("")]
fn from_hard_unknown(#[case] bad: &str) {
assert!(CounterCodeV1::from_hard(bad).is_err());
let err = CounterCodeV1::from_hard(bad).unwrap_err();
assert_eq!(err, CounterCodeError::UnknownCode(bad.to_owned()));
}
#[rstest]
#[case(CounterCodeV1::ControllerIdxSigs, 2, 2, 4)]
#[case(CounterCodeV1::WitnessIdxSigs, 2, 2, 4)]
#[case(CounterCodeV1::NonTransReceiptCouples, 2, 2, 4)]
#[case(CounterCodeV1::TransReceiptQuadruples, 2, 2, 4)]
#[case(CounterCodeV1::FirstSeenReplayCouples, 2, 2, 4)]
#[case(CounterCodeV1::TransIdxSigGroups, 2, 2, 4)]
#[case(CounterCodeV1::SealSourceCouples, 2, 2, 4)]
#[case(CounterCodeV1::TransLastIdxSigGroups, 2, 2, 4)]
#[case(CounterCodeV1::SealSourceTriples, 2, 2, 4)]
#[case(CounterCodeV1::PathedMaterialCouples, 2, 2, 4)]
#[case(CounterCodeV1::BigPathedMaterialCouples, 3, 5, 8)]
#[case(CounterCodeV1::GenericGroup, 2, 2, 4)]
#[case(CounterCodeV1::BigGenericGroup, 3, 5, 8)]
#[case(CounterCodeV1::BodyWithAttachmentGroup, 2, 2, 4)]
#[case(CounterCodeV1::BigBodyWithAttachmentGroup, 3, 5, 8)]
#[case(CounterCodeV1::AttachmentGroup, 2, 2, 4)]
#[case(CounterCodeV1::BigAttachmentGroup, 3, 5, 8)]
#[case(CounterCodeV1::NonNativeBodyGroup, 2, 2, 4)]
#[case(CounterCodeV1::BigNonNativeBodyGroup, 3, 5, 8)]
#[case(CounterCodeV1::ESSRPayloadGroup, 2, 2, 4)]
#[case(CounterCodeV1::BigESSRPayloadGroup, 3, 5, 8)]
#[case(CounterCodeV1::KERIACDCGenusVersion, 5, 3, 8)]
fn size_values(
#[case] code: CounterCodeV1,
#[case] hs: usize,
#[case] ss: usize,
#[case] fs: usize,
) {
assert_eq!(code.hard_size(), hs);
assert_eq!(code.soft_size(), ss);
assert_eq!(code.full_size(), fs);
assert_eq!(code.hard_size() + code.soft_size(), code.full_size());
}
#[test]
fn to_big_v1_promotable() {
assert_eq!(
CounterCodeV1::PathedMaterialCouples.to_big(),
Some(CounterCodeV1::BigPathedMaterialCouples)
);
assert_eq!(
CounterCodeV1::GenericGroup.to_big(),
Some(CounterCodeV1::BigGenericGroup)
);
assert_eq!(
CounterCodeV1::AttachmentGroup.to_big(),
Some(CounterCodeV1::BigAttachmentGroup)
);
assert_eq!(
CounterCodeV1::BodyWithAttachmentGroup.to_big(),
Some(CounterCodeV1::BigBodyWithAttachmentGroup)
);
assert_eq!(
CounterCodeV1::NonNativeBodyGroup.to_big(),
Some(CounterCodeV1::BigNonNativeBodyGroup)
);
assert_eq!(
CounterCodeV1::ESSRPayloadGroup.to_big(),
Some(CounterCodeV1::BigESSRPayloadGroup)
);
}
#[test]
fn to_big_v1_not_promotable() {
assert_eq!(CounterCodeV1::ControllerIdxSigs.to_big(), None);
assert_eq!(CounterCodeV1::WitnessIdxSigs.to_big(), None);
assert_eq!(CounterCodeV1::BigGenericGroup.to_big(), None);
assert_eq!(CounterCodeV1::KERIACDCGenusVersion.to_big(), None);
}
#[test]
fn is_big_v1() {
assert!(!CounterCodeV1::GenericGroup.is_big());
assert!(CounterCodeV1::BigGenericGroup.is_big());
assert!(!CounterCodeV1::KERIACDCGenusVersion.is_big());
}
#[test]
fn full_size_is_multiple_of_4() {
let all_codes = [
CounterCodeV1::ControllerIdxSigs,
CounterCodeV1::WitnessIdxSigs,
CounterCodeV1::NonTransReceiptCouples,
CounterCodeV1::TransReceiptQuadruples,
CounterCodeV1::FirstSeenReplayCouples,
CounterCodeV1::TransIdxSigGroups,
CounterCodeV1::SealSourceCouples,
CounterCodeV1::TransLastIdxSigGroups,
CounterCodeV1::SealSourceTriples,
CounterCodeV1::PathedMaterialCouples,
CounterCodeV1::BigPathedMaterialCouples,
CounterCodeV1::GenericGroup,
CounterCodeV1::BigGenericGroup,
CounterCodeV1::BodyWithAttachmentGroup,
CounterCodeV1::BigBodyWithAttachmentGroup,
CounterCodeV1::AttachmentGroup,
CounterCodeV1::BigAttachmentGroup,
CounterCodeV1::NonNativeBodyGroup,
CounterCodeV1::BigNonNativeBodyGroup,
CounterCodeV1::ESSRPayloadGroup,
CounterCodeV1::BigESSRPayloadGroup,
CounterCodeV1::KERIACDCGenusVersion,
];
for code in all_codes {
assert_eq!(
code.full_size() % 4,
0,
"{:?} full_size {} is not a multiple of 4",
code,
code.full_size()
);
}
}
}