From 0ac2f401f8ac06bbbb0112b5bda63606f093bcd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Dom=C3=ADnguez?= Date: Fri, 20 Nov 2020 00:36:51 +0100 Subject: [PATCH] Add function to deserialize numbers and strings as an integer --- ruma-serde/src/lib.rs | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/ruma-serde/src/lib.rs b/ruma-serde/src/lib.rs index aa4717c9..34c7536b 100644 --- a/ruma-serde/src/lib.rs +++ b/ruma-serde/src/lib.rs @@ -1,6 +1,11 @@ //! De-/serialization helpers for other ruma crates -use serde::de::{Deserialize, IntoDeserializer}; +use js_int::Int; +use serde::{ + de::{Error, IntoDeserializer}, + Deserialize, +}; +use std::convert::{TryFrom, TryInto}; pub mod can_be_empty; mod canonical_json; @@ -65,3 +70,33 @@ where Some(s) => T::deserialize(s.into_deserializer()).map(Some), } } + +// Helper type for deserialize_int_or_string_to_int +#[derive(Deserialize)] +#[serde(untagged)] +enum IntOrString<'a> { + Num(Int), + Str(&'a str), +} + +impl TryFrom> for Int { + type Error = js_int::ParseIntError; + + fn try_from(input: IntOrString) -> Result { + match input { + IntOrString::Num(n) => Ok(n), + IntOrString::Str(string) => string.parse(), + } + } +} + +/// Take either an integer number or a string and deserialize to an integer number. +/// +/// To be used like this: +/// `#[serde(deserialize_with = "int_or_string_to_int")]` +pub fn int_or_string_to_int<'de, D>(de: D) -> Result +where + D: serde::Deserializer<'de>, +{ + IntOrString::deserialize(de)?.try_into().map_err(D::Error::custom) +}