use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_member_hash}; use crate::spec::polymorphic_enum_loop_spec::{ PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopChildUseCurrent, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild, PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough, }; use crate::spec::{SpecialChild, SpecialChildKind, StructField}; use yaml_rust2::Yaml; fn deserialize_build_child(child_name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuildChild { if props["use_current"].is_hash() { let kind = props["use_current"]["kind"].as_str().unwrap(); PolymorphicEnumLoopRuleBuildChild::UseCurrent(PolymorphicEnumLoopChildUseCurrent::new( child_name, kind, )) } else if props["on_each"].is_hash() { let rule = props["on_each"]["rule"].as_str().unwrap(); PolymorphicEnumLoopRuleBuildChild::OnEach(PolymorphicEnumLoopRuleChildOnEach::new( child_name, rule, )) } else if props["special"].is_hash() { let kind = match props["special"]["kind"].as_str().unwrap() { "range" => SpecialChildKind::Range, "file_id" => SpecialChildKind::FileId, _ => panic!("Unknown special child kind"), }; PolymorphicEnumLoopRuleBuildChild::Special(SpecialChild::new(child_name, kind)) } else { panic!("Expected 'use_current' or 'on_each' hash for polymorphic enum loop build child"); } } fn deserialize_build(name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuild { let variant = props["variant"].as_str().unwrap(); let children = props["children"] .as_vec() .unwrap() .iter() .map(|child_yaml| { let (child_name, child_props) = unwrap_single_member_hash(child_yaml); deserialize_build_child(&child_name, child_props) }) .map(Box::new) .collect(); let fields = props["fields"] .as_vec() .map(|fields| { fields.iter() .map(|field_yaml| { let (field_name, field_props) = unwrap_single_member_hash(field_yaml); let kind = field_props["kind"].as_str().unwrap(); StructField::new( &field_name, kind, None, false ) }) .collect::>() }) .unwrap_or_else(|| vec![]); PolymorphicEnumLoopRuleBuild::new(name, variant, children, fields) } fn deserialize_pass_through(name: &str, props: &Yaml) -> PolymorphicEnumLoopRulePassThrough { let kind = props["kind"].as_str().unwrap(); let with = make_build_fn_name(props["with"].as_str().unwrap_or(kind)); PolymorphicEnumLoopRulePassThrough::new(name, kind, &with) } fn deserialize_rule(rule_name: &str, props: &Yaml) -> PolymorphicEnumLoopRule { if props["pass_through"].is_hash() { PolymorphicEnumLoopRule::PassThrough(deserialize_pass_through( rule_name, &props["pass_through"], )) } else if props["build"].is_hash() { PolymorphicEnumLoopRule::Build(deserialize_build(rule_name, &props["build"])) } else { panic!("Polymorphic enum loop rule must have 'pass_through' or 'build' hash."); } } pub fn deserialize_polymorphic_enum_loop(name: &str, props: &Yaml) -> PolymorphicEnumLoopBuildSpec { let kind = props["kind"].as_str().unwrap(); let reverse = get_as_bool(&props["reverse"]); let rules = props["rules"] .as_vec() .unwrap() .iter() .map(|rule_yaml| { let (rule_name, rule_props) = unwrap_single_member_hash(rule_yaml); deserialize_rule(&rule_name, rule_props) }) .map(Box::new) .collect(); PolymorphicEnumLoopBuildSpec::new(name, kind, reverse, rules) }