Why the code compiles, I think the type is conflict

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(_)));
}