geop_lib_constraints/
unknown.rs1use std::collections::BTreeMap;
14
15use geop_core_math::{
16 geop_error::{GeopError, GeopResult},
17 solvers::system::Mobility,
18};
19use geop_core_program::{
20 element::{ElementReference, HasElements, Kind},
21 part::{Make, StepContext},
22 placed::key_behind,
23 reader::Reader,
24 target::{Target, TargetReference},
25 values::StateValue,
26};
27
28use crate::Generated;
29
30#[derive(Clone, Debug, PartialEq)]
36pub struct Unknown {
37 pub state: String,
38 pub mobility: Mobility,
39 pub seed: Option<StateValue>,
40 pub unless: Option<String>,
41}
42
43const UNKNOWNS: &str = "unknowns";
45
46#[derive(Clone, Debug, Default, PartialEq)]
49pub struct Unknowns(BTreeMap<String, Unknown>);
50
51impl Unknowns {
52 pub fn of(reader: &Reader) -> GeopResult<Self> {
60 if let Some(failed) = reader.failed_targets_of::<StepUnknowns>().pop() {
61 return Err(failed);
62 }
63 let mut all = Self::default();
64 for own in reader.targets_of::<StepUnknowns>() {
65 let own = reader.retrieve_element(&ElementReference::whole(own))?;
66 for declared in &own.0 {
67 all.declare(declared.clone());
68 }
69 }
70 for name in reader.instances() {
71 let inside = reader.placed_part(name)?;
72 let declared = Self::of(&inside)
73 .map_err(|e| e.with_context(format!("the unknowns of the placed part `{name}`")))?;
74 for unknown in declared.0.into_values() {
75 let seed = inside.given_state(&unknown.state).or(unknown.seed);
76 all.declare(Unknown {
77 state: key_behind(name, &unknown.state),
78 seed,
79 unless: (unknown.unless).map(|unless| key_behind(name, &unless)),
80 ..unknown
81 });
82 }
83 }
84 Ok(all)
85 }
86
87 pub fn get(&self, state: &str) -> Option<&Unknown> {
89 self.0.get(state)
90 }
91
92 pub fn iter(&self) -> impl Iterator<Item = &Unknown> {
94 self.0.values()
95 }
96
97 fn declare(&mut self, declared: Unknown) {
100 match self.0.get_mut(&declared.state) {
101 None => {
102 self.0.insert(declared.state.clone(), declared);
103 }
104 Some(kept) if declared.mobility == Mobility::Fixed => kept.mobility = Mobility::Fixed,
105 Some(_) => {}
106 }
107 }
108}
109
110#[derive(Clone, Debug, PartialEq)]
112struct StepUnknowns(Vec<Unknown>);
113
114impl Target for StepUnknowns {}
116
117impl Kind for StepUnknowns {
119 const NAME: &'static str = "step unknowns";
120}
121
122impl HasElements<StepUnknowns> for StepUnknowns {
123 type Element<'a> = &'a StepUnknowns;
124
125 fn element(&self, name: &str) -> GeopResult<&Self> {
126 match name.is_empty() {
127 true => Ok(self),
128 false => Err(GeopError::new(format!(
129 "a step's unknowns have no element `{name}`: they are read whole"
130 ))),
131 }
132 }
133}
134
135pub fn declare_unknowns<Args: PartialEq + Clone + std::fmt::Debug + 'static>(
140 ctx: &mut StepContext,
141 args: &Args,
142 generator: Make<Args, Vec<Unknown>>,
143) -> GeopResult<()> {
144 let own = TargetReference::<StepUnknowns>::new(format!("{UNKNOWNS}:{}", ctx.step()));
145 let generated = Generated {
146 args: args.clone(),
147 generator,
148 };
149 ctx.produce(&own, &generated, declare)
150}
151
152fn declare<Args>(
154 reader: &Reader,
155 generated: &Generated<Args, Vec<Unknown>>,
156) -> GeopResult<StepUnknowns> {
157 Ok(StepUnknowns((generated.generator)(
158 reader,
159 &generated.args,
160 )?))
161}