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:
parent
87583fc383
commit
29addcaf9a
|
@ -65,6 +65,13 @@ pub trait Preference {
|
||||||
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
|
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
|
||||||
fn as_prefstring_bytes(&self) -> Vec<u8>;
|
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
|
/// Parse a base64 prefstring
|
||||||
///
|
///
|
||||||
/// This is the primary method of creating a `Preference` object from a prefstring. The
|
/// 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,
|
UserPreferences::V0(pref) => pref,
|
||||||
}.as_prefstring_bytes()
|
}.as_prefstring_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_preferences(prefs: &[u8]) -> Self where Self: Sized {
|
||||||
|
UserPreferences::V0(UserPreferencesV0::from_preferences(prefs))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use std::{
|
||||||
/// See the [prefstring specification][1] for more information about how this is interpretted.
|
/// 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
|
/// [1]: https://fem.mint.lgbt/Emi/PronounsToday/raw/branch/main/doc/User-Preference-String-Spec.txt
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct UserPreferencesV0 {
|
pub struct UserPreferencesV0 {
|
||||||
pub default_weight: u8,
|
pub default_weight: u8,
|
||||||
pub default_enabled: bool,
|
pub default_enabled: bool,
|
||||||
|
@ -129,6 +130,91 @@ impl Preference for UserPreferencesV0 {
|
||||||
.chain(self.commands.iter().map(|cmd| cmd.into()))
|
.chain(self.commands.iter().map(|cmd| cmd.into()))
|
||||||
.collect()
|
.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
|
/// Default to all pronouns on with equal weight
|
||||||
|
@ -392,4 +478,132 @@ mod tests {
|
||||||
|
|
||||||
check_table(table, expected_table);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue