Search code examples
postgresqlrustcastingnull

Cast option values directly?


I'm using the postgres-rs crate to retrieve info from a database. The query result gets stored in a postgres::Row where I can read a value at a time with Row::get().

So far so good, but now I want to read a PostgreSQL smallint or i16, and use this value as an i64 in Rust. I got it to work with:

let temp: Option<i16> = row.get(index);
let value = if let Some(v) = temp { Some(i64::from(v)) } else { None };

But it must be because my lack of experience with Rust that I can't write a one liner. I've tried:

let value: Option<i64> = row.get::<Option<i16>>::get(index);

But that leaves me with an error:

the trait `postgres::row::RowIndex` is not implemented for `std::option::Option<i64>`

Also I can't seem to cast option values directly:

let value: Option<usize> = Some(1 as i16).into();

This also gives me a similar error:

the trait `From<Option<i16>>` is not implemented for `Option<usize>`

I assume these errors are by design, but I'm still wondering if there isn't a shorter or better way to rewrite my first working example.


Solution

  • Row::get() takes two generic type arguments: I, type of the index, and T, type of the return vaue. Your attempt to specify the type argument sets the first one, which is I, whereas you meant to set T. This is why you get the error that "trait RowIndex is not implemented for Option<i64>". You need to use _ to leave it to the compiler to infer I:

    let value: Option<i64> = row.get::<_, Option<i16>>(index).map(Into::into);
    

    Your other issue that you try to convert to usize using the From (or Into) trait, which doesn't work because From is for conversions that can't fail. Since there are i16 values that can't be represented as usize (all the negative ones), From<i16> is not implemented for usize. Instead, you need to use TryFrom, which is, and handle errors accordingly.