use crate::ape::constants::INVALID_KEYS;
use crate::ape::tag::error::ApeTagItemValidationError;
use crate::tag::ItemValue;
use crate::tag::item::ItemValueRef;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ApeItem {
pub read_only: bool,
pub(crate) key: String,
pub(crate) value: ItemValue,
}
impl ApeItem {
pub(crate) const EMPTY: Self = ApeItem {
read_only: false,
key: String::new(),
value: ItemValue::Text(String::new()),
};
pub fn new(key: String, value: ItemValue) -> Result<Self, ApeTagItemValidationError> {
if INVALID_KEYS.iter().any(|k| k.eq_ignore_ascii_case(&key)) {
return Err(ApeTagItemValidationError::illegal_key(&key));
}
if !(2..=255).contains(&key.len()) {
return Err(ApeTagItemValidationError::invalid_length());
}
if key.chars().any(|c| !(0x20..=0x7E).contains(&(c as u32))) {
return Err(ApeTagItemValidationError::invalid_characters());
}
Ok(Self {
read_only: false,
key,
value,
})
}
pub fn key(&self) -> &str {
&self.key
}
pub fn value(&self) -> &ItemValue {
&self.value
}
pub fn text_values(&self) -> Option<impl Iterator<Item = &str>> {
match self.value() {
ItemValue::Text(text) | ItemValue::Locator(text) => Some(text.split('\0')),
ItemValue::Binary(_) => None,
}
}
pub(crate) fn text(key: &str, value: String) -> Self {
Self {
read_only: false,
key: String::from(key),
value: ItemValue::Text(value),
}
}
}
pub(crate) struct ApeItemRef<'a> {
pub read_only: bool,
pub key: &'a str,
pub value: ItemValueRef<'a>,
}
impl<'a> Into<ApeItemRef<'a>> for &'a ApeItem {
fn into(self) -> ApeItemRef<'a> {
ApeItemRef {
read_only: self.read_only,
key: self.key(),
value: (&self.value).into(),
}
}
}