behavior_tree_lite/parser/
yaml_parser.rs

1use crate::{
2    error::{AddChildError, LoadYamlError},
3    BehaviorNode, BehaviorNodeContainer, BlackboardValue, NumChildren, PortType, Registry,
4};
5use serde_yaml::Value;
6use std::collections::HashMap;
7
8type ParseResult = Result<Option<BehaviorNodeContainer>, LoadYamlError>;
9
10fn recurse_parse(value: &serde_yaml::Value, reg: &Registry) -> ParseResult {
11    let Some(name) = value.get("type").and_then(|value| value.as_str()) else {
12        return Ok(None);
13    };
14
15    let node = if let Some(node) = {
16        eprintln!("Returning {name}");
17        reg.build(name)
18    } {
19        node
20    } else {
21        eprintln!("Type does not exist in value {value:?}");
22        return Ok(None);
23    };
24
25    let mut child_nodes = vec![];
26    if let Some(Value::Sequence(children)) = value.get(&Value::from("children")) {
27        for child in children {
28            if let Some(built_child) = recurse_parse(child, reg)? {
29                if NumChildren::Finite(child_nodes.len()) < node.max_children() {
30                    child_nodes.push(built_child)
31                } else {
32                    return Err(LoadYamlError::AddChildError(AddChildError::TooManyNodes));
33                }
34            }
35        }
36    }
37
38    let blackboard_map = if let Some(Value::Mapping(ports)) = value.get(&Value::from("ports")) {
39        ports
40            .iter()
41            .filter_map(|(key, value)| {
42                key.as_str().zip(value.as_str()).and_then(|(key, value)| {
43                    Some((
44                        *reg.key_names.get(key)?,
45                        BlackboardValue::Ref(*reg.key_names.get(value)?, PortType::InOut),
46                    ))
47                })
48            })
49            .collect()
50    } else {
51        HashMap::new()
52    };
53
54    Ok(Some(BehaviorNodeContainer {
55        name: name.to_owned(),
56        node,
57        blackboard_map,
58        child_nodes,
59        last_result: None,
60        is_subtree: false,
61        subtree_expanded: std::cell::Cell::new(false),
62    }))
63}
64
65pub fn load_yaml(
66    yaml: &str,
67    reg: &Registry,
68) -> Result<HashMap<String, Box<dyn BehaviorNode>>, LoadYamlError> {
69    let yaml = serde_yaml::from_str(yaml)?;
70    if let Value::Mapping(root) = yaml {
71        // if let Some(Value::Mapping(nodes)) = root.get(&Value::from("nodes")) {
72        //     for (key, value) in nodes {
73        //         if let Some(key) = key.as_str() {
74        //             println!("Item: {}", key);
75        //         }
76        //     }
77        // }
78
79        if let Some(Value::Mapping(roots)) = root.get(&Value::from("behavior_tree")) {
80            return roots
81                .iter()
82                .map(|(name, value)| {
83                    Ok((
84                        name.as_str().ok_or(LoadYamlError::Missing)?.to_string(),
85                        recurse_parse(value, reg)?
86                            .map(|v| v.node)
87                            .ok_or_else(|| LoadYamlError::Missing)?,
88                    ))
89                })
90                .collect::<Result<_, LoadYamlError>>();
91        }
92    }
93
94    Err(LoadYamlError::Missing)
95}