use std::cmp::{Eq, PartialEq};
use std::error::Error;
use std::str::FromStr;
use regex::{self, Regex, RegexBuilder};
use util::parse_number;
use super::ModValues;
use super::id::ModId;
#[derive(Clone, Debug)]
pub struct ModInfo {
id: ModId,
text_template: String,
pub(super) regex: Regex,
}
impl ModInfo {
pub(super) fn from_raw<T: Into<String>>(id: &str, text: T) -> Result<Self, Box<Error>> {
let id = ModId::from_str(id)?;
let text = text.into();
let regex_str = regex_from_mod_text_template(&text);
Ok(ModInfo {
id: id,
text_template: text,
regex: RegexBuilder::new(®ex_str).case_insensitive(true).build()?,
})
}
}
pub(super) fn regex_from_mod_text_template(text: &str) -> String {
const VALUE_RE: &str = r"\+?(\d+(?:\.\d+)?)";
lazy_static! {
static ref VALUE_PH: String = regex::escape("#");
}
format!("^{}$", regex::escape(text.trim()).replace(VALUE_PH.as_str(), VALUE_RE))
}
impl ModInfo {
#[inline]
pub fn id(&self) -> ModId {
self.id
}
#[inline]
pub fn text(&self) -> &str {
self.text_template.as_str()
}
#[inline]
pub fn param_count(&self) -> usize {
self.regex.captures_len() - 1 }
pub fn parse_text(&self, text: &str) -> Option<ModValues> {
if self.param_count() == 0 {
return Some(ModValues::new());
}
self.regex.captures(text.trim()).map(|caps| {
caps.iter().skip(1)
.map(Option::unwrap) .map(|m| parse_number(m.as_str()).unwrap()) .collect()
})
}
}
impl PartialEq for ModInfo {
fn eq(&self, other: &ModInfo) -> bool {
self.id == other.id
}
}
impl Eq for ModInfo {}