1pub use yog_ids::yog::{MACHINE_PREFIX, PLAYER_INVENTORY, SLOT_PREFIX};
10
11const ACCEPTS: char = '=';
13const ACCEPTS_SEP: &str = "|";
14const PART_SEP: char = ';';
17const PLACE_SEP: &str = ",";
18const PLACE_INDEX: char = '/';
19const PLACE_INV: char = '=';
20const MACHINE_PARTS: usize = 3;
22
23pub fn slot_id(index: usize, accepts: &[&str]) -> String {
25 match accepts {
26 [] => format!("{SLOT_PREFIX}{index}"),
27 _ => format!("{SLOT_PREFIX}{index}{ACCEPTS}{}", accepts.join(ACCEPTS_SEP)),
28 }
29}
30
31pub fn read_slot(id: &str) -> Option<(usize, Vec<String>)> {
33 let rest = id.strip_prefix(SLOT_PREFIX)?;
34 let (index, accepts) = rest.split_once(ACCEPTS).unwrap_or((rest, ""));
35 let accepts = accepts
36 .split(ACCEPTS_SEP)
37 .filter(|a| !a.is_empty())
38 .map(str::to_owned)
39 .collect();
40 Some((index.parse().ok()?, accepts))
41}
42
43#[derive(Debug, Clone, PartialEq)]
46pub struct MachineId {
47 pub kind: String,
48 pub places: Vec<(String, usize, usize)>,
49 pub result: usize,
50}
51
52impl MachineId {
53 pub fn write(kind: &str, places: &[(&str, usize, usize)], result: usize) -> String {
54 let places: Vec<String> = places
55 .iter()
56 .map(|(s, i, inv)| format!("{s}{PLACE_INDEX}{i}{PLACE_INV}{inv}"))
57 .collect();
58 format!(
59 "{MACHINE_PREFIX}{kind}{PART_SEP}{result}{PART_SEP}{}",
60 places.join(PLACE_SEP)
61 )
62 }
63
64 pub fn read(id: &str) -> Option<MachineId> {
66 let mut parts = id
67 .strip_prefix(MACHINE_PREFIX)?
68 .splitn(MACHINE_PARTS, PART_SEP);
69 let kind = parts.next()?.to_string();
70 let result = parts.next()?.parse().ok()?;
71 let places = parts
72 .next()
73 .unwrap_or_default()
74 .split(PLACE_SEP)
75 .filter(|p| !p.is_empty())
76 .filter_map(|p| {
77 let (slot, rest) = p.split_once(PLACE_INDEX)?;
78 let (index, inv) = rest.split_once(PLACE_INV)?;
79 Some((slot.to_string(), index.parse().ok()?, inv.parse().ok()?))
80 })
81 .collect();
82 Some(MachineId {
83 kind,
84 places,
85 result,
86 })
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn ids_read_back_as_written() {
96 assert_eq!(read_slot(&slot_id(3, &[])), Some((3, vec![])));
97 assert_eq!(
98 read_slot(&slot_id(4, &["a:b", "#c:d"])),
99 Some((4, vec!["a:b".into(), "#c:d".into()]))
100 );
101 let id = MachineId::write("m:k", &[("in", 0, 1), ("in", 1, 2)], 5);
102 assert_eq!(
103 MachineId::read(&id),
104 Some(MachineId {
105 kind: "m:k".into(),
106 places: vec![("in".into(), 0, 1), ("in".into(), 1, 2)],
107 result: 5
108 })
109 );
110 assert_eq!(read_slot("other"), None);
111 }
112}