How to get query colums as String - rust

I'm porting a PHP-app to Rust (as a noob). Since my query results will go straight into html, I don't really need any type-safety. Just NULL -> "" and everything else as String.
Also time::PrimitiveDateTime doesn't fully implement format, such that {mytime:.19} doesn't cut off the useless ".0" milliseconds. So it'd be nice to have that as String too. Unless there is an easier conversion to get that?
Not having found (or understood) any appropriate converter, I tried
fn as_string(row: mysql::Row, index: usize) -> String {
if let Some(&value) = row.as_ref(index) {
value.to_string()
} else {
String::from("")
}
}
but
error[E0599]: `mysql::Value` doesn't implement `std::fmt::Display`

Your value variable is of type mysql::Value, which is an Enum type.
As it doesn't implement Display, you probably want to write a conversion to String manually.
For enums, this usually involves a match:
use mysql::Value;
fn as_string(mut row: mysql::Row, index: usize) -> String {
if let Some(value) = row.as_ref(index) {
match value {
Value::NULL => String::from(""),
Value::Bytes(v) => String::from_utf8_lossy(v.as_slice()).into_owned(),
Value::Int(v) => format!("{v}"),
Value::UInt(v) => format!("{v}"),
Value::Float(v) => format!("{v}"),
Value::Double(v) => format!("{v}"),
Value::Date(year, month, day, hour, minutes, seconds, micro) => todo!(),
Value::Time(negative, days, hours, minutes, seconds, micro) => todo!(),
}
} else {
String::from("")
}
}
You should of course replace the todo!() statements with implementations for those specific types.
Note that you shouldn't actually handle the None case like this, because it indicates a programming error. It happens if you already moved the value out of Row before, not if your cell is empty.
So I would argue the cleanest way is to return an Option<String>, which simplifies this function even further:
use mysql::Value;
fn as_string(mut row: mysql::Row, index: usize) -> Option<String> {
row.as_ref(index).map(|value| match value {
Value::NULL => String::from(""),
Value::Bytes(v) => String::from_utf8_lossy(v.as_slice()).into_owned(),
Value::Int(v) => format!("{v}"),
Value::UInt(v) => format!("{v}"),
Value::Float(v) => format!("{v}"),
Value::Double(v) => format!("{v}"),
Value::Date(year, month, day, hour, minutes, seconds, micro) => todo!(),
Value::Time(negative, days, hours, minutes, seconds, micro) => todo!(),
})
}

Related

How to infer other library error in result type

