diff --git a/src/lib.rs b/src/lib.rs index baeca87..359c69c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ pub mod user_preferences; pub mod util; mod weighted_table; +use std::error::Error; +use core::str::FromStr; use std::fmt; use serde::{Serialize, Deserialize, self}; @@ -248,3 +250,108 @@ impl From<Pronoun> for [String; 5] { ] } } + +/// An intermediary struct to facilitate parsing and serializing lists of pronouns +/// +/// ## Examples +/// +/// ``` +/// use pronouns_today::PronounList; +/// +/// let list: PronounList = vec![ +/// ["she", "her", "her", "hers", "herself" ].into(), +/// ["he", "him", "his", "his", "himself" ].into(), +/// ].into(); +/// +/// assert_eq!( +/// list.to_string(), +/// "she/her/her/hers/herself,he/him/his/his/himself" +/// ) +/// ``` +/// +/// ``` +/// use pronouns_today::PronounList; +/// use pronouns_today::Pronoun; +/// +/// let unparsed = "sea/sear/sear/sears/seaself,po/pony/ponys/ponys/ponyself"; +/// let parsed: PronounList = unparsed.parse().unwrap(); +/// let parsed_vec: Vec<Pronoun> = parsed.into(); +/// +/// assert_eq!( +/// parsed_vec, +/// vec![ +/// ["sea", "sear", "sear", "sears", "seaself" ].into(), +/// ["po", "pony", "ponys", "ponys", "ponyself" ].into(), +/// ] +/// ) +/// ``` +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct PronounList(Vec<Pronoun>); + +impl fmt::Display for PronounList { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for set_i in 0..self.0.len() { + let set = &self.0[set_i]; + if set_i > 0 { + write!(f, ",")?; + } + write!(f, + "{}/{}/{}/{}/{}", + set.subject_pronoun, + set.object_pronoun, + set.possesive_determiner, + set.possesive_pronoun, + set.reflexive_pronoun, + )?; + } + Ok(()) + } +} + +impl FromStr for PronounList { + type Err = PronounListError; + fn from_str(s: &str) -> Result<PronounList, Self::Err> { + s.split(',') + .map(|s| { + let split: Vec<&str> = s.split('/').collect(); + if split.len() != 5 { + Err(PronounListError) + } else { + Ok(Pronoun { + subject_pronoun: split[0].into(), + object_pronoun: split[1].into(), + possesive_determiner: split[2].into(), + possesive_pronoun: split[3].into(), + reflexive_pronoun: split[4].into(), + }) + } + }) + .collect::<Result<Vec<Pronoun>, PronounListError>>() + .map(PronounList) + } +} + +impl From<PronounList> for Vec<Pronoun> { + fn from(list: PronounList) -> Vec<Pronoun> { + list.0 + } +} + +impl From<Vec<Pronoun>> for PronounList { + fn from(list: Vec<Pronoun>) -> PronounList { + PronounList(list) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct PronounListError; + +impl fmt::Display for PronounListError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("Pronouns must be written in their five-form form, with each form + seperated by a slash (/), and each set seperated by a comma (,). For + example: 'he/him/his/his/himself,she/her/her/hers/herself'") + } +} + +impl Error for PronounListError {}