use std::fmt::Display;
use std::str::FromStr;
use crate::element::Action;
use crate::node::{Tag, TagOpen, TryFromNodeError};
use crate::{Component, State};
pub type StringPair<T> = (T, &'static str);
fn strip_brackets(mut source: &str) -> &str {
source = source.strip_prefix('<').unwrap_or(source);
source.strip_suffix('>').unwrap_or(source)
}
#[track_caller]
pub fn try_from_node<'a, T>(source: &'a str) -> T
where
T: TryFrom<Tag<'a>, Error = TryFromNodeError>,
{
match Tag::parse(strip_brackets(source), true) {
Ok(tag) => match T::try_from(tag) {
Ok(node) => node,
Err(e) => panic!("{e}"),
},
Err(e) => panic!("failed to parse definition: {e}"),
}
}
#[track_caller]
pub fn decode_actions(source: &str, state: &State) -> crate::Result<Vec<Action>> {
let tag: TagOpen = try_from_node(source);
match state.get_component(tag.name, true)? {
Component::AtomicTag(atom) => Ok(vec![atom.decode(&tag.arguments, state)?.into_owned()]),
Component::Element(el) => el
.decode(&tag.arguments, state)
.map(|result| result.map(Action::into_owned))
.collect(),
}
}
fn zip_pairs<T, U, F>(pairs: &[StringPair<T>], mut zipper: F) -> (Vec<U>, Vec<U>)
where
F: FnMut(&T, &'static str) -> (U, U),
{
let mut actual = Vec::with_capacity(pairs.len());
let mut expected = Vec::with_capacity(pairs.len());
for (item, s) in pairs {
let (actual_result, expected_result) = zipper(item, s);
actual.push(actual_result);
expected.push(expected_result);
}
(actual, expected)
}
pub fn format_from_pairs<T: Display>(pairs: &[StringPair<T>]) -> (Vec<String>, Vec<String>) {
zip_pairs(pairs, |item, s| (item.to_string(), (*s).to_owned()))
}
type ParseResult<T> = Result<T, <T as FromStr>::Err>;
pub fn parse_from_pairs<T: FromStr + Clone>(
pairs: &[StringPair<T>],
) -> (Vec<ParseResult<T>>, Vec<ParseResult<T>>) {
zip_pairs(pairs, |item, s| (s.parse(), Ok(item.clone())))
}