geop_ops_step/import/
reader.rs1use geop_core_math::geop_error::{GeopError, GeopResult};
6
7use crate::part21::{Exchange, Instance, Record, Value};
8
9pub fn unsupported(id: u64, instance: &Instance, why: &str) -> GeopError {
12 GeopError::new(format!(
13 "#{id} {} is not supported: {why}",
14 instance.type_name()
15 ))
16}
17
18#[derive(Clone, Copy)]
20pub struct Args<'a> {
21 pub id: u64,
22 pub record: &'a Record,
23}
24
25impl<'a> Args<'a> {
26 fn error(&self, k: usize, what: &str) -> GeopError {
27 GeopError::new(format!(
28 "#{} {}: parameter {} {what}",
29 self.id,
30 self.record.name,
31 k + 1
32 ))
33 }
34
35 pub fn get(&self, k: usize) -> GeopResult<&'a Value> {
36 self.record
37 .args
38 .get(k)
39 .ok_or_else(|| self.error(k, "is missing"))
40 }
41
42 pub fn is_null(&self, k: usize) -> bool {
43 matches!(self.record.args.get(k), None | Some(Value::Null))
44 }
45
46 pub fn real(&self, k: usize) -> GeopResult<f64> {
47 real(self.get(k)?).ok_or_else(|| self.error(k, "is not a number"))
48 }
49
50 pub fn integer(&self, k: usize) -> GeopResult<i64> {
51 match self.get(k)? {
52 Value::Integer(i) => Ok(*i),
53 _ => Err(self.error(k, "is not an integer")),
54 }
55 }
56
57 pub fn reference(&self, k: usize) -> GeopResult<u64> {
58 match self.get(k)? {
59 Value::Ref(id) => Ok(*id),
60 _ => Err(self.error(k, "is not a reference to an instance")),
61 }
62 }
63
64 pub fn list(&self, k: usize) -> GeopResult<&'a [Value]> {
65 match self.get(k)? {
66 Value::List(values) => Ok(values),
67 _ => Err(self.error(k, "is not a list")),
68 }
69 }
70
71 pub fn references(&self, k: usize) -> GeopResult<Vec<u64>> {
72 self.list(k)?
73 .iter()
74 .map(|v| match v {
75 Value::Ref(id) => Ok(*id),
76 _ => Err(self.error(k, "is not a list of references")),
77 })
78 .collect()
79 }
80
81 pub fn reals(&self, k: usize) -> GeopResult<Vec<f64>> {
82 self.list(k)?
83 .iter()
84 .map(|v| real(v).ok_or_else(|| self.error(k, "is not a list of numbers")))
85 .collect()
86 }
87
88 pub fn integers(&self, k: usize) -> GeopResult<Vec<i64>> {
89 self.list(k)?
90 .iter()
91 .map(|v| match v {
92 Value::Integer(i) => Ok(*i),
93 _ => Err(self.error(k, "is not a list of integers")),
94 })
95 .collect()
96 }
97
98 pub fn logical(&self, k: usize) -> GeopResult<bool> {
100 match self.get(k)? {
101 Value::Enum(e) if e == "T" => Ok(true),
102 Value::Enum(e) if e == "F" => Ok(false),
103 _ => Err(self.error(k, "is not .T. or .F.")),
104 }
105 }
106
107 pub fn enumeration(&self, k: usize) -> GeopResult<&'a str> {
108 match self.get(k)? {
109 Value::Enum(e) => Ok(e),
110 _ => Err(self.error(k, "is not an enumeration value")),
111 }
112 }
113
114 pub fn string(&self, k: usize) -> GeopResult<&'a str> {
115 match self.get(k)? {
116 Value::String(s) => Ok(s),
117 _ => Err(self.error(k, "is not a string")),
118 }
119 }
120}
121
122pub fn real(value: &Value) -> Option<f64> {
124 match value {
125 Value::Real(r) => Some(*r),
126 Value::Integer(i) => Some(*i as f64),
127 Value::Typed(_, inner) => real(inner),
128 _ => None,
129 }
130}
131
132#[derive(Clone, Copy)]
134pub struct Reader<'a> {
135 pub exchange: &'a Exchange,
136}
137
138impl<'a> Reader<'a> {
139 pub fn instance(&self, id: u64) -> GeopResult<&'a Instance> {
140 self.exchange.get(id)
141 }
142
143 pub fn args(&self, id: u64, name: &str) -> GeopResult<Args<'a>> {
146 let instance = self.instance(id)?;
147 let record = instance.record(name).ok_or_else(|| {
148 GeopError::new(format!(
149 "#{id} is a {}, where a {name} was expected",
150 instance.type_name()
151 ))
152 })?;
153 Ok(Args { id, record })
154 }
155
156 pub fn args_of_any(
159 &self,
160 id: u64,
161 names: &[&'static str],
162 ) -> GeopResult<(&'static str, Args<'a>)> {
163 let instance = self.instance(id)?;
164 for &name in names {
165 if let Some(record) = instance.record(name) {
166 return Ok((name, Args { id, record }));
167 }
168 }
169 Err(GeopError::new(format!(
170 "#{id} is a {}, where one of {} was expected",
171 instance.type_name(),
172 names.join(", ")
173 )))
174 }
175}