use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TurnPolicy {
#[default]
RoundRobin,
AdjacencyPair,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DurationPolicy {
#[default]
SingleExchange,
MultiBeat {
max_beats: usize,
},
UntilResolved,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PracticeSpec {
pub name: String,
pub affordances: Vec<String>,
#[serde(default)]
pub turn_policy: TurnPolicy,
#[serde(default)]
pub duration_policy: DurationPolicy,
#[serde(default)]
pub entry_condition_source: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn practice_spec_deserializes() {
let s = r#"
name = "negotiation"
affordances = ["offer", "counter_offer", "accept", "reject"]
turn_policy = "adjacency_pair"
[duration_policy]
multi_beat = { max_beats = 10 }
"#;
let spec: PracticeSpec = toml::from_str(s).expect("should deserialize");
assert_eq!(spec.name, "negotiation");
assert_eq!(spec.affordances.len(), 4);
assert_eq!(spec.turn_policy, TurnPolicy::AdjacencyPair);
assert_eq!(
spec.duration_policy,
DurationPolicy::MultiBeat { max_beats: 10 }
);
}
#[test]
fn practice_defaults_to_single_exchange_round_robin() {
let s = r#"
name = "greeting"
affordances = ["wave", "nod"]
"#;
let spec: PracticeSpec = toml::from_str(s).expect("should deserialize");
assert_eq!(spec.name, "greeting");
assert_eq!(spec.affordances.len(), 2);
assert_eq!(spec.turn_policy, TurnPolicy::RoundRobin);
assert_eq!(spec.duration_policy, DurationPolicy::SingleExchange);
assert_eq!(spec.entry_condition_source, "");
}
}