Removed a panic in the derive/src/generate module, moved it to derive/src/derive_* instead

This commit is contained in:
Victor Koenders 2021-10-19 10:22:19 +02:00
parent baad206c6c
commit 435e030182
6 changed files with 132 additions and 99 deletions

View File

@ -15,6 +15,7 @@ impl DeriveEnum {
generator
.impl_for("bincode::enc::Encode")
.unwrap()
.generate_fn("encode")
.with_generic("E", ["bincode::enc::Encoder"])
.with_self_arg(FnSelfArg::RefSelf)
@ -64,20 +65,23 @@ impl DeriveEnum {
body.push_parsed(format!(
"<u32 as bincode::enc::Encode>::encode(&{}, &mut encoder)?;",
variant_index
));
))
.unwrap();
// If we have any fields, encode them all one by one
for field_name in variant.fields.names() {
body.push_parsed(format!(
"bincode::enc::Encode::encode({}, &mut encoder)?;",
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
));
))
.unwrap();
}
});
match_body.punct(',');
}
});
fn_body.push_parsed("Ok(())");
});
fn_body.push_parsed("Ok(())").unwrap();
})
.unwrap();
Ok(())
}
@ -89,14 +93,15 @@ impl DeriveEnum {
// enum has a lifetime, implement BorrowDecode
generator.impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>")
.unwrap()
.generate_fn("borrow_decode")
.with_generic("D", ["bincode::de::BorrowDecoder<'__de>"])
.with_arg("mut decoder", "D")
.with_return_type("Result<Self, bincode::error::DecodeError>")
.body(|fn_builder| {
fn_builder
.push_parsed("let variant_index = <u32 as bincode::de::Decode>::decode(&mut decoder)?;");
fn_builder.push_parsed("match variant_index");
.push_parsed("let variant_index = <u32 as bincode::de::Decode>::decode(&mut decoder)?;").unwrap();
fn_builder.push_parsed("match variant_index").unwrap();
fn_builder.group(Delimiter::Brace, |variant_case| {
for (idx, variant) in variants.iter().enumerate() {
// idx => Ok(..)
@ -120,7 +125,7 @@ impl DeriveEnum {
variant_body.ident(field.unwrap_ident().clone());
}
variant_body.punct(':');
variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,");
variant_body.push_parsed("bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,").unwrap();
}
});
});
@ -132,59 +137,59 @@ impl DeriveEnum {
"variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})",
variants.len() - 1,
enum_name.to_string()
));
)).unwrap();
});
});
}).unwrap();
} else {
// enum has no lifetimes, implement Decode
generator.impl_for("bincode::de::Decode")
.unwrap()
.generate_fn("decode")
.with_generic("D", ["bincode::de::Decoder"])
.with_arg("mut decoder", "D")
.with_return_type("Result<Self, bincode::error::DecodeError>")
.body(|fn_builder| {
fn_builder
.push_parsed("let variant_index = <u32 as bincode::de::Decode>::decode(&mut decoder)?;").unwrap();
fn_builder.push_parsed("match variant_index").unwrap();
fn_builder.group(Delimiter::Brace, |variant_case| {
for (idx, variant) in variants.iter().enumerate() {
// idx => Ok(..)
variant_case.lit_u32(idx as u32);
variant_case.puncts("=>");
variant_case.ident_str("Ok");
variant_case.group(Delimiter::Parenthesis, |variant_case_body| {
// Self::Variant { }
// Self::Variant { 0: ..., 1: ... 2: ... },
// Self::Variant { a: ..., b: ... c: ... },
variant_case_body.ident_str("Self");
variant_case_body.puncts("::");
variant_case_body.ident(variant.name.clone());
fn_builder
.push_parsed("let variant_index = <u32 as bincode::de::Decode>::decode(&mut decoder)?;");
fn_builder.push_parsed("match variant_index");
fn_builder.group(Delimiter::Brace, |variant_case| {
for (idx, variant) in variants.iter().enumerate() {
// idx => Ok(..)
variant_case.lit_u32(idx as u32);
variant_case.puncts("=>");
variant_case.ident_str("Ok");
variant_case.group(Delimiter::Parenthesis, |variant_case_body| {
// Self::Variant { }
// Self::Variant { 0: ..., 1: ... 2: ... },
// Self::Variant { a: ..., b: ... c: ... },
variant_case_body.ident_str("Self");
variant_case_body.puncts("::");
variant_case_body.ident(variant.name.clone());
variant_case_body.group(Delimiter::Brace, |variant_body| {
let is_tuple = matches!(variant.fields, Fields::Tuple(_));
for (idx, field) in variant.fields.names().into_iter().enumerate() {
if is_tuple {
variant_body.lit_usize(idx);
} else {
variant_body.ident(field.unwrap_ident().clone());
variant_case_body.group(Delimiter::Brace, |variant_body| {
let is_tuple = matches!(variant.fields, Fields::Tuple(_));
for (idx, field) in variant.fields.names().into_iter().enumerate() {
if is_tuple {
variant_body.lit_usize(idx);
} else {
variant_body.ident(field.unwrap_ident().clone());
}
variant_body.punct(':');
variant_body.push_parsed("bincode::de::Decode::decode(&mut decoder)?,").unwrap();
}
variant_body.punct(':');
variant_body.push_parsed("bincode::de::Decode::decode(&mut decoder)?,");
}
});
});
});
variant_case.punct(',');
}
variant_case.punct(',');
}
// invalid idx
variant_case.push_parsed(format!(
"variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})",
variants.len() - 1,
enum_name.to_string()
));
});
});
// invalid idx
variant_case.push_parsed(format!(
"variant => return Err(bincode::error::DecodeError::UnexpectedVariant {{ min: 0, max: {}, found: variant, type_name: {:?} }})",
variants.len() - 1,
enum_name.to_string()
)).unwrap();
});
}).unwrap();
}
Ok(())

View File

@ -11,8 +11,9 @@ impl DeriveStruct {
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
let DeriveStruct { fields } = self;
let mut impl_for = generator.impl_for("bincode::enc::Encode");
impl_for
generator
.impl_for("bincode::enc::Encode")
.unwrap()
.generate_fn("encode")
.with_generic("E", ["bincode::enc::Encoder"])
.with_self_arg(crate::generate::FnSelfArg::RefSelf)
@ -20,13 +21,16 @@ impl DeriveStruct {
.with_return_type("Result<(), bincode::error::EncodeError>")
.body(|fn_body| {
for field in fields.names() {
fn_body.push_parsed(format!(
"bincode::enc::Encode::encode(&self.{}, &mut encoder)?;",
field.to_string()
));
fn_body
.push_parsed(format!(
"bincode::enc::Encode::encode(&self.{}, &mut encoder)?;",
field.to_string()
))
.unwrap();
}
fn_body.push_parsed("Ok(())");
});
fn_body.push_parsed("Ok(())").unwrap();
})
.unwrap();
Ok(())
}
@ -39,6 +43,7 @@ impl DeriveStruct {
generator
.impl_for_with_de_lifetime("bincode::de::BorrowDecode<'__de>")
.unwrap()
.generate_fn("borrow_decode")
.with_generic("D", ["bincode::de::BorrowDecoder<'__de>"])
.with_arg("mut decoder", "D")
@ -50,21 +55,25 @@ impl DeriveStruct {
ok_group.ident_str("Self");
ok_group.group(Delimiter::Brace, |struct_body| {
for field in fields.names() {
struct_body.push_parsed(format!(
struct_body
.push_parsed(format!(
"{}: bincode::de::BorrowDecode::borrow_decode(&mut decoder)?,",
field.to_string()
));
))
.unwrap();
}
});
});
});
})
.unwrap();
Ok(())
} else {
// struct has no lifetimes, implement Decode
let mut impl_for = generator.impl_for("bincode::de::Decode");
impl_for
generator
.impl_for("bincode::de::Decode")
.unwrap()
.generate_fn("decode")
.with_generic("D", ["bincode::de::Decoder"])
.with_arg("mut decoder", "D")
@ -82,14 +91,17 @@ impl DeriveStruct {
// ...
// }
for field in fields.names() {
struct_body.push_parsed(format!(
"{}: bincode::de::Decode::decode(&mut decoder)?,",
field.to_string()
));
struct_body
.push_parsed(format!(
"{}: bincode::de::Decode::decode(&mut decoder)?,",
field.to_string()
))
.unwrap();
}
});
});
});
})
.unwrap();
Ok(())
}

