Skip to main content

yog_core/
state.rs

1//! Block states as written (`"ns:id[k=v,...]"`).
2
3use yog_ids::sep::{
4    PROPERTY_IS, PROPERTY_SEP, STATE_CLOSE as PROPS_CLOSE, STATE_OPEN as PROPS_OPEN,
5};
6
7/// A block state (`"ns:id[k=v,...]"`) as its id and its properties.
8pub fn split_state(state: &str) -> (&str, Vec<(&str, &str)>) {
9    let (id, rest) = state.split_once(PROPS_OPEN).unwrap_or((state, ""));
10    let props = rest
11        .trim_end_matches(PROPS_CLOSE)
12        .split(PROPERTY_SEP)
13        .filter_map(|p| p.split_once(PROPERTY_IS))
14        .collect();
15    (id, props)
16}
17
18/// A block state from its id and properties: [`split_state`]'s inverse.
19pub fn join_state(id: &str, props: &[(&str, &str)]) -> String {
20    if props.is_empty() {
21        return id.to_owned();
22    }
23    let props: Vec<String> = props
24        .iter()
25        .map(|(k, v)| format!("{k}{PROPERTY_IS}{v}"))
26        .collect();
27    format!("{id}{PROPS_OPEN}{}{PROPS_CLOSE}", props.join(PROPERTY_SEP))
28}
29
30#[cfg(test)]
31mod tests {
32    use super::split_state;
33
34    #[test]
35    fn a_state_joins_back() {
36        assert_eq!(super::join_state("minecraft:stone", &[]), "minecraft:stone");
37        assert_eq!(
38            super::join_state("a:b", &[("x", "1"), ("y", "2")]),
39            "a:b[x=1,y=2]"
40        );
41    }
42
43    #[test]
44    fn a_state_splits_into_its_id_and_properties() {
45        assert_eq!(split_state("minecraft:stone"), ("minecraft:stone", vec![]));
46        assert_eq!(
47            split_state("hexcasting:impetus/look[energized=false,facing=up]"),
48            (
49                "hexcasting:impetus/look",
50                vec![("energized", "false"), ("facing", "up")]
51            )
52        );
53    }
54}