Skip to main content

openjd_model/template/
actions.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5//! Action types per spec §5.
6
7use crate::format_string::FormatString;
8use serde::Deserialize;
9
10/// §5 Action
11#[derive(Debug, Clone, Deserialize)]
12#[serde(rename_all = "camelCase", deny_unknown_fields)]
13pub struct Action {
14    pub command: FormatString,
15    pub args: Option<Vec<FormatString>>,
16    pub cancelation: Option<CancelationMode>,
17    pub timeout: Option<FormatString>,
18}
19
20/// §5.3 CancelationMethod — discriminated union on `mode`.
21#[derive(Debug, Clone)]
22pub enum CancelationMode {
23    /// §5.3.1 — immediate termination, no extra fields allowed.
24    Terminate,
25    /// §5.3.2 — notify then terminate, with optional grace period.
26    NotifyThenTerminate {
27        notify_period_in_seconds: Option<FormatString>,
28    },
29}
30
31impl<'de> Deserialize<'de> for CancelationMode {
32    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
33        use std::collections::HashMap;
34        let map = HashMap::<String, serde_json::Value>::deserialize(deserializer)?;
35        let mode = map
36            .get("mode")
37            .and_then(|v| v.as_str())
38            .ok_or_else(|| serde::de::Error::missing_field("mode"))?;
39        match mode {
40            "TERMINATE" => {
41                let extra: Vec<_> = map.keys().filter(|k| *k != "mode").collect();
42                if !extra.is_empty() {
43                    return Err(serde::de::Error::custom(format!(
44                        "unknown field `{}`, TERMINATE accepts no additional fields",
45                        extra[0]
46                    )));
47                }
48                Ok(CancelationMode::Terminate)
49            }
50            "NOTIFY_THEN_TERMINATE" => {
51                let extra: Vec<_> = map
52                    .keys()
53                    .filter(|k| *k != "mode" && *k != "notifyPeriodInSeconds")
54                    .collect();
55                if !extra.is_empty() {
56                    return Err(serde::de::Error::custom(format!(
57                        "unknown field `{}`, expected `notifyPeriodInSeconds`",
58                        extra[0]
59                    )));
60                }
61                let notify = map
62                    .get("notifyPeriodInSeconds")
63                    .map(|v| FormatString::deserialize(v.clone()))
64                    .transpose()
65                    .map_err(serde::de::Error::custom)?;
66                Ok(CancelationMode::NotifyThenTerminate {
67                    notify_period_in_seconds: notify,
68                })
69            }
70            other => Err(serde::de::Error::custom(format!(
71                "unknown variant `{other}`, expected `TERMINATE` or `NOTIFY_THEN_TERMINATE`"
72            ))),
73        }
74    }
75}
76
77/// §3.5.1 StepActions
78#[derive(Debug, Clone, Deserialize)]
79#[serde(rename_all = "camelCase", deny_unknown_fields)]
80pub struct StepActions {
81    pub on_run: Action,
82}
83
84/// §4.1 EnvironmentActions
85#[derive(Debug, Clone, Deserialize)]
86#[serde(rename_all = "camelCase", deny_unknown_fields)]
87pub struct EnvironmentActions {
88    pub on_enter: Option<Action>,
89    pub on_exit: Option<Action>,
90}