comnum_spec/blocks/schema/
fact.rs1use crate::blocks::{Block, BlockInfo, Frame};
5use comnum_core::rng::Rng;
6use comnum_core::{Error, Result};
7use std::borrow::Borrow;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub enum Fact {
12 Bits,
14 Symbols,
16 Constellation,
18 Samples,
20 Noise,
22 Csi,
24 Payload,
26 Llr,
28 Decoded,
30 Ofdm,
32 Wdm,
34 Capture,
36}
37
38impl Fact {
39 pub const ALL: [Fact; 12] = [
41 Fact::Bits,
42 Fact::Symbols,
43 Fact::Constellation,
44 Fact::Samples,
45 Fact::Noise,
46 Fact::Csi,
47 Fact::Payload,
48 Fact::Llr,
49 Fact::Decoded,
50 Fact::Ofdm,
51 Fact::Wdm,
52 Fact::Capture,
53 ];
54
55 pub fn name(self) -> &'static str {
57 match self {
58 Fact::Bits => "bits",
59 Fact::Symbols => "symbols",
60 Fact::Constellation => "constellation",
61 Fact::Samples => "samples",
62 Fact::Noise => "noise",
63 Fact::Csi => "csi",
64 Fact::Payload => "payload",
65 Fact::Llr => "llr",
66 Fact::Decoded => "decoded",
67 Fact::Ofdm => "ofdm",
68 Fact::Wdm => "wdm",
69 Fact::Capture => "capture",
70 }
71 }
72
73 pub fn holds(self, s: &Frame) -> bool {
75 match self {
76 Fact::Bits => !s.bits.is_empty(),
77 Fact::Symbols => !s.symbols.is_empty(),
78 Fact::Constellation => s.constellation.is_some(),
79 Fact::Samples => !s.samples.is_empty(),
80 Fact::Noise => {
81 s.receiver.noise_var.is_some() || s.channel.noise_var.is_some() || !s.receiver.symbol_noise.is_empty()
82 }
83 Fact::Csi => s.channel.csi.is_some(),
84 Fact::Payload => !s.coding.payload.is_empty(),
85 Fact::Llr => !s.coding.llr.is_empty(),
86 Fact::Decoded => !s.coding.decoded.is_empty(),
87 Fact::Ofdm => s.in_flight.ofdm.is_some(),
88 Fact::Wdm => s.in_flight.wdm.is_some(),
89 Fact::Capture => !s.capture.reference.is_empty(),
90 }
91 }
92}
93
94pub fn check_link<B: Borrow<BlockInfo>>(kinds: &[&str], registry: &[B]) -> Result<()> {
101 let registry: Vec<&BlockInfo> = registry.iter().map(Borrow::borrow).collect();
102 let mut have: Vec<Fact> = Vec::new();
103 for (i, k) in kinds.iter().enumerate() {
104 let Some(b) = registry.iter().find(|b| b.name == *k) else { continue };
105 if let Some(f) = b.needs.iter().find(|f| !have.contains(f)) {
106 let givers: Vec<&str> = registry.iter().filter(|g| g.gives.contains(f)).map(|g| g.name).collect();
107 return Err(Error::Config(format!(
108 "link block {} ({k}) needs {}, which no block before it gives: add one of {givers:?} before it",
109 i + 1,
110 f.name()
111 )));
112 }
113 have.extend(b.gives.iter().copied());
114 }
115 Ok(())
116}
117
118#[cfg_attr(not(debug_assertions), allow(dead_code, reason = "built in debug builds only"))]
122pub(crate) struct Checked {
123 pub(crate) inner: Box<dyn Block>,
124 pub(crate) kind: String,
125 pub(crate) gives: &'static [Fact],
126}
127
128impl Block for Checked {
129 fn apply(&self, s: &mut Frame, rng: &mut Rng) -> Result<()> {
130 let before: Vec<Fact> = Fact::ALL.into_iter().filter(|f| f.holds(s)).collect();
131 self.inner.apply(s, rng)?;
132 if let Some(f) = Fact::ALL.into_iter().find(|f| f.holds(s) && !before.contains(f) && !self.gives.contains(f)) {
133 panic!("block {:?} gave {}, which it does not declare in gives", self.kind, f.name());
134 }
135 Ok(())
136 }
137
138 fn needs_training(&self) -> bool {
139 self.inner.needs_training()
140 }
141
142 fn train(&mut self, s: &Frame, rng: &mut Rng) -> Result<()> {
143 self.inner.train(s, rng)
144 }
145}