Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for repeated messages generation #24

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions actix-prost-build/src/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,32 @@ impl ConversionsGenerator {
) -> Option<ProcessedType> {
self.try_process_option(m_type, f, convert_field, res)
.or(self.try_process_map(m_type, f, convert_field, res))
.or(self.try_process_array(m_type, f, convert_field, res))
}

fn try_process_array(
&mut self,
m_type: MessageType,
f: &Field,
convert_field: Option<&ConvertFieldOptions>,
res: &mut Vec<TokenStream>,
) -> Option<ProcessedType> {
let name = f.ident.as_ref().unwrap();

let field_desc = convert_field.map(|cf| &cf.field)?;
let el_type = match (field_desc.cardinality(), field_desc.kind()) {
(Cardinality::Repeated, Kind::Message(m)) if !m.is_map_entry() => Some(m),
_ => None,
}?;
// TODO: Proto name might not be the same as Rust struct name
let rust_struct_name = self.messages.get(el_type.name())?.ident.clone();

let new_struct_name = self.build_internal_nested_struct(m_type, &rust_struct_name, res);

let convert = &self.convert_prefix;
let ty = quote!(::prost::alloc::vec::Vec<#new_struct_name>);
let conversion = quote!(#convert::try_convert(from.#name)?);
Some((ty, conversion))
}

fn try_process_option(
Expand Down
46 changes: 33 additions & 13 deletions tests/proto/conversions.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,54 @@ import "convert_options.proto";

option go_package = "github.com/blockscout/actix-prost/tests";

service ConversionsRPC { rpc ConvertRPC(ConversionsRequest) returns (ConversionsResponse); }

message Nested {
string address = 3 [ (convert_options.convert) = { type : "ethers::types::Address" } ];
service ConversionsRPC {
rpc ConvertRPC(ConversionsRequest) returns (ConversionsResponse);
}

message MapValue {
string address = 1 [ (convert_options.convert) = { type : "ethers::types::Address" } ];
string address = 1
[ (convert_options.convert) = {type : "ethers::types::Address"} ];
}

message OuterMessage {
string address = 3
[ (convert_options.convert) = {type : "ethers::types::Address"} ];
}

message RepeatedValue {
string address = 1
[ (convert_options.convert) = {type : "ethers::types::Address"} ];
}

message ConversionsRequest {
option (convert_options.extra_fields) = { name: "field1", type: "String" };
option (convert_options.extra_fields) = { name: "field2", type: "i32" };
option (convert_options.extra_fields) = {
name : "field1",
type : "String"
};
option (convert_options.extra_fields) = {
name : "field2",
type : "i32"
};
map<string, MapValue> map_field = 1;

string query = 2
[ (convert_options.convert) = {override : "Default::default()"} ];
repeated string addresses = 3 [ (convert_options.convert) = {
type : "std::collections::HashSet<ethers::types::Address>"
} ];

enum NestedEnum {
NESTED_OK = 0;
NESTED_ERROR = 1;
}

string query = 2 [ (convert_options.convert) = { override : "Default::default()" } ];
repeated string addresses = 3 [ (convert_options.convert) = { type : "std::collections::HashSet<ethers::types::Address>" } ];
NestedEnum nested_enum = 4;
Nested nested = 5 [ (convert_options.convert) = { required : true } ];
OuterMessage outer = 5 [ (convert_options.convert) = {required : true} ];
repeated RepeatedValue repeated = 6;
}

message ConversionsResponse {
string address = 1 [ (convert_options.convert) = { type : "ethers::types::Address" } ];
Nested nested = 2;
string address = 1
[ (convert_options.convert) = {type : "ethers::types::Address"} ];
OuterMessage outer = 2;
map<string, MapValue> map_field = 3;
}
16 changes: 11 additions & 5 deletions tests/src/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
proto::conversions::{
conversions_rpc_actix::route_conversions_rpc, conversions_rpc_server::ConversionsRpc,
ConversionsRequest, ConversionsRequestInternal, ConversionsResponse,
ConversionsResponseInternal, MapValue, Nested,
ConversionsResponseInternal, MapValue, OuterMessage, RepeatedValue,
},
test,
};
Expand All @@ -28,7 +28,7 @@ impl ConversionsRpc for ConversionsServer {

let internal_response = ConversionsResponseInternal {
address: Address::from_low_u64_be(0),
nested: Some(internal_request.nested),
outer: Some(internal_request.outer),
map_field: internal_request.map_field,
};

Expand Down Expand Up @@ -75,9 +75,12 @@ async fn conversions() {
query: "some_string".to_string(),
addresses: vec!["".to_string()],
nested_enum: 1,
nested: Some(Nested {
outer: Some(OuterMessage {
address: "".to_string(),
}),
repeated: vec![RepeatedValue {
address: "".to_string(),
}],
};

let res = send_post(&addr, "/conversions", serde_json::to_value(req).unwrap()).await;
Expand All @@ -100,14 +103,17 @@ async fn conversions() {
query: "some_string".to_string(),
addresses: vec![test_address.clone()],
nested_enum: 1,
nested: Some(Nested {
outer: Some(OuterMessage {
address: test_address.clone(),
}),
repeated: vec![RepeatedValue {
address: test_address.clone(),
}],
};

let res = send_post(&addr, "/conversions", serde_json::to_value(req).unwrap()).await;

let res: ConversionsResponse = serde_json::from_str(&res).unwrap();
assert_eq!(res.nested.unwrap().address, test_address);
assert_eq!(res.outer.unwrap().address, test_address);
assert_eq!(res.map_field.get("key").unwrap().address, test_address);
}
57 changes: 41 additions & 16 deletions tests/src/proto/conversions.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#[actix_prost_macros::serde]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Nested {
pub struct MapValue {
#[prost(string, tag = "1")]
pub address: ::prost::alloc::string::String,
}
#[actix_prost_macros::serde]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct OuterMessage {
#[prost(string, tag = "3")]
pub address: ::prost::alloc::string::String,
}
#[actix_prost_macros::serde]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct MapValue {
pub struct RepeatedValue {
#[prost(string, tag = "1")]
pub address: ::prost::alloc::string::String,
}
Expand All @@ -25,7 +32,9 @@ pub struct ConversionsRequest {
#[prost(enumeration = "conversions_request::NestedEnum", tag = "4")]
pub nested_enum: i32,
#[prost(message, optional, tag = "5")]
pub nested: ::core::option::Option<Nested>,
pub outer: ::core::option::Option<OuterMessage>,
#[prost(message, repeated, tag = "6")]
pub repeated: ::prost::alloc::vec::Vec<RepeatedValue>,
}
/// Nested message and enum types in `ConversionsRequest`.
pub mod conversions_request {
Expand Down Expand Up @@ -74,7 +83,7 @@ pub struct ConversionsResponse {
#[prost(string, tag = "1")]
pub address: ::prost::alloc::string::String,
#[prost(message, optional, tag = "2")]
pub nested: ::core::option::Option<Nested>,
pub outer: ::core::option::Option<OuterMessage>,
#[prost(map = "string, message", tag = "3")]
pub map_field: ::std::collections::HashMap<::prost::alloc::string::String, MapValue>,
}
Expand All @@ -99,7 +108,9 @@ pub mod conversions_rpc_actix {
#[prost(enumeration = "conversions_request::NestedEnum", tag = "4")]
pub nested_enum: i32,
#[prost(message, optional, tag = "5")]
pub nested: ::core::option::Option<Nested>,
pub outer: ::core::option::Option<OuterMessage>,
#[prost(message, repeated, tag = "6")]
pub repeated: ::prost::alloc::vec::Vec<RepeatedValue>,
}
async fn call_convert_rpc(
service: ::actix_web::web::Data<dyn ConversionsRpc + Sync + Send + 'static>,
Expand All @@ -121,7 +132,8 @@ pub mod conversions_rpc_actix {
query: json.query,
addresses: json.addresses,
nested_enum: json.nested_enum,
nested: json.nested,
outer: json.outer,
repeated: json.repeated,
};
let request = ::actix_prost::new_request(request, &http_request);
let response = service.convert_rpc(request).await?;
Expand All @@ -148,11 +160,22 @@ impl convert_trait::TryConvert<MapValue> for MapValueInternal {
}
}
#[derive(Debug)]
pub struct NestedInternal {
pub struct OuterMessageInternal {
pub address: ethers::types::Address,
}
impl convert_trait::TryConvert<OuterMessage> for OuterMessageInternal {
fn try_convert(from: OuterMessage) -> Result<Self, String> {
Ok(Self {
address: convert_trait::TryConvert::try_convert(from.address)?,
})
}
}
#[derive(Debug)]
pub struct RepeatedValueInternal {
pub address: ethers::types::Address,
}
impl convert_trait::TryConvert<Nested> for NestedInternal {
fn try_convert(from: Nested) -> Result<Self, String> {
impl convert_trait::TryConvert<RepeatedValue> for RepeatedValueInternal {
fn try_convert(from: RepeatedValue) -> Result<Self, String> {
Ok(Self {
address: convert_trait::TryConvert::try_convert(from.address)?,
})
Expand All @@ -167,7 +190,8 @@ pub struct ConversionsRequestInternal {
pub query: ::prost::alloc::string::String,
pub addresses: std::collections::HashSet<ethers::types::Address>,
pub nested_enum: conversions_request::NestedEnum,
pub nested: NestedInternal,
pub outer: OuterMessageInternal,
pub repeated: ::prost::alloc::vec::Vec<RepeatedValueInternal>,
pub field1: Option<String>,
pub field2: Option<i32>,
}
Expand All @@ -178,16 +202,17 @@ impl convert_trait::TryConvert<ConversionsRequest> for ConversionsRequestInterna
query: Default::default(),
addresses: convert_trait::TryConvert::try_convert(from.addresses)?,
nested_enum: conversions_request::NestedEnum::try_from(from.nested_enum)?,
nested: convert_trait::TryConvert::try_convert(
from.nested.ok_or("field nested is required")?,
outer: convert_trait::TryConvert::try_convert(
from.outer.ok_or("field outer is required")?,
)?,
repeated: convert_trait::TryConvert::try_convert(from.repeated)?,
field1: None,
field2: None,
})
}
}
impl convert_trait::TryConvert<NestedInternal> for Nested {
fn try_convert(from: NestedInternal) -> Result<Self, String> {
impl convert_trait::TryConvert<OuterMessageInternal> for OuterMessage {
fn try_convert(from: OuterMessageInternal) -> Result<Self, String> {
Ok(Self {
address: convert_trait::TryConvert::try_convert(from.address)?,
})
Expand All @@ -203,7 +228,7 @@ impl convert_trait::TryConvert<MapValueInternal> for MapValue {
#[derive(Debug)]
pub struct ConversionsResponseInternal {
pub address: ethers::types::Address,
pub nested: ::core::option::Option<NestedInternal>,
pub outer: ::core::option::Option<OuterMessageInternal>,
pub map_field: ::std::collections::HashMap<
::prost::alloc::string::String,
MapValueInternal,
Expand All @@ -213,7 +238,7 @@ impl convert_trait::TryConvert<ConversionsResponseInternal> for ConversionsRespo
fn try_convert(from: ConversionsResponseInternal) -> Result<Self, String> {
Ok(Self {
address: convert_trait::TryConvert::try_convert(from.address)?,
nested: convert_trait::TryConvert::try_convert(from.nested)?,
outer: convert_trait::TryConvert::try_convert(from.outer)?,
map_field: convert_trait::TryConvert::try_convert(from.map_field)?,
})
}
Expand Down