Stubbed some core functionality
This commit is contained in:
parent
6e4c63bfdf
commit
aeef51f1e4
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "PronounsToday"
|
name = "pronouns_today"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Emi <emi@alchemi.dev>", "Sashanora <ben@benaaron.dev>", "Bit <theotheroracle@disroot.org>"]
|
authors = ["Emi <emi@alchemi.dev>", "Sashanora <ben@benaaron.dev>", "Bit <theotheroracle@disroot.org>"]
|
||||||
|
@ -11,3 +11,9 @@ license-file = "LICENSE.md"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.19"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["derive"]
|
||||||
|
|
129
src/lib.rs
Normal file
129
src/lib.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
pub mod user_preferences;
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize, self};
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # settings = InstanceSettings::default();
|
||||||
|
/// # name = String::from("Sashanora");
|
||||||
|
/// # 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!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_prefstring(&self, pref_string: Option<impl AsRef<str>>) -> &str {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 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 {
|
||||||
|
let mut five_form = IntoIterator::into_iter(five_form);
|
||||||
|
Pronoun {
|
||||||
|
subject_pronoun: five_form.next().unwrap().to_string(),
|
||||||
|
object_pronoun: five_form.next().unwrap().to_string(),
|
||||||
|
possesive_determiner: five_form.next().unwrap().to_string(),
|
||||||
|
possesive_pronoun: five_form.next().unwrap().to_string(),
|
||||||
|
reflexive_pronoun: five_form.next().unwrap().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,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
97
src/user_preferences/mod.rs
Normal file
97
src/user_preferences/mod.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
//! Pronoun selection & parsing for various version of user preferences
|
||||||
|
//!
|
||||||
|
//! There may be several possible representations of parsed prefstrings, each of which possibly
|
||||||
|
//! with a different algorithm for selecting pronouns, and a different way of parsing itself. This
|
||||||
|
//! module houses the implementations for each of these versions.
|
||||||
|
|
||||||
|
pub mod v0;
|
||||||
|
|
||||||
|
use crate::{InstanceSettings, Pronoun};
|
||||||
|
|
||||||
|
use base64::{decode, encode};
|
||||||
|
use chrono::{Local, NaiveDate};
|
||||||
|
|
||||||
|
/// A user's preferences for the probabilities of certain pronouns
|
||||||
|
///
|
||||||
|
/// This is the parsed version of a prefstring. The actual implementation details may vary across
|
||||||
|
/// versions, but universally they must be able to at least randomly select a pronoun set unique to
|
||||||
|
/// a given date and name.
|
||||||
|
///
|
||||||
|
/// To this end, all versions of the user preferences implement [`Preference`]. For convenience,
|
||||||
|
/// `UserPreferences` also implements [`Preference`].
|
||||||
|
///
|
||||||
|
/// Because parsing a prefstring must be done in relation to an [`InstanceSettings`], the
|
||||||
|
/// `UserPreferences` struct shares a lifetime with the settings it was created with.
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum UserPreferences<'a> {
|
||||||
|
V0(v0::UserPreferencesV0<'a>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Functionality provided by any version of user preferences
|
||||||
|
///
|
||||||
|
/// See also: [`UserPreferences`]
|
||||||
|
pub trait Preference<'a> {
|
||||||
|
|
||||||
|
/// Randomly select a pronoun set for a given date and name.
|
||||||
|
///
|
||||||
|
/// This function should be *pure*, and any randomness must be emulating using PRNG. That is
|
||||||
|
/// to say, for any given date and name, this preference object must always produce the same
|
||||||
|
/// pronoun set.
|
||||||
|
fn select_pronouns_on_date(&self, date: NaiveDate, name: Option<&str>) -> &'a Pronoun;
|
||||||
|
|
||||||
|
/// A shorthand for calling [`Preference::select_pronouns_on_date()`] with today's date
|
||||||
|
///
|
||||||
|
/// The date is generated for the system's time and timezone
|
||||||
|
fn select_pronouns(&self, name: Option<&str>) -> &'a Pronoun {
|
||||||
|
self.select_pronouns_on_date(Local::today().naive_local(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a given prefstring, after it's extraction from base64
|
||||||
|
///
|
||||||
|
/// This should attempt to parse the data contained in a prefstring into the appropriate
|
||||||
|
/// format. Prefstrings will already have been parsed from base64 before being passed to the
|
||||||
|
/// implementation. Users looking to turn a b64 prefstring into a `Preference` should use
|
||||||
|
/// [`Preference::from_prefstring()`]
|
||||||
|
fn from_prefstring_bytes(bytes: &[u8], settings: &'a InstanceSettings) -> Self where Self: Sized;
|
||||||
|
|
||||||
|
/// Serialize these preferences into as few bytes as possible
|
||||||
|
///
|
||||||
|
/// This should produce a series of bytes that, when passed to
|
||||||
|
/// [`Preference::from_prefstring_bytes()`] should produce this `Preference` object again.
|
||||||
|
/// This should be done in accordance with the [prefstring specification][1].
|
||||||
|
///
|
||||||
|
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
|
||||||
|
fn into_prefstring_bytes(&self) -> Vec<u8>;
|
||||||
|
|
||||||
|
/// Parse a base64 prefstring
|
||||||
|
///
|
||||||
|
/// This is the primary method of creating a `Preference` object from a prefstring. The
|
||||||
|
/// default implementation calls the underlying [`Preference::from_prefstring_bytes()`] method.
|
||||||
|
fn from_prefstring(prefstring: &str, settings: &'a InstanceSettings) -> Result<Self, base64::DecodeError> where Self: Sized {
|
||||||
|
decode(prefstring).map(|ps| Self::from_prefstring_bytes(ps.as_ref(), settings))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize into a base64 prefstring
|
||||||
|
///
|
||||||
|
/// This is the primary method of creating a prefstring from a `Preference` object. The
|
||||||
|
/// default implementation calls the underlying [`Preference::into_prefstring_bytes()`] method.
|
||||||
|
fn into_prefstring(&self) -> String {
|
||||||
|
encode(self.into_prefstring_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Preference<'a> for UserPreferences<'a> {
|
||||||
|
fn select_pronouns_on_date(&self, date: NaiveDate, name: Option<&str>) -> &'a Pronoun {
|
||||||
|
match self {
|
||||||
|
UserPreferences::V0(pref) => pref,
|
||||||
|
}.select_pronouns_on_date(date, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_prefstring_bytes(bytes: &[u8], settings: &'a InstanceSettings) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_prefstring_bytes(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
32
src/user_preferences/v0.rs
Normal file
32
src/user_preferences/v0.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//! Version 0 Prefstrings
|
||||||
|
|
||||||
|
use crate::{InstanceSettings, Pronoun, user_preferences::Preference};
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use chrono::{NaiveDate};
|
||||||
|
|
||||||
|
/// A parsed version of the V0 prefstring
|
||||||
|
///
|
||||||
|
/// See the [prefstring specification][1] for more information about how this is interpretted.
|
||||||
|
///
|
||||||
|
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
|
||||||
|
pub struct UserPreferencesV0<'a> {
|
||||||
|
default_weight: u8,
|
||||||
|
default_enabled: bool,
|
||||||
|
overrides: HashMap<&'a Pronoun, u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Preference<'a> for UserPreferencesV0<'a> {
|
||||||
|
fn select_pronouns_on_date(&self, date: NaiveDate, name: Option<&str>) -> &'a Pronoun {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_prefstring_bytes(bytes: &[u8], settings: &'a InstanceSettings) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_prefstring_bytes(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue