PronounsToday/src/lib.rs

210 lines
7.1 KiB
Rust

//! The algorithms powering pronouns.today - Random pronouns generated daily
//!
//! This library contains all of the functionality for selecting a random pronoun based off of a
//! user's preferences, including parsing various preference string (prefstring) versions,
//! generating a weighted table based off of user preferences, and selecting a pronoun set based
//! off of that weighted table.
//!
//! ## Basic Usage
//!
//! ```
//! use pronouns_today::InstanceSettings;
//!
//! let instance_settings = InstanceSettings::default(); // Or load from a config file
//!
//! // When you receive a request
//! let user_name = Some("Emi");
//! let user_prefstr = Some("acaqqbykawbag");
//! let pronouns = instance_settings.select_pronouns(user_name, user_prefstr);
//!
//! println!("Your pronouns are: {}", pronouns);
//! ```
//!
//! ## Advanced Usage
//!
//! The `InstanceSettings::select_pronouns()` method is really just a shorthand for the
//! more complex process going on behind the scenes. In reality, there are several steps
//! used to select the pronouns. Each step can be modified or run individually for
//! greater control.
//!
//! 1. Configure the [`InstanceSettings`] from a config or default
//! 2. Parse the user's prefstring with [`UserPreferences::from_prefstring()`][up]
//! 3. Produce a weighted table from the preferences using
//! [`UserPreferences::into_weighted_table()`][up]
//! 4. Roll a pronoun set from the weighted table with one of the methods in the
//! [`WeightedTable`] struct.
//! 5. Render the [`Pronoun`]s with one of the provided methods, or use the forms
//! individually.
//!
//! [up]: UserPreferences
pub mod user_preferences;
mod weighted_table;
use std::fmt;
use serde::{Serialize, Deserialize, self};
pub use weighted_table::WeightedTable;
pub use user_preferences::UserPreferences;
/// Runtime-constant setting that apply to an entire pronouns.today instance
///
/// These are values specified by the instance operator through the pronouns.today config file.
///
/// This is also the struct that is used to perform the majority of operations pertaining parsing
/// user preference strings (prefstrings). Utility methods are also provided for parsing a
/// prefstring and then selecting a pronoun with it all at once.
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct InstanceSettings {
/// A list of pronouns recognized by the instance
pub pronoun_list: Vec<Pronoun>,
}
impl InstanceSettings {
/// Parse a prefstring and then immediately select pronouns from it.
///
/// This is shorthand for
///
/// ```
/// # use pronouns_today::InstanceSettings;
/// # let settings = InstanceSettings::default();
/// # let name = String::from("Sashanora");
/// # let prefstring = String::from("todo");
/// let pronouns = settings.parse_prefstring(Some(&prefstring)).select_pronouns(Some(&name));
/// # assert_eq!(pronouns, settings.select_pronouns(Some(&name), Some(&prefstring)));
/// ```
pub fn select_pronouns(&self, name: Option<impl AsRef<str>>, pref_string: Option<impl AsRef<str>>) -> &str {
todo!()
}
}
impl Default for InstanceSettings {
fn default() -> Self {
let pronouns: Vec<Pronoun> = vec![
["she", "her", "her", "hers", "herself" ].into(),
["he", "him", "his", "his", "himself" ].into(),
["they", "them", "their", "theirs", "themself" ].into(),
["it", "it", "its", "its", "itself" ].into(),
["xe", "xem", "xyr", "xyrs", "xemself" ].into(),
["ze", "zem", "zyr", "zyrs", "zemself" ].into(),
["fae", "faer", "faer", "faers", "faerself" ].into(),
["ne", "nem", "nir", "nirs", "nirself" ].into(),
["e", "em", "eir", "eirs", "eirself" ].into(),
["vey", "vem", "ver", "vers", "verself" ].into(),
];
InstanceSettings {
pronoun_list: pronouns
}
}
}
/// A standard five-form pronoun set
///
/// All pronouns are configured as five-form pronoun set. This is necessary in order to display
/// example sentances to the user. However, typically only two or three forms of the pronoun are
/// used to display the pronoun. For example, she/her/her/hers/herself would typically be written
/// she/her or she/her/hers.
///
/// Methods are provided to quickly generate these shorter forms, as well as example sentences.
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Debug)]
#[serde(from = "[String; 5]", into = "[String; 5]")]
pub struct Pronoun {
/// The pronoun's form when used as a subject
///
/// For "she", this is "she", as in
///
/// > *She* went to the park.
pub subject_pronoun: String,
/// The pronoun's form when used as an object
///
/// For "she", this is "her", as in
///
/// > I went with *her*
pub object_pronoun: String,
/// The pronoun's form when used as a possesive determiner
///
/// For "she", this is "her", as in
///
/// > I have *her* frisbee
pub possesive_determiner: String,
/// The pronoun's form when used as a possesive pronoun
///
/// For "she", this is "hers", as in
///
/// > At least I think it is *hers*.
pub possesive_pronoun: String,
/// The pronoun's form when used reflexively
///
/// For "she", this is "herself", as in
///
/// > She did it herself
pub reflexive_pronoun: String,
}
impl Pronoun {
pub fn render_threeform(&self) -> String {
format!("{}/{}/{}", self.subject_pronoun, self.object_pronoun, self.possesive_pronoun)
}
}
impl fmt::Display for Pronoun {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.render_threeform())
}
}
impl From<[String; 5]> for Pronoun {
fn from(five_form: [String; 5]) -> Self {
let mut five_form = IntoIterator::into_iter(five_form);
// If anyone knows a better way of deconstructing this, *please* let me know, or PR
Pronoun {
subject_pronoun: five_form.next().unwrap(),
object_pronoun: five_form.next().unwrap(),
possesive_determiner: five_form.next().unwrap(),
possesive_pronoun: five_form.next().unwrap(),
reflexive_pronoun: five_form.next().unwrap(),
}
}
}
impl From<[&str; 5]> for Pronoun {
fn from(five_form: [&str; 5]) -> Self {
(&five_form).into()
}
}
impl From<&[&str; 5]> for Pronoun {
fn from(five_form: &[&str; 5]) -> Self {
Pronoun {
subject_pronoun: five_form[0].to_string(),
object_pronoun: five_form[1].to_string(),
possesive_determiner: five_form[2].to_string(),
possesive_pronoun: five_form[3].to_string(),
reflexive_pronoun: five_form[4].to_string(),
}
}
}
impl From<Pronoun> for [String; 5] {
fn from(pronoun: Pronoun) -> Self {
[
pronoun.subject_pronoun,
pronoun.object_pronoun,
pronoun.possesive_determiner,
pronoun.possesive_pronoun,
pronoun.reflexive_pronoun,
]
}
}