aimx/expressions/
retry.rs1use crate::{
11 aim::{ContextLike, WriterLike, Writer},
12 expressions::{Coalesce, ExpressionLike, Reference, parse_coalesce, parse_arc_identifier},
13 literals::{Literal, parse_unsigned},
14 values::Value,
15};
16use anyhow::Result;
17use nom::{
18 IResult, Parser,
19 bytes::complete::tag,
20 character::complete::{char, multispace0},
21 sequence::{delimited, preceded},
22};
23use std::{
24 fmt,
25 sync::Arc,
26};
27
28#[derive(Debug, Clone, PartialEq)]
29pub struct Retry {
30 count: u32,
31 condition: Coalesce,
32 target: Arc<str>,
33}
34
35impl Retry {
36 pub fn new(count: u32, condition: Coalesce, target: Arc<str>) -> Self {
37 Self {
38 count,
39 condition,
40 target,
41 }
42 }
43
44 pub fn count(&self) -> u32 {
45 self.count
46 }
47
48 pub fn condition(&self) -> &dyn ExpressionLike {
49 &self.condition
50 }
51
52 pub fn target(&self) -> Arc<str> {
53 self.target.clone()
54 }
55
56 pub fn print(&self, writer: &mut Writer) {
57 writer.write_unsigned(self.count);
58 writer.write_str(", ");
59 self.condition.print(writer);
60 writer.write_str(" -> ");
61 writer.write_str(&self.target);
62 }
63}
64
65pub fn parse_retry(input: &str) -> IResult<&str, Retry> {
66 let (input, (count, condition, target)) = delimited(
67 multispace0,
68 (
70 parse_unsigned,
71 preceded(
72 (multispace0, char(','), multispace0),
73 parse_coalesce),
74 preceded(
75 (multispace0, tag("->"), multispace0),
76 parse_arc_identifier
77 ),
78 ),
79 multispace0,
80 ).parse(input)?;
81
82 Ok((input, Retry::new(count, condition, target)))
83}
84
85impl ExpressionLike for Retry {
86 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>> {
87 let value = self.condition.evaluate(context)?;
88 if value.is_error() {
89 return Ok(value);
90 }
91 match &*value.to_bool() {
92 Value::Literal(Literal::Bool(true)) => {
93 let reference = Reference::new(self.target.clone());
94 let value = context.get_value(&reference)?;
95 let count = if value.is_number() {
96 value.to_number().unwrap_or(self.count as f64) as u32
97 } else {
98 self.count
99 };
100 if count > 0 {
101 let new_value = Arc::new(Value::Literal(Literal::Number((count - 1) as f64)));
102 let _ = context.set_value(&self.target, new_value);
103 return Ok(Arc::new(Value::Branch(self.target.clone())));
104 }
105 }
106 _ => {}
107 }
108 Ok(Value::empty())
109 }
110
111 fn to_formula(&self) -> String {
113 let mut writer = Writer::formulizer();
114 self.print(&mut writer);
115 writer.finish()
116 }
117}
118
119impl WriterLike for Retry {
120 fn write(&self, writer: &mut Writer) {
121 self.print(writer);
122 }
123}
124
125impl fmt::Display for Retry {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(f, "{}", self.to_stringized())
128 }
129}