View File

@ -1,9 +1,9 @@
use super::{ImplFor, StreamBuilder};
use super::{stream_builder::PushParseError, ImplFor, StreamBuilder};
use crate::prelude::Delimiter;
/// A builder for functions.
pub struct FnBuilder<'a, 'b> {
generate: Option<&'b mut ImplFor<'a>>,
generate: &'b mut ImplFor<'a>,
name: String,
lifetime_and_generics: Vec<(String, Vec<String>)>,
@ -15,7 +15,7 @@ pub struct FnBuilder<'a, 'b> {
impl<'a, 'b> FnBuilder<'a, 'b> {
pub(super) fn new(generate: &'b mut ImplFor<'a>, name: impl Into<String>) -> Self {
Self {
generate: Some(generate),
generate,
name: name.into(),
lifetime_and_generics: Vec::new(),
self_arg: FnSelfArg::None,
@ -94,9 +94,9 @@ impl<'a, 'b> FnBuilder<'a, 'b> {
/// b.push_parsed("println!(\"hello world\");");
/// });
/// ```
pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) {
pub fn body(self, body_builder: impl FnOnce(&mut StreamBuilder)) -> Result<(), PushParseError> {
let FnBuilder {
mut generate,
generate,
name,
lifetime_and_generics,
self_arg,
@ -123,7 +123,7 @@ impl<'a, 'b> FnBuilder<'a, 'b> {
if !dependencies.is_empty() {
for (idx, dependency) in dependencies.into_iter().enumerate() {
builder.punct(if idx == 0 { ':' } else { '+' });
builder.push_parsed(&dependency);
builder.push_parsed(&dependency)?;
}
}
}
@ -140,22 +140,23 @@ impl<'a, 'b> FnBuilder<'a, 'b> {
if idx != 0 {
arg_stream.punct(',');
}
arg_stream.push_parsed(&arg_name);
arg_stream.push_parsed(&arg_name)?;
arg_stream.punct(':');
arg_stream.push_parsed(&arg_ty);
arg_stream.push_parsed(&arg_ty)?;
}
});
Ok(())
})?;
// Return type: `-> ResultType`
if let Some(return_type) = return_type {
builder.puncts("->");
builder.push_parsed(&return_type);
builder.push_parsed(&return_type)?;
}
let generator = generate.take().unwrap();
generate.group.append(builder);
generate.group.group(Delimiter::Brace, body_builder);
generator.group.append(builder);
generator.group.group(Delimiter::Brace, body_builder);
Ok(())
}
}

View File

@ -1,3 +1,4 @@
use super::stream_builder::PushParseError;
use super::{ImplFor, StreamBuilder};
use crate::parse::{GenericConstraints, Generics};
use crate::prelude::{Ident, TokenStream};
@ -30,12 +31,15 @@ impl Generator {
}
/// Generate an `for <trait_name> for <target_name>` implementation. See [ImplFor] for more information.
pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> {
pub fn impl_for<'a>(&'a mut self, trait_name: &str) -> Result<ImplFor<'a>, PushParseError> {
ImplFor::new(self, trait_name)
}
/// Generate an `for <'__de> <trait_name> for <target_name>` implementation. See [ImplFor] for more information.
pub fn impl_for_with_de_lifetime<'a>(&'a mut self, trait_name: &str) -> ImplFor<'a> {
pub fn impl_for_with_de_lifetime<'a>(
&'a mut self,
trait_name: &str,
) -> Result<ImplFor<'a>, PushParseError> {
ImplFor::new_with_de_lifetime(self, trait_name)
}

