use super::Located;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RestartPolicy {
raw: Located<String>,
kind: RestartPolicyKind,
}
impl RestartPolicy {
pub(crate) fn parse(raw: Located<String>) -> Self {
let kind = match raw.value().as_str() {
"no" => RestartPolicyKind::No,
"always" => RestartPolicyKind::Always,
"on-failure" => RestartPolicyKind::OnFailure { maximum_retries: None },
"unless-stopped" => RestartPolicyKind::UnlessStopped,
value if value.contains('$') => RestartPolicyKind::Expression,
value => parse_maximum_retries(value).map_or(RestartPolicyKind::Other, |maximum_retries| {
RestartPolicyKind::OnFailure {
maximum_retries: Some(maximum_retries.to_owned()),
}
}),
};
Self { raw, kind }
}
#[must_use]
pub const fn raw(&self) -> &Located<String> {
&self.raw
}
#[must_use]
pub const fn kind(&self) -> &RestartPolicyKind {
&self.kind
}
#[must_use]
pub const fn is_valid(&self) -> bool {
!matches!(self.kind, RestartPolicyKind::Other)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum RestartPolicyKind {
No,
Always,
OnFailure {
maximum_retries: Option<String>,
},
UnlessStopped,
Expression,
Other,
}
fn parse_maximum_retries(value: &str) -> Option<&str> {
let retries = value.strip_prefix("on-failure:")?;
(!retries.is_empty() && retries.bytes().all(|byte| byte.is_ascii_digit())).then_some(retries)
}
#[cfg(test)]
mod tests {
use super::{RestartPolicy, RestartPolicyKind};
use crate::model::Located;
use crate::source::{SourceId, SourceSpan};
#[test]
fn retains_maximum_retry_spelling_without_normalizing_it() -> Result<(), &'static str> {
let value = "on-failure:003";
let span = SourceSpan::new(SourceId::new(1), 0, value.len()).ok_or("valid test span expected")?;
let policy = RestartPolicy::parse(Located::new(value.to_owned(), span));
assert_eq!(policy.raw().value(), value);
assert_eq!(
policy.kind(),
&RestartPolicyKind::OnFailure {
maximum_retries: Some("003".to_owned()),
}
);
assert!(policy.is_valid());
Ok(())
}
}