Rust tonic and prost_types conversion - rust

I'm using tonic framework, a rust grpc server implementation. In the generated rust code from the proto file, I have a struct which has a field:
#[prost(message, optional, tag="3")]
pub data: ::core::option::Option<::prost_types::Value>,
generated from a protobuff field:
google.protobuf.Value data = 3;
I can't seem to find a way to init data which is type prost_types::Value by converting a struct I have. I'm doing something like:
prost_types::Value::try_from(myOwnsStructVar)
But it does not work. Anyone have used prost_types lib before and know how to encode/convert to prost_types::Value
myOwnsStructVar is a type struct. I need to convert it to prost_types::Struct So then I can do:
prost_types::value::Kind::StructValue(myOwnsStructVarAfterConversiontToProstStruct)

Just from looking at the docs, we can see that Value is a struct with a single public field kind which is of type Option<Kind>. The docs say that if this field is None then that indicates an error. If you look at the docs for Kind, then it's apparent this is where the actual data is stored. So if you want to initialize something of type Value then you'd want to do something like the following, substituting in the appropriate variant of Kind for your use case:
Value {
kind: Some(Kind::NumberValue(10.0f64))
}
The reason that your try_from solution didn't work is because there are no TryFrom implementations for Value other than the default blanket implementation.

Related

Dealing with `Options` and defaults when parsing in TOML structs with Rust+Serde

