Skip to content

Commit

Permalink
fix(pilota-build): indirect cycle (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
PureWhiteWu authored Oct 27, 2023
1 parent 392993b commit 72f6f5f
Show file tree
Hide file tree
Showing 18 changed files with 3,943 additions and 3,171 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pilota-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pilota-build"
version = "0.9.2"
version = "0.9.3"
edition = "2021"
description = "Compile thrift and protobuf idl into rust code at compile-time."
documentation = "https://docs.rs/pilota-build"
Expand Down
47 changes: 29 additions & 18 deletions pilota-build/src/codegen/thrift/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,36 @@ impl ThriftBackend {
decode: String,
decode_async: String,
) -> String {
let decode_async_fn = if self.cx().db.type_graph().is_cycled(def_id) {
format!(
r#"fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>> + Send + 'a>> {{
::std::boxed::Box::pin(async move {{
{decode_async}
}})
}}"#
)
} else {
format!(
r#"async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &mut T,
) -> ::std::result::Result<Self,::pilota::thrift::DecodeError> {{
// FIXME: here we will encounter problems when the type is indirect recursive
// such as `struct A { a: Vec<A> }`.
// Just use the boxed future for now.
// let decode_async_fn = if self.cx().db.type_graph().is_cycled(def_id) {
// format!(
// r#"fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
// protocol: &'a mut T,
// ) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output =
// ::std::result::Result<Self, ::pilota::thrift::DecodeError>> + Send +
// 'a>> {{ ::std::boxed::Box::pin(async move {{ {decode_async} }})
// }}"#
// )
// } else {
// format!(
// r#"async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
// protocol: &mut T,
// ) -> ::std::result::Result<Self,::pilota::thrift::DecodeError> {{
// {decode_async}
// }}"#
// )
// };
let decode_async_fn = format!(
r#"fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>> + Send + 'a>> {{
::std::boxed::Box::pin(async move {{
{decode_async}
}}"#
)
};
}})
}}"#
);
format! {r#"
impl ::pilota::thrift::Message for {name} {{
fn encode<T: ::pilota::thrift::TOutputProtocol>(
Expand Down
89 changes: 50 additions & 39 deletions pilota-build/test_data/must_gen_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,52 +76,63 @@ pub mod must_gen_items {
Ok(data)
}

async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &mut T,
) -> ::std::result::Result<Self, ::pilota::thrift::DecodeError> {
let mut a = None;
fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<
::std::boxed::Box<
dyn ::std::future::Future<
Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>,
> + Send
+ 'a,
>,
> {
::std::boxed::Box::pin(async move {
let mut a = None;

let mut __pilota_decoding_field_id = None;
let mut __pilota_decoding_field_id = None;

protocol.read_struct_begin().await?;
if let Err(err) = async {
loop {
let field_ident = protocol.read_field_begin().await?;
if field_ident.field_type == ::pilota::thrift::TType::Stop {
break;
} else {
}
__pilota_decoding_field_id = field_ident.id;
match field_ident.id {
Some(1) if field_ident.field_type == ::pilota::thrift::TType::I32 => {
a = Some(protocol.read_i32().await?);
protocol.read_struct_begin().await?;
if let Err(err) = async {
loop {
let field_ident = protocol.read_field_begin().await?;
if field_ident.field_type == ::pilota::thrift::TType::Stop {
break;
} else {
}
_ => {
protocol.skip(field_ident.field_type).await?;
__pilota_decoding_field_id = field_ident.id;
match field_ident.id {
Some(1)
if field_ident.field_type == ::pilota::thrift::TType::I32 =>
{
a = Some(protocol.read_i32().await?);
}
_ => {
protocol.skip(field_ident.field_type).await?;
}
}
}

protocol.read_field_end().await?;
}
Ok::<_, ::pilota::thrift::DecodeError>(())
}
.await
{
if let Some(field_id) = __pilota_decoding_field_id {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::WithContext(::std::boxed::Box::new(
err,
)),
format!("decode struct `A` field(#{}) failed", field_id),
));
} else {
return Err(err);
protocol.read_field_end().await?;
}
Ok::<_, ::pilota::thrift::DecodeError>(())
}
};
protocol.read_struct_end().await?;
.await
{
if let Some(field_id) = __pilota_decoding_field_id {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::WithContext(
::std::boxed::Box::new(err),
),
format!("decode struct `A` field(#{}) failed", field_id),
));
} else {
return Err(err);
}
};
protocol.read_struct_end().await?;

let data = Self { a };
Ok(data)
let data = Self { a };
Ok(data)
})
}

fn size<T: ::pilota::thrift::TLengthProtocol>(&self, protocol: &mut T) -> usize {
Expand Down
172 changes: 100 additions & 72 deletions pilota-build/test_data/plugin/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,71 +108,83 @@ pub mod serde {
Ok(data)
}

async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &mut T,
) -> ::std::result::Result<Self, ::pilota::thrift::DecodeError> {
let mut a = None;
let mut b = None;

let mut __pilota_decoding_field_id = None;

protocol.read_struct_begin().await?;
if let Err(err) = async {
loop {
let field_ident = protocol.read_field_begin().await?;
if field_ident.field_type == ::pilota::thrift::TType::Stop {
break;
} else {
}
__pilota_decoding_field_id = field_ident.id;
match field_ident.id {
Some(1)
if field_ident.field_type == ::pilota::thrift::TType::Binary =>
{
a = Some(protocol.read_faststr().await?);
}
Some(2) if field_ident.field_type == ::pilota::thrift::TType::I32 => {
b = Some(protocol.read_i32().await?);
fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<
::std::boxed::Box<
dyn ::std::future::Future<
Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>,
> + Send
+ 'a,
>,
> {
::std::boxed::Box::pin(async move {
let mut a = None;
let mut b = None;

let mut __pilota_decoding_field_id = None;

protocol.read_struct_begin().await?;
if let Err(err) = async {
loop {
let field_ident = protocol.read_field_begin().await?;
if field_ident.field_type == ::pilota::thrift::TType::Stop {
break;
} else {
}
_ => {
protocol.skip(field_ident.field_type).await?;
__pilota_decoding_field_id = field_ident.id;
match field_ident.id {
Some(1)
if field_ident.field_type
== ::pilota::thrift::TType::Binary =>
{
a = Some(protocol.read_faststr().await?);
}
Some(2)
if field_ident.field_type == ::pilota::thrift::TType::I32 =>
{
b = Some(protocol.read_i32().await?);
}
_ => {
protocol.skip(field_ident.field_type).await?;
}
}
}

protocol.read_field_end().await?;
protocol.read_field_end().await?;
}
Ok::<_, ::pilota::thrift::DecodeError>(())
}
Ok::<_, ::pilota::thrift::DecodeError>(())
}
.await
{
if let Some(field_id) = __pilota_decoding_field_id {
.await
{
if let Some(field_id) = __pilota_decoding_field_id {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::WithContext(
::std::boxed::Box::new(err),
),
format!("decode struct `A` field(#{}) failed", field_id),
));
} else {
return Err(err);
}
};
protocol.read_struct_end().await?;

let Some(a) = a else {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::WithContext(::std::boxed::Box::new(
err,
)),
format!("decode struct `A` field(#{}) failed", field_id),
::pilota::thrift::DecodeErrorKind::InvalidData,
"field a is required".to_string(),
));
} else {
return Err(err);
}
};
protocol.read_struct_end().await?;

let Some(a) = a else {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::InvalidData,
"field a is required".to_string(),
));
};
let Some(b) = b else {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::InvalidData,
"field b is required".to_string(),
));
};
};
let Some(b) = b else {
return Err(::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::InvalidData,
"field b is required".to_string(),
));
};

let data = Self { a, b };
Ok(data)
let data = Self { a, b };
Ok(data)
})
}

