1mod drive;
2mod emit_intensity;
3mod error;
4mod phase;
5
6use std::collections::HashMap;
7
8pub use drive::Drive;
9pub use emit_intensity::Intensity;
10pub use error::GainError;
11pub use phase::Phase;
12
13use crate::{
14 datagram::{DeviceFilter, Segment, TransitionMode},
15 geometry::{Device, Geometry, Transducer},
16};
17
18#[derive(Debug)]
19pub struct TransducerFilter(Option<HashMap<usize, Option<bit_vec::BitVec<u32>>>>);
21
22impl TransducerFilter {
23 #[doc(hidden)]
24 pub const fn new(filter: HashMap<usize, Option<bit_vec::BitVec<u32>>>) -> Self {
25 Self(Some(filter))
26 }
27
28 pub const fn all_enabled() -> Self {
30 Self(None)
31 }
32
33 pub fn from_fn<FT: Fn(&Transducer) -> bool>(
35 geo: &Geometry,
36 f: impl Fn(&Device) -> Option<FT>,
37 ) -> Self {
38 Self(Some(HashMap::from_iter(geo.iter().filter_map(|dev| {
39 f(dev).map(|f| {
40 (
41 dev.idx(),
42 Some(bit_vec::BitVec::from_fn(dev.num_transducers(), |idx| {
43 f(&dev[idx])
44 })),
45 )
46 })
47 }))))
48 }
49
50 pub const fn is_all_enabled(&self) -> bool {
52 self.0.is_none()
53 }
54
55 pub fn is_enabled_device(&self, dev: &Device) -> bool {
57 self.0.as_ref().is_none_or(|f| f.contains_key(&dev.idx()))
58 }
59
60 pub fn is_enabled(&self, tr: &Transducer) -> bool {
62 self.0.as_ref().is_none_or(|f| {
63 f.get(&tr.dev_idx())
64 .map(|f| f.as_ref().map(|f| f[tr.idx()]).unwrap_or(true))
65 .unwrap_or(false)
66 })
67 }
68
69 pub fn num_enabled_devices(&self, geometry: &Geometry) -> usize {
71 self.0.as_ref().map_or(geometry.num_devices(), |f| {
72 geometry
73 .iter()
74 .filter(|dev| f.contains_key(&dev.idx()))
75 .count()
76 })
77 }
78
79 pub fn num_enabled_transducers(&self, dev: &Device) -> usize {
81 self.0.as_ref().map_or(dev.num_transducers(), |f| {
82 f.get(&dev.idx()).map_or(0, |filter| {
83 filter
84 .as_ref()
85 .map_or(dev.num_transducers(), |f| f.count_ones() as usize)
86 })
87 })
88 }
89}
90
91impl From<&DeviceFilter> for TransducerFilter {
92 fn from(filter: &DeviceFilter) -> Self {
93 if let Some(filter) = filter.0.as_ref() {
94 Self(Some(
95 filter
96 .iter()
97 .enumerate()
98 .filter_map(|(idx, enable)| enable.then_some((idx, None)))
99 .collect(),
100 ))
101 } else {
102 Self(None)
103 }
104 }
105}
106
107pub trait GainCalculator: Send + Sync {
111 #[must_use]
113 fn calc(&self, tr: &Transducer) -> Drive;
114}
115
116impl GainCalculator for Box<dyn GainCalculator> {
117 fn calc(&self, tr: &Transducer) -> Drive {
118 self.as_ref().calc(tr)
119 }
120}
121
122pub trait GainCalculatorGenerator {
124 type Calculator: GainCalculator;
126
127 #[must_use]
129 fn generate(&mut self, device: &Device) -> Self::Calculator;
130}
131
132pub trait Gain: std::fmt::Debug + Sized {
138 type G: GainCalculatorGenerator;
140
141 fn init(self, geometry: &Geometry, filter: &TransducerFilter) -> Result<Self::G, GainError>;
146}
147
148#[doc(hidden)]
149pub struct GainOperationGenerator<G: GainCalculatorGenerator> {
150 pub generator: G,
151 pub segment: Segment,
152 pub transition: Option<TransitionMode>,
153}
154
155impl<G: GainCalculatorGenerator> GainOperationGenerator<G> {
156 pub fn new<T: Gain<G = G>>(
157 gain: T,
158 geometry: &Geometry,
159 filter: &DeviceFilter,
160 segment: Segment,
161 transition: Option<TransitionMode>,
162 ) -> Result<Self, GainError> {
163 Ok(Self {
164 generator: gain.init(geometry, &TransducerFilter::from(filter))?,
165 segment,
166 transition,
167 })
168 }
169}
170
171#[derive(Debug, Clone, PartialEq)]
172pub struct GainInspectionResult {
174 pub name: String,
176 pub data: Vec<Drive>,
178 pub segment: Segment,
180 pub transition_mode: Option<TransitionMode>,
182}