I have been working on configuration parsing code and wondered if you could help me to pick the best types for this code.
I am trying to parse the following TOML:
[default]
a=10
b="abc"
[section1]
a = 78
[section2]
b="xyz"
The types of keys are the same in each section and each field follows the chain of defaults: sectionX.value => default.value => default value hardcoded in Rust via x.value.or(default.value).or(Some(...) for each field.
The most straightforward way to declare it in Rust (including serde attributes)
struct Section{
a: Option<usize>,
b: Option<String>,
}
The problem is that I want to parse all defaults first, and then use a fully materialized struct with no unassigned values in my code.
struct Section{
a: usize,
b: String,
}
I can use the following approaches:
Use original Section struct and always to unwrap/expect because I "know" the defaults have been assigned in the config parsing code. I make a mistake, I can catch panic and that does not look tidy. I'd like to leverage more help from the compiler.
Use the second Section struct (the one that has no Options). I can assign defaults via Serde annotations, but then I am loosing the signal that something was unspecified and needs a default from another level.
Declare both variants of the struct. This is the most verbose variant and I will look even more verbose when I grow 20+ fields or embedded structs in the config.
Generated Solution 3 via macros or some clever typing. Is there a crate for this? Maybe Section could have some generic type that can be Option in one place, but then "newtype" wrapper with a single value somewhere else?
Something else?
Some of the solutions above would work alright, but maybe there is a known elegant solution.

Make a one to one mapping from string to enum variant without using a match statement

I'm writing code to parse HTTP requests. I'd rather keep some things like request methods and response codes as enums because of their exhaustibility.
But it also means that for each of those enums I would have to make a From<String> implementation. The obvious way to do it is to match against a plethora of constant strings. That seems like a lot of almost identical code which I would want to factor out.
Someone suggested I use a macro to do it, but my knowledge of rust macros is limited so it made me question some things:
How can I ensure the argument is of type &str or String? Macros can take expressions, but I don't want to use type_name and panic if it doesn't match as it seems to be a very dirty fix.
How can I convert a string to a token stream? So far I've seen that the proc_macro crate offers that functionality, but is it possible to do with simple declarative macro?
Is it possible to achieve one to one mapping by any other means? I hoped I could pre-initialize enum variants with some known values like in Java.
You really want to use a library for this. You can write the macro yourself, but someone else has already made a battle-tested version of what you're trying to do.
Use strum's EnumString derive:
In Cargo.toml:
[dependencies]
strum = "0.24"
strum_macros = "0.24"
In your source code: (eg main.rs)
use std::str::FromStr;
use strum_macros::EnumString;
#[derive(Debug, EnumString)]
enum MyEnum {
Foo,
Bar,
Baz,
}
fn main() {
dbg!(MyEnum::from_str("Foo").unwrap());
}
Gives you
[src/main.rs:12] MyEnum::from_str("Foo").unwrap() = Foo
For more details see The documentation for the FromString derive and strum's readme.

How can I copy the fields of another structure?

Is there any crate or functionality that allows me to copy the fields from another structure?
Crate A
struct Product {
name: String,
sku: String,
amount: i32,
}
Crate B
#[derive(copy_fields_from = "a::Product", InputObject)]
struct ProductApi {}
I have to expose several objects from another crate in an API that uses
"#[derive(InputObject)]". For that, I have to duplicate all the structures of the other structure. Is it possible to copy the fields of another structure? Perhaps using hypothetical syntax such as #[derive(copy_fields_from ="a::Product")].
No, there is no way of doing this cleanly.
If you felt you had to do this, you'd need to write a build script that:
Located the source code of the target crate.
Parsed the source code using a crate like syn.
Located the types in question.
Output them again.
See also:
How do I apply a macro attribute to a function defined in a separate module?
Add Serialize attribute to type from third-party lib
Is it possible for one struct to extend an existing struct, keeping all the fields?
For your specific case, I'd advocate implementing whatever trait(s) by hand.

What is the difference between using a type as a different name and a type alias?

What is the difference between
use hyper::status::StatusCode as Error;
and
type Error = hyper::status::StatusCode;
Are the any more differences between them except that type can be also pub type? What are the benefits between using one or another?
In case of simple types, like in your example, there doesn't seem to be any semantic difference. Moreover, there is a direct analogue with use to pub type, it's pub use:
// will be available to other modules
pub use hyper::status::StatusCode as Error;
However, there are differences in more complex cases. For example, you can define generic type aliases or aliases for specialized generic types:
type Result<T> = ::std::result::Result<T, MyError>;
type OptionI32 = Option<i32>;
The general idea is that you usually use type aliases because they are more powerful and suggest the intent more clearly, like with Result, and you use use .. as .. when you only want to import that specific name but it conflicts with something which is already in the current namespace:
use std::io::Read as StdRead;
trait Read: StdRead { ... }
Note that using path-qualified identifiers should be preferred to use renaming. The above is better written as
use std::io;
trait Read: io::Read { ... }
(unless Read methods are used for some concrete type in the same file, of course).
Using use .. as .. as a substitute for type (in case where it is possible) is uncommon and I think it should be avoided.

Optional function argument that is specified as a trait instead of a concrete type

I have been watching Rust for the past few months but I just started into an actual project. I am not sure if the terminology in the title is correct. Please let me know how it can be corrected.
I am writing a rust wrapper around the ENet library (http://enet.bespin.org). My goal is to keep the rust API as similar to the C API as possible except to refactor functions that take C style handle pointers into member functions of structure objects. I want to keep the API similar so that the official C documentation will apply equally well to the rust wrapper.
ENet exposes a single function to create either a client host or a server host. When creating a server you pass a pointer to an IP Address structure to the function. When creating a client you pass NULL.
I am trying to emulate that behavior using the ToSocketAddr trait and Option but I am running into problems using them in conjunction.
This is a reduced example of what I am trying to do:
use std::io::net::ip::ToSocketAddr;
fn create_host<A: ToSocketAddr>(addr: Option<A>) {
match addr {
Some(a) => println!("Address is {}. Return a server host object.",a.to_socket_addr()),
None => println!("no address... Return a client.")
};
}
fn main() {
create_host(Some("localhost:12345"));
create_host(None);
}
The first call to create_host() works like a charm. The second call however will not compile.
Rustc returns
error: unable to infer enough type information about `_`; type annotations required
I am guessing that error is occurring because None doesn't provide any resolution to the generic A. I tried the following but this doesn't work either because ToSocketAddr does not implement the trait core::kinds::Sized.
fn create_host(addr: Option<ToSocketAddr>) {
...
}
Is there a way I can do this or do I need to take a different approach?
fn main() {
create_host(Some("localhost:12345"));
create_host(None::<&str>);
}
I've chosen &str here as it is the same type as on the first call, so that the compiler wouldn't generate another monomorphized version of the generic function. You could choose any type that implements ToSocketAddr.

Resources