handle AnkiDroid's two element new intervals

https://github.com/ankidroid/Anki-Android/issues/8889
This commit is contained in:
Damien Elmes 2021-10-07 23:15:51 +10:00
parent 3814385e41
commit ca32a46594

View file

@ -3,6 +3,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Deserialize as DeTrait, Deserializer};
use serde_aux::field_attributes::deserialize_number_from_string; use serde_aux::field_attributes::deserialize_number_from_string;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
@ -66,7 +67,7 @@ pub struct NewConfSchema11 {
#[serde(deserialize_with = "default_on_invalid")] #[serde(deserialize_with = "default_on_invalid")]
delays: Vec<f32>, delays: Vec<f32>,
initial_factor: u16, initial_factor: u16,
#[serde(deserialize_with = "default_on_invalid")] #[serde(deserialize_with = "deserialize_new_intervals")]
ints: NewCardIntervals, ints: NewCardIntervals,
#[serde(deserialize_with = "default_on_invalid")] #[serde(deserialize_with = "default_on_invalid")]
pub(crate) order: NewCardOrderSchema11, pub(crate) order: NewCardOrderSchema11,
@ -77,7 +78,7 @@ pub struct NewConfSchema11 {
other: HashMap<String, Value>, other: HashMap<String, Value>,
} }
#[derive(Serialize_tuple, Deserialize, Debug, PartialEq, Clone)] #[derive(Serialize_tuple, Debug, PartialEq, Clone)]
pub struct NewCardIntervals { pub struct NewCardIntervals {
good: u16, good: u16,
easy: u16, easy: u16,
@ -89,11 +90,34 @@ impl Default for NewCardIntervals {
Self { Self {
good: 1, good: 1,
easy: 4, easy: 4,
_unused: 7, _unused: 0,
} }
} }
} }
/// This extra logic is required because AnkiDroid's options screen was creating
/// a 2 element array instead of a 3 element one.
fn deserialize_new_intervals<'de, D>(deserializer: D) -> Result<NewCardIntervals, D::Error>
where
D: Deserializer<'de>,
{
let vals: Result<Vec<u16>, _> = DeTrait::deserialize(deserializer);
Ok(vals
.ok()
.and_then(|vals| {
if vals.len() >= 2 {
Some(NewCardIntervals {
good: vals[0],
easy: vals[1],
_unused: 0,
})
} else {
None
}
})
.unwrap_or_default())
}
#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)] #[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone)]
#[repr(u8)] #[repr(u8)]
pub enum NewCardOrderSchema11 { pub enum NewCardOrderSchema11 {
@ -396,3 +420,51 @@ fn clear_other_duplicates(top_other: &mut HashMap<String, Value>) {
top_other.remove(*key); top_other.remove(*key);
} }
} }
#[cfg(test)]
mod test {
use serde::de::IntoDeserializer;
use serde_json::{json, Value};
use super::*;
#[test]
fn new_intervals() {
let decode = |value: Value| -> NewCardIntervals {
deserialize_new_intervals(value.into_deserializer()).unwrap()
};
assert_eq!(
decode(json!([2, 4, 6])),
NewCardIntervals {
good: 2,
easy: 4,
_unused: 0
}
);
assert_eq!(
decode(json!([3, 9])),
NewCardIntervals {
good: 3,
easy: 9,
_unused: 0
}
);
// invalid input will yield defaults
assert_eq!(
decode(json!([4])),
NewCardIntervals {
good: 1,
easy: 4,
_unused: 0
}
);
assert_eq!(
decode(json!([-5, 4, 3])),
NewCardIntervals {
good: 1,
easy: 4,
_unused: 0
}
);
}
}