How can I pass data to a protobuf oneof in tonic?
I couldn't find any instruction or example in the docs.
Tonic should generate an enum and corresponding type for each oneof variant. You'll have to match on that.
I'm assuming tonic = "0.4.3" and prost = "0.7.0" or higher for this answer. Let's use the following .proto definition as an example:
syntax = "proto3";
package stack_overflow;
service StackOverflow {
rpc Question (HelpRequest) returns (HelpResponse);
}
message HelpRequest {
oneof foo {
FroozleType froozle = 1;
FrobnikType frobnik = 2;
}
}
message FroozleType {
int32 value = 1;
}
message FrobnikType {}
message HelpResponse {
oneof bar {
QuxType qux = 1;
BazType baz = 2;
}
}
message QuxType {
int32 answer = 1;
}
message BazType {
string comment = 1;
}
When built, this generates the following types and traits. For the service:
stack_overflow_server::StackOverflow: the server trait
For the requests:
HelpRequest: the struct for the request message
help_request::Foo: an enum for the oneof foo in the request having an Froozle and a Frobnik variant
FroozleType: the struct of the FroozleType message
FrobnikType: the struct of the FrobnikType message
For the replies:
HelpResponse: the struct for the response message
help_response::Bar: an enum for the oneof bar in the response having an Qux and a Baz variant
QuxType: the struct of the QuxType message
BazType: the struct of the BazType message
For example, the HelpRequest struct and help_request::Foo enum are defined as such:
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HelpRequest {
#[prost(oneof = "help_request::Foo", tags = "1, 2")]
pub foo: ::core::option::Option<help_request::Foo>,
}
/// Nested message and enum types in `HelpRequest`.
pub mod help_request {
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Foo {
#[prost(message, tag = "1")]
Froozle(super::FroozleType),
#[prost(message, tag = "2")]
Frobnik(super::FrobnikType),
}
}
Sticking it all together, an example implementation of the above service could look like this:
use tonic::{Request, Response, Status};
mod grpc {
tonic::include_proto!("stack_overflow");
}
#[derive(Debug)]
pub struct StackOverflowService {}
#[tonic::async_trait]
impl grpc::stack_overflow_server::StackOverflow for StackOverflowService {
async fn question(
&self,
request: Request<grpc::HelpRequest>,
) -> Result<Response<grpc::HelpResponse>, Status> {
let request = request.into_inner();
let bar = match request.foo {
Some(grpc::help_request::Foo::Froozle(froozle)) => {
Some(grpc::help_response::Bar::Qux(grpc::QuxType {
answer: froozle.value + 42,
}))
}
Some(grpc::help_request::Foo::Frobnik(_)) => {
Some(grpc::help_response::Bar::Baz(grpc::BazType {
comment: "forty-two".into(),
}))
}
None => None,
};
let reply = grpc::HelpResponse { bar };
return Ok(Response::new(reply));
}
}
Related
I have an example Pest grammar:
WHITESPACE = _{ " " }
identifier = #{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
int_literal = { DECIMAL_NUMBER+ }
assignment_op = { ":=" }
formula = { (identifier ~ assignment_op ~ int_literal) | int_literal }
file = { formula ~ EOI }
and a pest-ast derives:
extern crate pest_derive;
extern crate from_pest;
extern crate pest_ast;
extern crate pest;
mod parser {
#[derive(Parser)]
#[grammar = "talk/formula.pest"]
pub struct Parser;
}
mod ast {
use super::parser::Rule;
use pest::Span;
fn span_into_str(span: Span) -> &str {
span.as_str()
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::int_literal))]
pub struct IntLiteral {
#[pest_ast(outer(with(span_into_str), with(str::parse::<i64>), with(Result::unwrap)))]
pub value: i64
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier {
#[pest_ast(inner(with(span_into_str), with(String::from)))]
pub value: String
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::assignment_op))]
pub struct AssignmentOp {
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::formula))]
pub enum Formula {
Assignment {
lvalue: Identifier,
a: AssignmentOp, // can I skip this?
rvalue: IntLiteral,
},
IntLiteral {
rvalue: IntLiteral,
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::ast::*;
use pest::Parser;
use from_pest::FromPest;
#[test]
fn test_formula0() {
let source = "a := 12";
let mut parse_tree = parser::Parser::parse(parser::Rule::formula, source).unwrap();
println!("parse tree = {:#?}", parse_tree);
let syntax_tree: Formula = Formula::from_pest(&mut parse_tree).expect("infallible");
println!("syntax tree = {:#?}", syntax_tree);
}
}
Running the test, I'm getting infallible: NoMatch panic.
Does pest-ast even support deriving enum variants with fields?
Can I match enum variant to a parenthesed () group of terminals?
Can I skip some terminals? I don't exactly need to know := was used if I get an AssignmentExpression { lvalue, rvalue } in the end.
I found an example in pest-ast issue #8. Grammar rules:
seq = { a ~ b ~ c }
choice = { a | b | c }
compund_seq = { a ~ (b | c) }
compound_choice = { (a ~ b) | (b ~ c) }
assign = { (a|b|c) ~ "=" ~ number }
assigns = { (assign ~ ",")* ~ assign ~ ","? }
correspond to code:
enum choice<'pest>{
struct _1(a<'pest>),
struct _2(b<'pest>),
struct _3(c<'pest>),
}
struct compound_seq<'pest>(
#[pest_ast(outer)] Span<'pest>,
a<'pest>,
enum _2 {
struct _1(b<'pest>),
struct _2(c<'pest>),
},
);
enum compound_choice<'pest>{
struct _1(
#[pest_ast(outer)] Span<'pest>,
a<'pest>,
b<'pest>,
),
struct _2(
#[pest_ast(outer)] Span<'pest>,
b<'pest>,
c<'pest>,
),
}
struct assign<'pest>(
#[pest_ast(outer)] Span<'pest>,
enum _1 {
struct _1(a<'pest>),
struct _2(b<'pest>),
struct _3(c<'pest>),
},
number<'pest>,
);
struct assigns<'pest>(
#[pest_ast(outer)] Span<'pest>,
Vec<struct _1(assign<'pest>)>,
assign<'pest>,
);
Once I knew I was on the right track, I figured out the error in my code, completely unrelated to the question asked. It was that Identifier rule should use outer span instead of inner.
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier {
#[pest_ast(outer(with(span_into_str), with(String::from)))]
pub value: String
}
The most useful debugging tool was to print the raw syntax tree the Identifier rule produced:
#[test]
fn test_identifier() {
let source = "foobar";
let mut parse_tree = parser::Parser::parse(parser::Rule::identifier, source).unwrap();
println!("parse tree = {:#?}", parse_tree);
let syntax_tree: Identifier = Identifier::from_pest(&mut parse_tree).expect("infallible");
println!("syntax tree = {:#?}", syntax_tree);
assert_eq!(syntax_tree.value, "foobar".to_string());
}
I also had to remove struct inside an enum to have Formula compile:
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::formula))]
pub enum Formula {
Assignment {
lvalue: Identifier,
// a: AssignmentOp,
rvalue: IntLiteral,
},
OrTest {
or_test: IntLiteral,
}
}
The answers to the questions:
Does pest-ast even support deriving enum variants with fields?
Yes, example above.
Can I match enum variant to a parenthesed () group of terminals?
No answer yet. This hasn't worked for me.
Can I skip some terminals? I don't exactly need to know := was used if I get an AssignmentExpression { lvalue, rvalue } in the end.
pest-ast works with the tree produced by pest. In order to skip something, make it a silent rule in the source grammar.
I want to iterate over over the fields of a struct and access its respective value for each iteration:
#[derive(Default, Debug)]
struct A {
foo: String,
bar: String,
baz: String
}
fn main() {
let fields = vec!["foo", "bar", "baz"];
let a: A = Default::default();
for field in fields {
let value = a[field] // this doesn't work
}
}
How can I access a field by variable?
Rust doesn't have any way of iterating directly over its fields. You should instead use a collection type such as Vec, array or one of the collections in std::collections if your data semantically represents a collection of some sort.
If you still feel the need to iterate over the fields, perhaps you need to re-consider your approach to your task and see if there isn't a more idiomatic/proper way to accomplish it
By using pattern matching, you can iterate over its fields.
#[derive(Default, Debug)]
struct A {
foo: String,
bar: String,
baz: String
}
impl A {
fn get(&self, field_string: &str) -> Result<&String, String> {
match field_string {
"foo" => Ok(&self.foo),
"bar" => Ok(&self.bar),
"baz" => Ok(&self.baz),
_ => Err(format!("invalid field name to get '{}'", field_string))
}
}
}
fn main() {
let fields = vec!["foo", "bar", "baz"];
let a = A {
foo: "value_of_foo".to_string(),
bar: "value_of_bar".to_string(),
baz: "value_of_baz".to_string()
};
for field in fields {
let value = a.get(field).unwrap();
println!("{:?}", value);
}
}
returns
"value_of_foo"
"value_of_bar"
"value_of_baz"
I am now writing a macro that implements such codes automatically for any struct, although there may be some bugs.
field_accessor (https://github.com/europeanplaice/field_accessor).
Cargo.toml
[dependencies]
field_accessor = "0"
use field_accessor::FieldAccessor;
#[derive(Default, Debug, FieldAccessor)]
struct A {
foo: String,
bar: String,
baz: String
}
fn main() {
let a = A {
foo: "value_of_foo".to_string(),
bar: "value_of_bar".to_string(),
baz: "value_of_baz".to_string()
};
for field in a.getstructinfo().field_names.iter() {
let value = a.get(field).unwrap();
println!("{:?}", value);
}
}
It also returns
"value_of_foo"
"value_of_bar"
"value_of_baz"
Based on the answer of sshashank124 I came to the conclusion that I should use an Hashmap instead of a struct:
fn main() {
let mut B = HashMap::new();
B.insert("foo", 1);
B.insert("bar", 2);
B.insert("baz", 3);
let fields = vec!["foo", "bar", "baz"];
for &field in &fields {
let value = B.get(field);
}
}
clap allows you to provide list of accepted values using possible_values like this.
let mode_vals = ["fast", "slow"];
.possible_values(&mode_vals)
How to do this with structopt?
Since structopt 0.3, you can use any method from App and Arg directly:
const MODE_VALS: &[&str] = &["fast", "slow"];
#[derive(StructOpt, Debug)]
struct Opt {
/// The velocity mode
#[structopt(short, long, possible_values(MODE_VALS))]
mode: String,
}
https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md#raw-attributes-are-removed-198-by-sphynx
clap’s possible_values is exposed as a field option, as shown in this structopt example:
//! How to use `arg_enum!` with `StructOpt`.
use clap::arg_enum;
use structopt::StructOpt;
arg_enum! {
#[derive(Debug)]
enum Baz {
Foo,
Bar,
FooBar
}
}
#[derive(StructOpt, Debug)]
struct Opt {
/// Important argument.
#[structopt(possible_values = &Baz::variants(), case_insensitive = true)]
i: Baz,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
Notably, this is making use of case_insensitive as well, to allow any case of those variants to be accepted.
If you want more granular control, you could omit case_insensitive and instead implement the variants yourself:
use structopt::StructOpt;
#[derive(Debug)]
enum Baz {
Foo,
Bar,
FooBar
}
impl Baz {
fn variants() -> [&'static str; 3] {
["foo", "bar", "foo-bar"]
}
}
#[derive(StructOpt, Debug)]
struct Opt {
/// Important argument.
#[structopt(possible_values = &Baz::variants())]
i: Baz,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}
Finally, you could also use a string array in the same manner.
How can I perform an equality comparison on substrate Hash trait?
Say I have the following code, with owned_vec contains a vector of Hash:
use support::{decl_module, decl_storage, decl_event, dispatch::Result,
StorageValue, StorageMap, ensure, traits::Currency };
use system::ensure_signed;
// this is needed when you want to use Vec and Box
use rstd::prelude::*;
use runtime_primitives::traits::{ As, Hash };
use parity_codec::{ Encode, Decode };
// Our own Cat struct
#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)]
pub struct Kitty<Hash, Balance> {
id: Hash,
name: Option<Vec<u8>>,
base_price: Balance, // when 0, it is not for sale
}
// This module's storage items.
decl_storage! {
trait Store for Module<T: Trait> as CatAuction {
Kitties get(kitties): map T::Hash => Kitty<T::Hash, T::Balance>;
KittyOwner get(owner_of): map T::Hash => Option<T::AccountId>;
OwnedKitties get(kitties_owned): map T::AccountId => Vec<T::Hash> = Vec::new();
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
pub fn transaction(origin, kitty_id: T::Hash) -> Result {
let sender = ensure_signed(origin)?;
let kitty_owner = Self::owner_of(kitty_id).ok_or("Kitty has no owner.")?;
let mut kitty = Self::kitties(kitty_id);
<OwnedKitties<T>>::mutate(kitty_owner, |owned_vec| {
let kitty_index = 0;
for (i, el) in owned_vec.iter().enumerate() {
// This is where the compilation error occurs!
if el != kitty.id { continue }
kitty_index = i;
}
owned_vec.remove(kitty_index);
});
}
}
}
It gives me compiler error that:
no implementation for `&<T as srml_system::Trait>::Hash == <T as srml_system::Trait>::Hash
help: the trait `core::cmp::PartialEq<<T as srml_system::Trait>::Hash>` is not implemented for `&<T as srml_system::Trait>::Hash`
help: consider adding a `where &<T as srml_system::Trait>::Hash: core::cmp::PartialEq<<T as srml_system::Trait>::Hash>` bound
Thank you!
p.s: Aware the tutorial says that looping through a vector is not encouraged in runtime module implementation.
I can do this:
enum MyEnum {
A(i32),
B(i32),
}
but not this:
enum MyEnum {
A(123), // 123 is a constant
B(456), // 456 is a constant
}
I can create the structures for A and B with a single field and then implement that field, but I think there might be an easier way. Is there any?
The best way to answer this is working out why you want constants in an enum: are you associating a value with each variant, or do you want each variant to be that value (like an enum in C or C++)?
For the first case, it probably makes more sense to just leave the enum variants with no data, and make a function:
enum MyEnum {
A,
B,
}
impl MyEnum {
fn value(&self) -> i32 {
match *self {
MyEnum::A => 123,
MyEnum::B => 456,
}
}
}
// call like some_myenum_value.value()
This approach can be applied many times, to associate many separate pieces of information with each variant, e.g. maybe you want a .name() -> &'static str method too. In the future, these functions can even be marked as const functions.
For the second case, you can assign explicit integer tag values, just like C/C++:
enum MyEnum {
A = 123,
B = 456,
}
This can be matched on in all the same ways, but can also be cast to an integer MyEnum::A as i32. (Note that computations like MyEnum::A | MyEnum::B are not automatically legal in Rust: enums have specific values, they're not bit-flags.)
Creating an "enum" with constant values, can be augmented using structs and associated constants.
This is similar to how crates like bitflags works and what it would generate.
Additionally, to prevent direct instantiation of MyEnum you can tag it with #[non_exhaustive].
#[non_exhaustive]
struct MyEnum;
impl MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
}
Then you simply use the "enum" as you otherwise would, by accessing MyEnum::A and MyEnum::B.
People looking at this may stumble upon the introduction and deprecation of FromPrimitive. A possible replacement which might also be useful here is enum_primitive. It allows you to use C-like enums and have them cast between numeric and logical representation:
#[macro_use]
extern crate enum_primitive;
extern crate num;
use num::FromPrimitive;
enum_from_primitive! {
#[derive(Debug, PartialEq)]
enum FooBar {
Foo = 17,
Bar = 42,
Baz,
}
}
fn main() {
assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
assert_eq!(FooBar::from_i32(91), None);
}
The enum-map crate provides the ability to assign a value to the enum record. What is more, you can use this macro with different value types.
use enum_map::{enum_map, Enum}; // 0.6.2
#[derive(Debug, Enum)]
enum Example {
A,
B,
C,
}
fn main() {
let mut map = enum_map! {
Example::A => 1,
Example::B => 2,
Example::C => 3,
};
map[Example::C] = 4;
assert_eq!(map[Example::A], 1);
for (key, &value) in &map {
println!("{:?} has {} as value.", key, value);
}
}
How about this?
enum MyEnum {
A = 123,
B = 456,
}
assert_eq!(MyEnum::A as i32, 123i32);
assert_eq!(MyEnum::B as i32, 456i32);
Just to give another idea.
#[allow(non_snake_case, non_upper_case_globals)]
mod MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
}
Then you can simply use it by accessing MyEnum::A and MyEnum::B or use MyEnum::*.
The advantage of doing this over associated constants is that you can even nest more enums.
#[allow(non_snake_case, non_upper_case_globals)]
mod MyEnum {
pub const A: i32 = 123;
pub const B: i32 = 456;
#[allow(non_snake_case, non_upper_case_globals)]
mod SubEnum {
pub const C: i32 = 789;
}
}
For my project I wrote a macro that automatically generates indexes and sets initial values.
#[macro_export]
macro_rules! cnum {
(#step $_idx:expr,) => {};
(#step $idx:expr, $head:ident, $($tail:ident,)*) => {
pub const $head: usize = $idx;
cnum!(#step $idx + 1usize, $($tail,)*);
};
($name:ident; $($n:ident),* $(,)* $({ $($i:item)* })?) => {
cnum!($name; 0usize; $($n),* $({ $($i)* })?);
};
($name:ident; $start:expr; $($n:ident),* $(,)* $({ $($i:item)* })?) => {
#[macro_use]
#[allow(dead_code, non_snake_case, non_upper_case_globals)]
pub mod $name {
use crate::cnum;
$($($i)*)?
cnum!(#step $start, $($n,)*);
}
};
}
Then you can use it like this,
cnum! { Tokens;
EOF,
WhiteSpace,
Identifier,
{
cnum! { Literal; 100;
Numeric,
String,
True,
False,
Nil,
}
cnum! { Keyword; 200;
For,
If,
Return,
}
}
}
I have created a crate enumeration just for this.
Example using my crate:
use enumeration::prelude::*;
enumerate!(MyEnum(u8; i32)
A = 123
B = 456
);
pub fn main() {
assert_eq!(*MyEnum::A.value(), 123);
assert_eq!(*MyEnum::B.value(), 456);
}