Im new to rust
consider this following code
fn my_function(text: &str) -> Result<String, _WHAT_SHOULD_I_USE_HERE_> {
let word = OtherLib::text(&text)?;
...
Ok(word)
}
OtherLib::text has a return type of Result<String, anyhow::Error>
but my problem is rust force me to add return type on my_function
I am not using anyhow on my project
is there any way to solve this, aside/without installing anyhow. And is there any easy way to auto complete this on vscode
what i expected
fn my_function(text: &str) -> Result<String, _JUST_INFER_IT_> {
and the caller of my function will get
Result<String, Error1 | Error2>
btw using _ is not working for me
fn my_function(text: &str) -> Result<String, _> {
// the placeholder `_` is not allowed within types on item signatures for return types
Part 2
I think rust don't have a union😅
so base on following the OtherLib::text, I come up with the following imaginary type
imaginary type: Result<String, ErrorKindEnum1 | ErrorKindEnum2 | Error>
current type : Result<String, Error>
where | is union type and Error at the end is just a subset/value/kind of ErrorKindEnum3, example ErrorKindEnum3::Error1
my new problem is how I can match it like, because vscode dosent give me any intellisense
match value {
ErrorKindEnum1::Error1 => todo!(),
ErrorKindEnum1::Error2 => todo!(),
ErrorKindEnum2::Error1 => todo!(),
...
ErrorKindEnum3::Error1 => todo!(), // this is okay
ErrorKindEnum3::Error2 => todo!(), // this should error. Not possible
}
as much as possible without type casting, or hardcoding type😅
Part 3
enum MyError {
A, B, C
}
fn greet () -> MyError {
if ... {
return MyError::A;
}
if ... {
return MyError::B;
}
}
fn main() {
match greet() {
MyError:A => todo!(),
MyError:B => todo!(),
MyError:C => todo!(), // rust cant tell me this is impossible?
}
}

Rust hdf5 crate: reading a scalar dataset of unknown type

Given an hdf5 Dataset, there is the is_scalar method to check if it is a scalar.
However, when I read that scalar, I need to specify the type I wish to read that scalar into as in the code below.
let ds: Dataset = group.handler
.dataset(dataset_name.as_ref())
.unwrap();
if ds.is_scalar() {
let x: hdf5::types::VarLenUnicode = ds.read_scalar();
}
In this example above I specified that I wish to read the scalar into the hdf5::types::VarLenUnicode type.
This works fine when I know precisely what type to expect.
In some other circumstances however, I do not have the type information of the hdf5 Dataset in advance.
Depending on the datatype, I wish to process the Dataset differently. Is there a way of checking the datatype of the scalar before reading it?
What would be an idiomatic way of reading an hdf5 Dataset that could contain either a string or a float?
Similarly, is it possible to read and cast the hdf5 dataset into a string even if it contains a float?
Here is a working solution that starts with the to_descriptor() method, eggyal posted on comments.
After getting the TypeDescriptor value, we need to handle every possible case (the Rust way).
match ds_type.to_descriptor().unwrap() {
hdf5::types::TypeDescriptor::Float(_) => {
self.show_dataset::<f64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::VarLenUnicode => {
self.show_dataset::<hdf5::types::VarLenUnicode>(
&ds,
dataset,
ctx,
&mut is_open,
);
}
hdf5::types::TypeDescriptor::Integer(_) => {
self.show_dataset::<i64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Unsigned(_) => {
self.show_dataset::<u64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Boolean => {
self.show_dataset::<bool>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Enum(_) => todo!(),
hdf5::types::TypeDescriptor::Compound(_) => todo!(),
hdf5::types::TypeDescriptor::FixedArray(_, _) => todo!(),
hdf5::types::TypeDescriptor::FixedAscii(_) => todo!(),
hdf5::types::TypeDescriptor::FixedUnicode(_) => todo!(),
hdf5::types::TypeDescriptor::VarLenArray(_) => todo!(),
hdf5::types::TypeDescriptor::VarLenAscii => {
self.show_dataset::<hdf5::types::VarLenAscii>(
&ds,
dataset,
ctx,
&mut is_open,
);
}
}
Later in the processing, in case of a scalar I just had to display the contents of the scalar types via the std::fmt::Display. I used generic types there to avoid code duplication in processing different types.
In the case of a non-scalar (vector), I used read_raw to load it.
fn show_dataset<T: hdf5::H5Type + std::fmt::Display>(
&mut self,
ds: &hdf5::Dataset,
dataset: &str,
ctx: &egui::Context,
is_open: &mut bool,
) {
if ds.is_scalar() {
let x_data: T = ds.read_scalar().unwrap();
Window::new(dataset.to_owned())
.open(is_open)
.vscroll(true)
.resizable(true)
.default_height(300.0)
.show(ctx, |ui| {
ui.label(format!("{}", x_data));
});
} else {
let x_data: Vec<T> = ds.read_raw().unwrap();
let mut table_box = Box::<super::table::TableWindow<T>>::default();
table_box.set_name(dataset.to_owned());
table_box.set_data(x_data);
table_box.show(ctx, is_open);
}
}
There is a caveat in this solution though.
As you probably have already noticed, these types below are not handled. In my application, those types are not needed to be handled but in general I do not know how these types could possibly be handled.
hdf5::types::TypeDescriptor::FixedArray(_, _) => todo!(),
hdf5::types::TypeDescriptor::FixedAscii(_) => todo!(),
hdf5::types::TypeDescriptor::FixedUnicode(_) => todo!(),

Bind variable to literal in Rust pattern matching

I have a state machine written in Rust which needs to perform the same action for two states.
Both states are variants of an enum but contain a different number of elements.
match self.state {
RunState::ACCUMULATE(byte, count) | RunState::ESCAPE(count) => todo!(),
_ => todo!()
}
The example is invalid source code because byte is not bound in all patterns.
This could be solved by binding byte to a literal zero in the second pattern but i don't know how to archive that.
I`am currently matching both patterns separately which leads to code duplication which i would like to avoid.
Thank you for your attention.
Patterns are designed to match by structure and bind variables based on the value being matched. It is not designed to introduce arbitrary bindings. You should use separate match arms and perhaps use a helper function if you're concerned about duplication:
match self.state {
RunState::ACCUMULATE(byte, count) => helper(byte, count),
RunState::ESCAPE(count) => helper(0, count),
...
}
Or you can introduce a function for your enum that returns the needed values like:
impl RunState {
fn to_parts(&self) -> (u8, usize) { // or Option<(u8, usize)> if its not applicable to all
match self.state {
RunState::ACCUMULATE(byte, count) => (byte, count),
RunState::ESCAPE(count) => (0, count),
...
}
}
}
You can solve your issue by not binding byte in any branch:
match self.state {
RunState::ACCUMULATE(_, count) | RunState::ESCAPE(count) => todo!(),
_ => todo!()
}
If you need byte in the ACCUMULATE case, then the code isn't strictly speaking the same for both, but this can be accomplished with an extra step to extract byte:
match self.state {
RunState::ACCUMULATE(_, count) | RunState::ESCAPE(count) => {
let byte = if let RunState::ACCUMULATE (byte, _) = self.state { byte } else { 0 };
todo!()
},
_ => todo!()
}

How can I use `syn::parse::Parse` (or more generally, `ParseBuffer`) from a context where all I have is a `syn::buffer::Cursor`?

I'm working on a proc_macro2/syn macro, and I've been using Cursor to do low-level parsing of something... Rust-like. But deep in my grammar, I need to parse a syn::Type. As far as I know, the only really good way to do this is to use the impl syn::parse::Parse for syn::Type.
So what I really would like to find is a nice way to write a function of signature
fn parse_generic<T: Parse>(c: Cursor) -> Option<(T, Cursor)>;
My question then is what is the best (simplest, least problematic) way to implement a function of this type?
Here is the best I've come up with so far:
fn parse_generic<T: Parse>(mut c: Cursor) -> Option<(T, Cursor)> {
match T::parse.parse2(c.token_stream()) {
Ok(t) => Some((t, Cursor::empty())), // because parse2 checks for end-of-stream!
Err(e) => {
// OK, because parse2 checks for end-of-stream, let's chop
// the input at the position of the error and try again (!).
let mut collected = Vec::new();
let upto = e.span().start();
while !c.eof() && c.span().start() != upto {
let (tt, next) = c.token_tree().unwrap();
collected.push(tt);
c = next;
}
match T::parse.parse2(collected.into_iter().collect()) {
Ok(t) => Some((t, c)),
Err(_) => None,
}
}
}
}
It's not disastrous, but it's not ideal either.

Calling function recursively on all fields, and subfields in procmacro

I have a derive style procedural macro, where i would like to calculate the potential maximum length of the serialized version of a struct. For example, given the struct TestStruct below, i would like to call some function with all the fields to calculate the worst case length.
#[derive(MyLengthProcMacro)]
struct TestStruct {
f1: u32,
f2: i64,
f3: SomeOtherStruct
}
For primitives this could look something like:
fn get_string_length(ty: &Type) -> usize {
let type_string = quote! { #ty }.to_string();
match type_string.replace(" ", "").as_str() {
"str" => panic!("String slices must be annotated with a length using #[at_arg()]"),
"tuple" => panic!("Tuples are not supported!"),
"char" => "a".len(),
"bool" => "false".len(),
"isize" => format!("{:?}", std::isize::MAX).len(),
"usize" => format!("{:?}", std::usize::MAX).len(),
"u8" => format!("{:?}", std::u8::MAX).len(),
"u16" => format!("{:?}", std::u16::MAX).len(),
"u32" => format!("{:?}", std::u32::MAX).len(),
"u64" => format!("{:?}", std::u64::MAX).len(),
"u128" => format!("{:?}", std::u128::MAX).len(),
"i8" => format!("{:?}", std::i8::MIN).len(),
"i16" => format!("{:?}", std::i16::MIN).len(),
"i32" => format!("{:?}", std::i32::MIN).len(),
"i64" => format!("{:?}", std::i64::MIN).len(),
"i128" => format!("{:?}", std::i128::MIN).len(),
"f32" => format!("{:?}", std::f32::MIN).len(),
"f64" => format!("{:?}", std::f64::MIN).len(),
_ => {
// println!("Unexpected type: {:?}", type_string);
0
}
}
}
The problem i am asking here is regarding any non-primitive fields, eg. f3: SomeOtherStruct. Is there a way to access the fields of fields, in a proc-macro?
No.
Macros are expanded before that kind of analysis is done, so the compiler has no idea what SomeOtherStruct is at that point.
However, this is not how you should implement that macro! Your way doesn't allow the user to use type aliases.
What you should do is simply use your trait recursively and use sum the <T as MyLength>::my_length() where T is the type of the field for each field.
They manually implement your trait for the primitive types.

Resources