handle some instances of floats when an integer is expected during sync

This commit is contained in:
Damien Elmes 2020-08-03 17:47:15 +10:00
parent 655001eaf5
commit b363aaf401
3 changed files with 57 additions and 7 deletions

View file

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::serde::default_on_invalid;
use crate::serde::{default_on_invalid, deserialize_int_from_number};
use crate::{define_newtype, prelude::*};
use num_enum::TryFromPrimitive;
use serde::Deserialize;
@ -20,16 +20,16 @@ pub struct RevlogEntry {
#[serde(rename = "ease")]
pub button_chosen: u8,
/// Positive values are in days, negative values in seconds.
#[serde(rename = "ivl")]
#[serde(rename = "ivl", deserialize_with = "deserialize_int_from_number")]
pub interval: i32,
/// Positive values are in days, negative values in seconds.
#[serde(rename = "lastIvl")]
#[serde(rename = "lastIvl", deserialize_with = "deserialize_int_from_number")]
pub last_interval: i32,
/// Card's ease after answering, stored as 10x the %, eg 2500 represents 250%.
#[serde(rename = "factor")]
#[serde(rename = "factor", deserialize_with = "deserialize_int_from_number")]
pub ease_factor: u32,
/// Amount of milliseconds taken to answer the card.
#[serde(rename = "time")]
#[serde(rename = "time", deserialize_with = "deserialize_int_from_number")]
pub taken_millis: u32,
#[serde(rename = "type", default, deserialize_with = "default_on_invalid")]
pub review_kind: RevlogReviewKind,

View file

@ -1,7 +1,8 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use serde::Deserialize as DeTrait;
use crate::timestamp::TimestampSecs;
use serde::{Deserialize as DeTrait, Deserializer};
pub(crate) use serde_aux::field_attributes::{
deserialize_bool_from_anything, deserialize_number_from_string,
};
@ -15,3 +16,50 @@ where
let v: Value = DeTrait::deserialize(deserializer)?;
Ok(T::deserialize(v).unwrap_or_default())
}
pub fn deserialize_int_from_number<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: serde::Deserialize<'de> + FromF64,
{
#[derive(DeTrait)]
#[serde(untagged)]
enum IntOrFloat<T> {
Int(T),
Float(f64),
}
match IntOrFloat::<T>::deserialize(deserializer)? {
IntOrFloat::Float(s) => Ok(T::from_f64(s)),
IntOrFloat::Int(i) => Ok(i),
}
}
// It may be possible to use the num_traits crate instead in the future.
pub trait FromF64 {
fn from_f64(val: f64) -> Self;
}
impl FromF64 for i32 {
fn from_f64(val: f64) -> Self {
val as Self
}
}
impl FromF64 for u32 {
fn from_f64(val: f64) -> Self {
val as Self
}
}
impl FromF64 for i64 {
fn from_f64(val: f64) -> Self {
val as Self
}
}
impl FromF64 for TimestampSecs {
fn from_f64(val: f64) -> Self {
TimestampSecs(val as i64)
}
}

View file

@ -13,7 +13,7 @@ use crate::{
notetype::{NoteType, NoteTypeSchema11},
prelude::*,
revlog::RevlogEntry,
serde::default_on_invalid,
serde::{default_on_invalid, deserialize_int_from_number},
tags::{join_tags, split_tags},
version::sync_client_version,
};
@ -139,11 +139,13 @@ pub struct CardEntry {
pub nid: NoteID,
pub did: DeckID,
pub ord: u16,
#[serde(deserialize_with = "deserialize_int_from_number")]
pub mtime: TimestampSecs,
pub usn: Usn,
pub ctype: CardType,
pub queue: CardQueue,
pub due: i32,
#[serde(deserialize_with = "deserialize_int_from_number")]
pub ivl: u32,
pub factor: u16,
pub reps: u32,