use std::fmt;
use std::str;
use std::str::FromStr;
use serde::{Serialize, Deserialize};
use crate::{error::EpbdError, types::RenNrenCo2};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Meta {
pub key: String,
pub value: String,
}
impl Meta {
pub fn new<T, U>(key: T, value: U) -> Self
where
T: Into<String>,
U: Into<String>,
{
Self {
key: key.into(),
value: value.into(),
}
}
}
impl fmt::Display for Meta {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#META {}: {}", self.key, self.value)
}
}
impl std::str::FromStr for Meta {
type Err = EpbdError;
fn from_str(s: &str) -> Result<Meta, Self::Err> {
let items: Vec<&str> = s.trim()[5..].splitn(2, ':').map(str::trim).collect();
if items.len() == 2 {
let key = match items[0].trim() {
"Localizacion" => "CTE_LOCALIZACION",
"Area_ref" => "CTE_AREAREF",
"kexp" => "CTE_KEXP",
x => x,
};
let value = items[1].trim();
Ok(Meta::new(key, value))
} else {
Err(EpbdError::ParseError(s.into()))
}
}
}
pub trait MetaVec {
fn get_metavec(&self) -> &Vec<Meta>;
fn get_mut_metavec(&mut self) -> &mut Vec<Meta>;
fn has_meta(&self, key: &str) -> bool {
self.get_metavec().iter().any(|m| m.key == key)
}
fn has_meta_value(&self, key: &str, value: &str) -> bool {
self.get_meta(key).map(|v| v == value).unwrap_or(false)
}
fn get_meta(&self, key: &str) -> Option<String> {
self.get_metavec()
.iter()
.find(|m| m.key == key)
.map(|v| v.value.clone())
}
fn get_meta_f32(&self, key: &str) -> Option<f32> {
self.get_metavec()
.iter()
.find(|m| m.key == key)
.and_then(|v| f32::from_str(v.value.trim()).ok())
}
fn get_meta_rennren(&self, key: &str) -> Option<RenNrenCo2> {
self.get_metavec()
.iter()
.find(|m| m.key == key)
.and_then(|v| {
v.value
.parse::<RenNrenCo2>()
.map_err(|e| {
eprintln!("No se puede transformar el metadato a RenNrenCo2: {:?}", v);
e
})
.ok()
})
}
fn set_meta(&mut self, key: &str, value: &str) {
let wmeta = self.get_mut_metavec();
let metapos = wmeta.iter().position(|m| m.key == key);
if let Some(pos) = metapos {
wmeta[pos].value = value.to_string();
} else {
wmeta.push(Meta::new(key, value));
};
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq};
#[test]
fn tmeta() {
let meta = Meta {
key: "CTE_FUENTE".to_string(),
value: "RITE2014".to_string(),
};
let meta2 = Meta::new("CTE_FUENTE", "RITE2014");
let metastr = "#META CTE_FUENTE: RITE2014";
assert_eq!(format!("{}", meta), metastr);
assert_eq!(format!("{}", meta2), metastr);
assert_eq!(format!("{}", metastr.parse::<Meta>().unwrap()), metastr);
}
}