use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TrackChanges {
#[default]
Accept,
Reject,
All,
}
impl TrackChanges {
pub const ACCEPTED: &'static str = "accept, reject, all";
pub fn parse(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"accept" | "accepted" => Some(Self::Accept),
"reject" | "rejected" => Some(Self::Reject),
"all" => Some(Self::All),
_ => None,
}
}
pub fn as_str(self) -> &'static str {
match self {
Self::Accept => "accept",
Self::Reject => "reject",
Self::All => "all",
}
}
}
impl fmt::Display for TrackChanges {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for TrackChanges {
type Err = String;
fn from_str(s: &str) -> Result<Self, String> {
Self::parse(s)
.ok_or_else(|| format!("track_changes must be one of {}; got {s:?}", Self::ACCEPTED))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RevisionKind {
Insertion,
Deletion,
}
impl RevisionKind {
pub fn as_str(self) -> &'static str {
match self {
Self::Insertion => "insertion",
Self::Deletion => "deletion",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Revision {
pub kind: RevisionKind,
pub author: Option<String>,
pub date: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spellings() {
assert_eq!("Accept".parse::<TrackChanges>(), Ok(TrackChanges::Accept));
assert_eq!(" all ".parse::<TrackChanges>(), Ok(TrackChanges::All));
assert_eq!(TrackChanges::parse("rejected"), Some(TrackChanges::Reject));
assert!("keep".parse::<TrackChanges>().is_err());
assert_eq!(TrackChanges::default().as_str(), "accept");
}
}