Skip to content

Commit 19aa736

Browse files
committed
gsd-parser: Add proper error types for all possible failures during user_prm setting
Propagate all invalid situations during set_prm() or set_prm_from_text() to the user instead of panicking.
1 parent 28f1501 commit 19aa736

File tree

1 file changed

+106
-24
lines changed

1 file changed

+106
-24
lines changed

gsd-parser/src/lib.rs

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,28 @@ pub enum PrmValueConstraint {
219219
Unconstrained,
220220
}
221221

222+
#[derive(Debug, Clone, PartialEq, Eq)]
223+
pub struct PrmValueConstraintError {
224+
value: i64,
225+
constraint: PrmValueConstraint,
226+
}
227+
228+
impl std::fmt::Display for PrmValueConstraintError {
229+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230+
match &self.constraint {
231+
PrmValueConstraint::MinMax(min, max) => {
232+
write!(f, "value {} not in range {min}..={max}", self.value)
233+
}
234+
PrmValueConstraint::Enum(values) => {
235+
write!(f, "value {} not in set {values:?}", self.value)
236+
}
237+
PrmValueConstraint::Unconstrained => unreachable!(),
238+
}
239+
}
240+
}
241+
242+
impl std::error::Error for PrmValueConstraintError {}
243+
222244
impl PrmValueConstraint {
223245
pub fn is_valid(&self, value: i64) -> bool {
224246
match self {
@@ -228,21 +250,29 @@ impl PrmValueConstraint {
228250
}
229251
}
230252

231-
pub fn assert_valid(&self, value: i64) {
253+
pub fn assert_valid(&self, value: i64) -> Result<(), PrmValueConstraintError> {
232254
match self {
233255
PrmValueConstraint::MinMax(min, max) => {
234-
assert!(
235-
*min <= value && value <= *max,
236-
"value {value} not in range {min}..={max}",
237-
);
256+
if *min > value || value > *max {
257+
Err(PrmValueConstraintError {
258+
value,
259+
constraint: self.clone(),
260+
})
261+
} else {
262+
Ok(())
263+
}
238264
}
239265
PrmValueConstraint::Enum(values) => {
240-
assert!(
241-
values.contains(&value),
242-
"value {value} not in set {values:?}",
243-
);
266+
if !values.contains(&value) {
267+
Err(PrmValueConstraintError {
268+
value,
269+
constraint: self.clone(),
270+
})
271+
} else {
272+
Ok(())
273+
}
244274
}
245-
PrmValueConstraint::Unconstrained => (),
275+
PrmValueConstraint::Unconstrained => Ok(()),
246276
}
247277
}
248278
}
@@ -370,6 +400,46 @@ pub struct GenericStationDescription {
370400
pub unit_diag: UnitDiag,
371401
}
372402

403+
#[derive(Debug, Clone, PartialEq, Eq)]
404+
pub enum SetPrmError {
405+
PrmNotFound(String),
406+
PrmWithoutTexts(String),
407+
PrmTextNotFound { prm: String, text: String },
408+
ValueConstraint(PrmValueConstraintError),
409+
ValueRange { value: i64, ty: UserPrmDataType },
410+
}
411+
412+
impl From<PrmValueConstraintError> for SetPrmError {
413+
fn from(value: PrmValueConstraintError) -> Self {
414+
Self::ValueConstraint(value)
415+
}
416+
}
417+
418+
impl std::fmt::Display for SetPrmError {
419+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420+
match self {
421+
SetPrmError::PrmNotFound(name) => {
422+
write!(f, "prm {name} was not found")
423+
}
424+
SetPrmError::ValueConstraint(prm_value_constraint_error) => {
425+
prm_value_constraint_error.fmt(f)
426+
}
427+
SetPrmError::ValueRange { value, ty } => {
428+
write!(f, "value {value} is out of range for type {ty:?}")
429+
}
430+
SetPrmError::PrmWithoutTexts(name) => {
431+
write!(f, "prm {name} does not have texts")
432+
}
433+
SetPrmError::PrmTextNotFound { prm, text } => {
434+
write!(f, "prm {prm} does not have text {text:?}")
435+
}
436+
}
437+
}
438+
}
439+
440+
impl std::error::Error for SetPrmError {}
441+
442+
#[derive(Debug, PartialEq, Eq)]
373443
pub struct PrmBuilder<'a> {
374444
desc: &'a UserPrmData,
375445
prm: Vec<u8>,
@@ -412,37 +482,49 @@ impl<'a> PrmBuilder<'a> {
412482
Ok(())
413483
}
414484

415-
pub fn set_prm(&mut self, prm: &str, value: i64) -> Result<&mut Self, PrmValueRangeError> {
485+
pub fn set_prm(&mut self, prm: &str, value: i64) -> Result<&mut Self, SetPrmError> {
416486
let (offset, data_ref) = self
417487
.desc
418488
.data_ref
419489
.iter()
420490
.find(|(_, r)| r.name == prm)
421-
.expect("TODO");
422-
data_ref.constraint.assert_valid(value);
491+
.ok_or_else(|| SetPrmError::PrmNotFound(prm.to_string()))?;
492+
data_ref.constraint.assert_valid(value)?;
423493
data_ref
424494
.data_type
425-
.write_value_to_slice(value, &mut self.prm[(*offset)..])?;
495+
.write_value_to_slice(value, &mut self.prm[(*offset)..])
496+
.map_err(|_e| SetPrmError::ValueRange {
497+
value,
498+
ty: data_ref.data_type,
499+
})?;
426500
Ok(self)
427501
}
428502

429-
pub fn set_prm_from_text(
430-
&mut self,
431-
prm: &str,
432-
value: &str,
433-
) -> Result<&mut Self, PrmValueRangeError> {
503+
pub fn set_prm_from_text(&mut self, prm: &str, value: &str) -> Result<&mut Self, SetPrmError> {
434504
let (offset, data_ref) = self
435505
.desc
436506
.data_ref
437507
.iter()
438508
.find(|(_, r)| r.name == prm)
439-
.expect("TODO");
440-
let text_ref = data_ref.text_ref.as_ref().expect("TODO");
441-
let value = *text_ref.get(value).expect("TODO");
442-
data_ref.constraint.assert_valid(value);
509+
.ok_or_else(|| SetPrmError::PrmNotFound(prm.to_string()))?;
510+
let text_ref = data_ref
511+
.text_ref
512+
.as_ref()
513+
.ok_or_else(|| SetPrmError::PrmWithoutTexts(prm.to_string()))?;
514+
let value = *text_ref
515+
.get(value)
516+
.ok_or_else(|| SetPrmError::PrmTextNotFound {
517+
prm: prm.to_string(),
518+
text: value.to_string(),
519+
})?;
520+
data_ref.constraint.assert_valid(value)?;
443521
data_ref
444522
.data_type
445-
.write_value_to_slice(value, &mut self.prm[(*offset)..])?;
523+
.write_value_to_slice(value, &mut self.prm[(*offset)..])
524+
.map_err(|_e| SetPrmError::ValueRange {
525+
value,
526+
ty: data_ref.data_type,
527+
})?;
446528
Ok(self)
447529
}
448530

0 commit comments

Comments
 (0)