1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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());
}
}