use super::{
ber::{BerTest, BerTestParameters, Statistics},
modulation::{Bpsk, Psk8},
};
use crate::decoder::factory::{DecoderFactory, DecoderImplementation};
use clap::ValueEnum;
pub trait Ber {
fn run(self: Box<Self>) -> Result<Vec<Statistics>, Box<dyn std::error::Error>>;
fn n(&self) -> usize;
fn n_cw(&self) -> usize;
fn k(&self) -> usize;
fn rate(&self) -> f64;
}
#[derive(Debug)]
pub struct BerTestBuilder<'a, Dec = DecoderImplementation> {
pub parameters: BerTestParameters<'a, Dec>,
pub modulation: Modulation,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, ValueEnum)]
#[clap(rename_all = "UPPER")]
pub enum Modulation {
Bpsk,
Psk8,
}
impl std::str::FromStr for Modulation {
type Err = String;
fn from_str(s: &str) -> Result<Modulation, String> {
Ok(match s {
"BPSK" => Modulation::Bpsk,
"8PSK" => Modulation::Psk8,
_ => Err(format!("invalid modulation {s}"))?,
})
}
}
impl std::fmt::Display for Modulation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"{}",
match self {
Modulation::Bpsk => "BPSK",
Modulation::Psk8 => "8PSK",
}
)
}
}
impl<Dec: DecoderFactory> BerTestBuilder<'_, Dec> {
pub fn build(self) -> Result<Box<dyn Ber>, Box<dyn std::error::Error>> {
macro_rules! impl_match {
($($modulation:ident),*) => {
match self.modulation {
$(
Modulation::$modulation => Box::new(BerTest::<$modulation, Dec>::new(
self.parameters
)?),
)*
}
}
}
Ok(impl_match!(Bpsk, Psk8))
}
}