I would like to parse the type of each value in a row of data from tokio-postgresql
Here is an example of getting a single value for a row of data from postgresql:
...
let rows = client
.query("select * from ExampleTable;")
.await?;
// This is how you read a string if you know the first column is a string type.
let thisValue: &str = rows[0].get(0);
In this example, it is known at design-time that the type in the first column is a string, and therefore the type for thisValue
is &str
. I would like to accept an invariant type.
I intend to use std::any::type_name::<T>()
to derive the type name in thisValue
and then use conditional logic (if/switch) to process this data differently depending on the type.
Is there an invariant way to store a variable in Rust? Will std::any::type_name::<T>()
work on that variable? Is there another way to "box" the variable instead?
I understand that std::any::type_name::<T>()
is using a kind of generics interface. To me, this means it's probably a compile-time strategy, not run-time. So I have my doubts that the way I am researching will work, but I hope I am on the right track and only need the final piece: an invariant type.
Should I be using &dyn Any
and TypeId::of::<TypeHere>() == thisValue.type_id()
?
In this situation, the get
function of this API tokio-postgresql
uses generics and doesn't return a boxed value. Therefore in this situation I may need to use columns()
to determine the Rust type and the use separate functions to call get
with different variables types.
The overall question still needs to be answered "How to store an invariant type variable in Rust", regardless of the specifics I have used to ask the title question.
&dyn any
With &dyn any
: any is the trait, dyn means the type of the trait.
Declaring:
let thisValue: &dyn Any = rows[0].get(0); //This works if tokio-postgresql returned a "dyn any" type, which it doesn't
Example of testing what type is referenced:
TypeId::of::<String>() == thisValue.type_id() //type checking using TypeId of boxed value.
Example of testing the type with downcast:
if let Some(string) = thisValue.downcast_ref::<String>() {
println!("String ({}): {}", string.len(), string);
}
Box to force heap allocation (if necessary). This strategy is included too, so you can see how &dyn Any
works with Boxed
A "boxed" value of dyn Any
is invariant:
let thisValue: Boxed<dyn Any> = rows[0].get(0); //This works if tokio-postgresql returned a "dyn any" type, which it doesn't
In this scenario the API being used requires generic inference, so for tokio-postgresql this won't work, but it is the answer for the title question.
An example of testing the type with the downcast
function of Boxed
:
if let Ok(string) = thisValue.downcast::<String>() {
println!("String ({}): {}", string.len(), string);
}
About the postgresql sub-problem
As per the original post,
In this situation, the get function of this API tokio-postgresql uses generics and doesn't return a boxed value. Therefore in this situation I may need to use columns() to determine the Rust type and the use separate functions to call get with different variables types.
So this answer solves the question, and although it won't work with the tokio-postgresql API, it equips you with the knowledge of the kind of API you would like to find/build/wait-for.