View File

@ -1,4 +1,4 @@
use super::{FnBuilder, Generator, StreamBuilder};
use super::{stream_builder::PushParseError, FnBuilder, Generator, StreamBuilder};
use crate::prelude::Delimiter;
#[must_use]
@ -8,14 +8,17 @@ pub struct ImplFor<'a> {
}
impl<'a> ImplFor<'a> {
pub(super) fn new(generator: &'a mut Generator, trait_name: &str) -> Self {
pub(super) fn new(
generator: &'a mut Generator,
trait_name: &str,
) -> Result<Self, PushParseError> {
let mut builder = StreamBuilder::new();
builder.ident_str("impl");
if let Some(generics) = &generator.generics {
builder.append(generics.impl_generics());
}
builder.push_parsed(trait_name);
builder.push_parsed(trait_name)?;
builder.ident_str("for");
builder.ident(generator.name.clone());
@ -28,10 +31,13 @@ impl<'a> ImplFor<'a> {
generator.stream.append(builder);
let group = StreamBuilder::new();
Self { generator, group }
Ok(Self { generator, group })
}
pub(super) fn new_with_de_lifetime(generator: &'a mut Generator, trait_name: &str) -> Self {
pub(super) fn new_with_de_lifetime(
generator: &'a mut Generator,
trait_name: &str,
) -> Result<Self, PushParseError> {
let mut builder = StreamBuilder::new();
builder.ident_str("impl");
@ -43,7 +49,7 @@ impl<'a> ImplFor<'a> {
builder.punct('>');
}
builder.push_parsed(trait_name);
builder.push_parsed(trait_name)?;
builder.ident_str("for");
builder.ident(generator.name.clone());
if let Some(generics) = &generator.generics {
@ -55,7 +61,7 @@ impl<'a> ImplFor<'a> {
generator.stream.append(builder);
let group = StreamBuilder::new();
Self { generator, group }
Ok(Self { generator, group })
}
/// Add a function to the trait implementation

View File

@ -1,5 +1,5 @@
use crate::prelude::{
Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
use std::str::FromStr;
@ -36,15 +36,13 @@ impl StreamBuilder {
/// Attempt to parse the given string as valid Rust code, and append the parsed result to the internal stream.
///
/// Currently panics if the string could not be parsed as valid Rust code.
pub fn push_parsed(&mut self, item: impl AsRef<str>) {
self.stream
.extend(TokenStream::from_str(item.as_ref()).unwrap_or_else(|e| {
panic!(
"Could not parse string as rust: {:?}\n{:?}",
item.as_ref(),
e
)
}));
pub fn push_parsed(&mut self, item: impl AsRef<str>) -> Result<(), PushParseError> {
let tokens = TokenStream::from_str(item.as_ref()).map_err(|e| PushParseError {
error: e,
code: item.as_ref().to_string(),
})?;
self.stream.extend(tokens);
Ok(())
}
/// Push a single ident to the stream. An ident is any worse that a code file may contain, e.g. `fn`, `struct`, `where`, names of functions and structs, etc.
@ -63,11 +61,12 @@ impl StreamBuilder {
/// Add a group. A group is any block surrounded by `{ .. }`, `[ .. ]` or `( .. )`.
///
/// `delim` indicates which group it is. The `inner` callback is used to fill the contents of the group.
pub fn group(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder)) {
pub fn group<T>(&mut self, delim: Delimiter, inner: impl FnOnce(&mut StreamBuilder) -> T) -> T {
let mut stream = StreamBuilder::new();
inner(&mut stream);
let result = inner(&mut stream);
self.stream
.extend([TokenTree::Group(Group::new(delim, stream.stream))]);
result
}
/// Add a single punctuation to the stream. Puncts are single-character tokens like `.`, `<`, `#`, etc
@ -149,3 +148,9 @@ impl StreamBuilder {
.collect();
}
}
#[derive(Debug)]
pub struct PushParseError {
pub error: LexError,
pub code: String,
}