behavior_tree_lite/parser/
yaml_parser.rs1use 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(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}