the x type, to my understanding, should be Result<T, String>, but the expected type should be Result<Option, String>;
However, the code compiles.................
pub fn timed_kv_load<T: DeserializeOwned>(key: &str, secs: i32) -> Result<Option<T>, String> {
#[derive(QueryableByName)]
struct LoadResult {
#[diesel(sql_type = Jsonb)]
pub value: serde_json::Value,
}
let pool = pg_conn_get();
let mut conn = pool.get().map_err(|e| e.to_string())?;
let sql = "SELECT load_timed_kv($1, $2) as value";
let result = sql_query(sql)
.bind::<Text, _>(key)
.bind::<Integer, _>(secs)
.get_results::<LoadResult>(&mut conn);
match result {
Ok(mut r) if r.len() > 0 => {
let x = serde_json::from_value(r.pop().unwrap().value).map_err(|e| e.to_string());
x
}
Ok(_) => Ok(None),
Err(e) => Err(e.to_string()),
}
}
Why should it? serde_json::from_value is generic, it can return Result<Type, Error> for any Deserializeable Type, and Option<T> is Deserialize whenever T is Deserialize. And since you haven't required explicitly which type it must return, this type is inferred from the place where it is called.
1 Like
Deserialize is implemented for Option<T> given T: Deserialize
So, if there is an serde_json::Value::Integer(i32), I can make it deserialized to Some(i32)?
I know this, but I didn't realized a Value::Number(i32) can be Deserialized to Option<i32>
yes.
serde use Option<T> as a "nullable" marker. when serializing, None is serialized as null (or equivalence) value of the format, and when deserializing, absence of value is deserialized successfully to None.
note, Option<T> does not guarantee deserialization will always succeed. when the value is NOT null but cannot be deserialized as T, you get an Err back instead of Ok(None).
fn from_json(value: serde_json::Value) -> serde_json::Result<Option<i32>> {
serde_json::from_value(value)
}
fn main() {
use serde_json::json;
assert!(matches!(from_json(json!(42)), Ok(Some(42))));
assert!(matches!(from_json(json!(null)), Ok(None)));
assert!(matches!(from_json(json!("hello")), Err(_)));
}