Impl from_preferences

With creates a Preference instance from a list of pronoun weights.

Signed-off-by: Ben Aaron Goldberg <ben@benaaron.dev>
This commit is contained in:
Ben Aaron Goldberg 2021-10-24 00:01:48 -04:00
parent 87583fc383
commit 29addcaf9a
2 changed files with 225 additions and 0 deletions

View File

@ -65,6 +65,13 @@ pub trait Preference {
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
fn as_prefstring_bytes(&self) -> Vec<u8>;
/// Create a Preference instance from a list of pronoun preferences
///
/// This should produce an instance of Preference using the provided preferences.
/// `prefs` is a list of pronoun preferences. Each entry is the weight of the pronoun
/// at that index in the pronoun list in the settings.
fn from_preferences(prefs: &[u8]) -> Self where Self: Sized;
/// Parse a base64 prefstring
///
/// This is the primary method of creating a `Preference` object from a prefstring. The
@ -128,4 +135,8 @@ impl Preference for UserPreferences {
UserPreferences::V0(pref) => pref,
}.as_prefstring_bytes()
}
fn from_preferences(prefs: &[u8]) -> Self where Self: Sized {
UserPreferences::V0(UserPreferencesV0::from_preferences(prefs))
}
}

View File

@ -17,6 +17,7 @@ use std::{
/// 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
#[derive(Debug, PartialEq, Eq)]
pub struct UserPreferencesV0 {
pub default_weight: u8,
pub default_enabled: bool,
@ -129,6 +130,91 @@ impl Preference for UserPreferencesV0 {
.chain(self.commands.iter().map(|cmd| cmd.into()))
.collect()
}
fn from_preferences(prefs: &[u8]) -> Self where Self: Sized {
if prefs.is_empty() {
return Self::default();
}
let mut weight_counts = vec![0u8; *prefs.iter().max().unwrap() as usize + 1];
let mut num_zeros = 0;
for w in prefs {
if *w == 0 {
num_zeros += 1;
} else {
weight_counts[*w as usize] += 1;
}
}
let default_weight = weight_counts
.iter()
.enumerate()
.max_by(|(_, v1), (_, v2)| v1.cmp(v2))
.map(|(w, _)| w as u8)
.unwrap();
let default_enabled = num_zeros < prefs.len() / 2;
let mut commands = Vec::new();
if default_enabled {
let mut last_default = -1;
for (i, w) in prefs.iter().enumerate() {
let i = i as isize;
if *w == default_weight {
continue;
} else {
if i - last_default > 1 {
let toggle_enabled = *w == 0;
let distance = if toggle_enabled {
(i - last_default) as u8 - 1
} else {
(i - last_default) as u8 - 2
};
eprintln!("{} {} {} {}", toggle_enabled, distance, i, last_default);
commands.push(Command::Move {
toggle_enabled,
distance
});
if !toggle_enabled {
commands.push(Command::SetWeight(*w));
}
} else {
commands.push(Command::SetWeight(*w));
}
last_default = i;
}
}
} else {
let mut last_enabled = -1;
for (i, w) in prefs.iter().enumerate() {
let i = i as isize;
if *w == 0 {
continue;
} else {
if i - last_enabled > 1 {
let toggle_enabled = *w == default_weight;
let distance = if toggle_enabled {
(i - last_enabled) as u8 - 1
} else {
(i - last_enabled) as u8 - 2
};
eprintln!("{} {} {} {}", toggle_enabled, distance, i, last_enabled);
commands.push(Command::Move {
toggle_enabled,
distance
});
if !toggle_enabled {
commands.push(Command::SetWeight(*w));
}
} else {
commands.push(Command::SetWeight(*w));
}
last_enabled = i;
}
}
}
Self {
default_weight,
default_enabled,
commands,
}
}
}
/// Default to all pronouns on with equal weight
@ -392,4 +478,132 @@ mod tests {
check_table(table, expected_table);
}
#[test]
fn test_from_prefs_most_disabled1() {
let pref_vals = vec![0,1,2,0,0];
let expected_prefs = UserPreferencesV0 {
default_enabled: false,
default_weight: 2,
commands: vec![
Command::Move {
toggle_enabled: false,
distance: 0,
},
Command::SetWeight(1),
Command::SetWeight(2),
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
#[test]
fn test_from_prefs_most_disabled2() {
let pref_vals = vec![0,1,1,0,0,0,2];
let expected_prefs = UserPreferencesV0 {
default_enabled: false,
default_weight: 1,
commands: vec![
Command::Move {
toggle_enabled: true,
distance: 1,
},
Command::SetWeight(1),
Command::Move {
toggle_enabled: false,
distance: 2,
},
Command::SetWeight(2),
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
#[test]
fn test_from_prefs_most_disabled3() {
let pref_vals = vec![0,0,0,0,1,0,0,0,2];
let expected_prefs = UserPreferencesV0 {
default_enabled: false,
default_weight: 2,
commands: vec![
Command::Move {
toggle_enabled: false,
distance: 3,
},
Command::SetWeight(1),
Command::Move {
toggle_enabled: true,
distance: 3,
},
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
#[test]
fn test_from_prefs_most_enabled1() {
let pref_vals = vec![0,1,2,1,1];
let expected_prefs = UserPreferencesV0 {
default_enabled: true,
default_weight: 1,
commands: vec![
Command::SetWeight(0),
Command::Move {
toggle_enabled: false,
distance: 0,
},
Command::SetWeight(2),
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
#[test]
fn test_from_prefs_most_enabled2() {
let pref_vals = vec![1,0,0,1,1,1,2];
let expected_prefs = UserPreferencesV0 {
default_enabled: true,
default_weight: 1,
commands: vec![
Command::Move {
toggle_enabled: true,
distance: 1,
},
Command::SetWeight(0),
Command::Move {
toggle_enabled: false,
distance: 2,
},
Command::SetWeight(2),
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
#[test]
fn test_from_prefs_most_enabled3() {
let pref_vals = vec![1,1,1,1,0,1,1,1,2];
let expected_prefs = UserPreferencesV0 {
default_enabled: true,
default_weight: 1,
commands: vec![
Command::Move {
toggle_enabled: true,
distance: 4,
},
Command::Move {
toggle_enabled: false,
distance: 2,
},
Command::SetWeight(2),
],
};
let prefs = UserPreferencesV0::from_preferences(&pref_vals);
assert_eq!(prefs, expected_prefs);
}
}