use serde::de::DeserializeOwned;
use serde::Serialize;
#[derive(Debug)]
pub enum SerdeFMError {
YamlParseError(serde_yaml::Error),
MissingFrontMatter,
}
impl From<serde_yaml::Error> for SerdeFMError {
fn from(e: serde_yaml::Error) -> SerdeFMError {
Self::YamlParseError(e)
}
}
pub fn deserialize<T: DeserializeOwned>(data: &str) -> Result<(T, String), SerdeFMError> {
if !data.starts_with("---") {
return Err(SerdeFMError::MissingFrontMatter);
}
let split_data = data.split("---").map(Into::into).collect::<Vec<String>>();
let frontmatter = match split_data.get(1) {
Some(fm) => Ok(fm),
None => Err(SerdeFMError::MissingFrontMatter),
}?;
let content = match split_data.get(2) {
Some(content) => content.clone(),
None => String::new(),
};
Ok((serde_yaml::from_str(frontmatter.as_ref())?, content))
}
pub fn serialize<T: Serialize>(front_matter: T, content: &str) -> Result<String, SerdeFMError> {
let frontmatter = serde_yaml::to_string(&front_matter)?;
Ok(format!("{}\n---\n{}", frontmatter, content))
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct FM {
pub title: String,
}
#[test]
fn test_valid() {
let test_string = "---\ntitle: Valid Yaml Test\n---\nsomething that's not yaml";
let (matter, content) = deserialize::<FM>(&test_string).unwrap();
assert_eq!(matter.title, "Valid Yaml Test");
assert_eq!(content, "\nsomething that's not yaml");
}
#[test]
fn test_invalid() {
let test_string = "something that's not yaml even if it has\n---\nsome: yaml\n--";
let result = deserialize::<FM>(&test_string);
assert!(result.is_err());
}
}