fn size<T: ::pilota::thrift::TLengthProtocol>(&self, protocol: &mut T) -> usize {
Expand Down Expand Up @@ -246,16 +258,25 @@ pub mod serde {
})?)
}

async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &mut T,
) -> ::std::result::Result<Self, ::pilota::thrift::DecodeError> {
let value = protocol.read_i32().await?;
Ok(::std::convert::TryFrom::try_from(value).map_err(|err| {
::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::InvalidData,
format!("invalid enum value for C, value: {}", value),
)
})?)
fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<
::std::boxed::Box<
dyn ::std::future::Future<
Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>,
> + Send
+ 'a,
>,
> {
::std::boxed::Box::pin(async move {
let value = protocol.read_i32().await?;
Ok(::std::convert::TryFrom::try_from(value).map_err(|err| {
::pilota::thrift::DecodeError::new(
::pilota::thrift::DecodeErrorKind::InvalidData,
format!("invalid enum value for C, value: {}", value),
)
})?)
})
}

fn size<T: ::pilota::thrift::TLengthProtocol>(&self, protocol: &mut T) -> usize {
Expand Down Expand Up @@ -311,10 +332,17 @@ pub mod serde {
Ok(B(protocol.read_i32()?))
}

async fn decode_async<T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &mut T,
) -> ::std::result::Result<Self, ::pilota::thrift::DecodeError> {
Ok(B(protocol.read_i32().await?))
fn decode_async<'a, T: ::pilota::thrift::TAsyncInputProtocol>(
protocol: &'a mut T,
) -> ::std::pin::Pin<
::std::boxed::Box<
dyn ::std::future::Future<
Output = ::std::result::Result<Self, ::pilota::thrift::DecodeError>,
> + Send
+ 'a,
>,
> {
::std::boxed::Box::pin(async move { Ok(B(protocol.read_i32().await?)) })
}

fn size<T: ::pilota::thrift::TLengthProtocol>(&self, protocol: &mut T) -> usize {
Expand Down
Loading

0 comments on commit 72f6f5f

Please sign in to comment.