use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
#[non_exhaustive]
pub enum WireInline {
Text { text: String },
Bold { children: Vec<WireInline> },
Italic { children: Vec<WireInline> },
Code { text: String },
Math { text: String },
Reference {
ref_kind: RefKind,
target: String,
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<String>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum RefKind {
Url,
Citation,
Footnote,
Session,
File,
Placeholder,
Unsure,
General,
}
impl<'de> Deserialize<'de> for RefKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(match s.as_str() {
"url" => Self::Url,
"citation" => Self::Citation,
"footnote" => Self::Footnote,
"session" => Self::Session,
"file" => Self::File,
"placeholder" => Self::Placeholder,
"unsure" => Self::Unsure,
_ => Self::General,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn text_inline_round_trips() {
let i = WireInline::Text {
text: "hello".into(),
};
let s = serde_json::to_string(&i).unwrap();
assert_eq!(s, r#"{"kind":"text","text":"hello"}"#);
let back: WireInline = serde_json::from_str(&s).unwrap();
assert_eq!(back, i);
}
#[test]
fn bold_with_nested_text() {
let i = WireInline::Bold {
children: vec![WireInline::Text {
text: "loud".into(),
}],
};
let s = serde_json::to_string(&i).unwrap();
assert_eq!(
s,
r#"{"kind":"bold","children":[{"kind":"text","text":"loud"}]}"#
);
}
#[test]
fn reference_url_round_trips() {
let i = WireInline::Reference {
ref_kind: RefKind::Url,
target: "https://example.com".into(),
label: None,
};
let s = serde_json::to_string(&i).unwrap();
assert_eq!(
s,
r#"{"kind":"reference","ref_kind":"url","target":"https://example.com"}"#
);
let back: WireInline = serde_json::from_str(&s).unwrap();
assert_eq!(back, i);
}
#[test]
fn reference_with_label() {
let i = WireInline::Reference {
ref_kind: RefKind::Footnote,
target: "1".into(),
label: Some("note one".into()),
};
let s = serde_json::to_string(&i).unwrap();
let back: WireInline = serde_json::from_str(&s).unwrap();
assert_eq!(back, i);
}
#[test]
fn unknown_ref_kind_falls_back_to_general() {
let kind: RefKind = serde_json::from_str(r#""acronym""#).unwrap();
assert_eq!(kind, RefKind::General);
}
}