Skip to main content

opys_core/
valdefs.rs

1use indexmap::IndexMap;
2use serde::{Deserialize, Serialize};
3use opys_mojang_rules::{satisfies_ruleset, OsOptions, RuleError, Ruleset};
4
5use crate::shorthand::{encode_short_ruleset, parse_short_ruleset, RawRuleset, ShorthandError};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct ConditionalVal {
9    pub value: String,
10    pub rules: Ruleset,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum ValDef {
15    Flat(String),
16    Arms(Vec<ConditionalVal>),
17}
18
19pub type ValDefs = IndexMap<String, ValDef>;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ConditionalValWire {
23    pub value: String,
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub rules: Option<RawRuleset>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(untagged)]
30pub enum ValDefWire {
31    Flat(String),
32    Arms(Vec<ConditionalValWire>),
33}
34
35pub fn parse_val_defs(raw: IndexMap<String, ValDefWire>) -> Result<ValDefs, ShorthandError> {
36    raw.into_iter()
37        .map(|(key, val)| {
38            let parsed = match val {
39                ValDefWire::Flat(s) => ValDef::Flat(s),
40                ValDefWire::Arms(arms) => ValDef::Arms(
41                    arms.into_iter()
42                        .map(|arm| {
43                            Ok(ConditionalVal {
44                                value: arm.value,
45                                rules: arm
46                                    .rules
47                                    .map(parse_short_ruleset)
48                                    .transpose()?
49                                    .unwrap_or_default(),
50                            })
51                        })
52                        .collect::<Result<_, ShorthandError>>()?,
53                ),
54            };
55            Ok((key, parsed))
56        })
57        .collect()
58}
59
60pub fn encode_val_defs(defs: &ValDefs) -> serde_json::Value {
61    let mut out = serde_json::Map::new();
62    for (key, val) in defs {
63        let v = match val {
64            ValDef::Flat(s) => serde_json::Value::String(s.clone()),
65            ValDef::Arms(arms) => serde_json::Value::Array(
66                arms.iter()
67                    .map(|arm| {
68                        let mut m = serde_json::Map::new();
69                        m.insert("value".into(), serde_json::Value::String(arm.value.clone()));
70                        if !arm.rules.is_empty() {
71                            m.insert(
72                                "rules".into(),
73                                serde_json::to_value(encode_short_ruleset(&arm.rules)).unwrap(),
74                            );
75                        }
76                        serde_json::Value::Object(m)
77                    })
78                    .collect(),
79            ),
80        };
81        out.insert(key.clone(), v);
82    }
83    serde_json::Value::Object(out)
84}
85
86/// For each key: flat → use as-is; arms → last matching arm wins.
87pub fn resolve_val_defs(
88    defs: &ValDefs,
89    os: &OsOptions,
90    feats: &[String],
91) -> Result<IndexMap<String, String>, RuleError> {
92    let mut result = IndexMap::new();
93    for (key, val) in defs {
94        match val {
95            ValDef::Flat(s) => {
96                result.insert(key.clone(), s.clone());
97            }
98            ValDef::Arms(arms) => {
99                let mut chosen: Option<String> = None;
100                for arm in arms {
101                    if satisfies_ruleset(&arm.rules, os, feats)? {
102                        chosen = Some(arm.value.clone());
103                    }
104                }
105                if let Some(v) = chosen {
106                    result.insert(key.clone(), v);
107                }
108            }
109        }
110    }
111    Ok(result)
112}