flow_gate_core/gate/
rectangle.rs1use smallvec::SmallVec;
2
3use crate::error::FlowGateError;
4use crate::traits::{Gate, GateId, ParameterName};
5use crate::transform::TransformKind;
6
7#[derive(Debug, Clone)]
8pub struct RectangleDimension {
9 pub parameter: ParameterName,
10 pub transform: Option<TransformKind>,
11 pub min: Option<f64>,
12 pub max: Option<f64>,
13}
14
15#[derive(Debug, Clone)]
16pub struct RectangleGate {
17 id: GateId,
18 parent_id: Option<GateId>,
19 dimensions: SmallVec<[RectangleDimension; 4]>,
20 dim_names: SmallVec<[ParameterName; 4]>,
21}
22
23impl RectangleGate {
24 pub fn new(
25 id: GateId,
26 parent_id: Option<GateId>,
27 dimensions: Vec<RectangleDimension>,
28 ) -> Result<Self, FlowGateError> {
29 if dimensions.is_empty() {
30 return Err(FlowGateError::InvalidGate(
31 "RectangleGate requires at least one dimension".to_string(),
32 ));
33 }
34 let dimensions: SmallVec<[RectangleDimension; 4]> = dimensions.into();
35 let dim_names = dimensions.iter().map(|d| d.parameter.clone()).collect();
36 Ok(Self {
37 id,
38 parent_id,
39 dimensions,
40 dim_names,
41 })
42 }
43
44 pub fn rectangle_dimensions(&self) -> &[RectangleDimension] {
45 &self.dimensions
46 }
47}
48
49impl Gate for RectangleGate {
50 fn dimensions(&self) -> &[ParameterName] {
51 &self.dim_names
52 }
53
54 fn contains(&self, coords: &[f64]) -> bool {
55 if coords.len() != self.dimensions.len() {
56 return false;
57 }
58 coords
59 .iter()
60 .zip(self.dimensions.iter())
61 .all(|(&coord, dim)| {
62 if !coord.is_finite() {
63 return false;
64 }
65 let above_min = dim.min.is_none_or(|lo| coord >= lo);
66 let below_max = dim.max.is_none_or(|hi| coord < hi);
68 above_min && below_max
69 })
70 }
71
72 fn gate_id(&self) -> &GateId {
73 &self.id
74 }
75
76 fn parent_id(&self) -> Option<&GateId> {
77 self.parent_id.as_ref()
78 }
79}