use crate::phonetic::common::Position;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FileMetadata {
pub name: Option<String>,
pub version: Option<String>,
pub author: Option<String>,
pub description: Option<String>,
}
impl FileMetadata {
pub fn new() -> Self {
Self::default()
}
pub fn with_name(name: impl Into<String>) -> Self {
Self {
name: Some(name.into()),
..Default::default()
}
}
pub fn is_empty(&self) -> bool {
self.name.is_none()
&& self.version.is_none()
&& self.author.is_none()
&& self.description.is_none()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn version(mut self, version: impl Into<String>) -> Self {
self.version = Some(version.into());
self
}
pub fn author(mut self, author: impl Into<String>) -> Self {
self.author = Some(author.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MetadataDirective {
Name(String, Position),
Version(String, Position),
Author(String, Position),
Description(String, Position),
}
impl MetadataDirective {
pub fn directive_name(&self) -> &'static str {
match self {
Self::Name(..) => "name",
Self::Version(..) => "version",
Self::Author(..) => "author",
Self::Description(..) => "description",
}
}
pub fn value(&self) -> &str {
match self {
Self::Name(v, _)
| Self::Version(v, _)
| Self::Author(v, _)
| Self::Description(v, _) => v,
}
}
pub fn position(&self) -> Position {
match self {
Self::Name(_, p)
| Self::Version(_, p)
| Self::Author(_, p)
| Self::Description(_, p) => *p,
}
}
pub fn apply_to(&self, metadata: &mut FileMetadata) -> Result<(), Position> {
match self {
Self::Name(value, _) => {
if metadata.name.is_some() {
return Err(self.position());
}
metadata.name = Some(value.clone());
}
Self::Version(value, _) => {
if metadata.version.is_some() {
return Err(self.position());
}
metadata.version = Some(value.clone());
}
Self::Author(value, _) => {
if metadata.author.is_some() {
return Err(self.position());
}
metadata.author = Some(value.clone());
}
Self::Description(value, _) => {
if metadata.description.is_some() {
return Err(self.position());
}
metadata.description = Some(value.clone());
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_file_metadata_default() {
let metadata = FileMetadata::default();
assert!(metadata.is_empty());
assert!(metadata.name.is_none());
assert!(metadata.version.is_none());
assert!(metadata.author.is_none());
assert!(metadata.description.is_none());
}
#[test]
fn test_file_metadata_with_name() {
let metadata = FileMetadata::with_name("Test Rules");
assert!(!metadata.is_empty());
assert_eq!(metadata.name, Some("Test Rules".to_string()));
}
#[test]
fn test_file_metadata_builder() {
let metadata = FileMetadata::new()
.name("Test Rules")
.version("1.0")
.author("Test Author")
.description("Test description");
assert!(!metadata.is_empty());
assert_eq!(metadata.name, Some("Test Rules".to_string()));
assert_eq!(metadata.version, Some("1.0".to_string()));
assert_eq!(metadata.author, Some("Test Author".to_string()));
assert_eq!(metadata.description, Some("Test description".to_string()));
}
#[test]
fn test_metadata_directive_apply() {
let mut metadata = FileMetadata::new();
let name_directive = MetadataDirective::Name("Test".into(), Position::start());
assert!(name_directive.apply_to(&mut metadata).is_ok());
assert_eq!(metadata.name, Some("Test".to_string()));
let name_directive2 = MetadataDirective::Name("Test2".into(), Position::new(2, 1, 10));
assert!(name_directive2.apply_to(&mut metadata).is_err());
}
#[test]
fn test_metadata_directive_accessors() {
let directive = MetadataDirective::Name("Test".into(), Position::new(1, 1, 0));
assert_eq!(directive.directive_name(), "name");
assert_eq!(directive.value(), "Test");
assert_eq!(directive.position(), Position::new(1, 1, 0));
}
}