From b363aaf401be63a995dede0e3ae109aa18ad6171 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 3 Aug 2020 17:47:15 +1000 Subject: [PATCH] handle some instances of floats when an integer is expected during sync --- rslib/src/revlog.rs | 10 ++++----- rslib/src/serde.rs | 50 ++++++++++++++++++++++++++++++++++++++++++- rslib/src/sync/mod.rs | 4 +++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/rslib/src/revlog.rs b/rslib/src/revlog.rs index 73caec66c..1d4d9dd6c 100644 --- a/rslib/src/revlog.rs +++ b/rslib/src/revlog.rs @@ -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, diff --git a/rslib/src/serde.rs b/rslib/src/serde.rs index ac2a9a9c3..ddb4ec03b 100644 --- a/rslib/src/serde.rs +++ b/rslib/src/serde.rs @@ -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 +where + D: Deserializer<'de>, + T: serde::Deserialize<'de> + FromF64, +{ + #[derive(DeTrait)] + #[serde(untagged)] + enum IntOrFloat { + Int(T), + Float(f64), + } + + match IntOrFloat::::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) + } +} diff --git a/rslib/src/sync/mod.rs b/rslib/src/sync/mod.rs index 2b2cacbc3..facdfe7a7 100644 --- a/rslib/src/sync/mod.rs +++ b/rslib/src/sync/mod.rs @@ -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,