From 435e03018263a332435eb783a61291eb553f2829 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Tue, 19 Oct 2021 10:22:19 +0200 Subject: [PATCH] Removed a panic in the derive/src/generate module, moved it to derive/src/derive_* instead --- derive/src/derive_enum.rs | 99 ++++++++++++++------------- derive/src/derive_struct.rs | 48 ++++++++----- derive/src/generate/generate_fn.rs | 27 ++++---- derive/src/generate/generator.rs | 8 ++- derive/src/generate/impl_for.rs | 20 ++++-- derive/src/generate/stream_builder.rs | 29 ++++---- 6 files changed, 132 insertions(+), 99 deletions(-) diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index fe3270f..6ab9f30 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -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!( "::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") .body(|fn_builder| { fn_builder - .push_parsed("let variant_index = ::decode(&mut decoder)?;"); - fn_builder.push_parsed("match variant_index"); + .push_parsed("let variant_index = ::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") .body(|fn_builder| { + fn_builder + .push_parsed("let variant_index = ::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 = ::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(()) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index c71b9c8..8c08f56 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -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(()) } diff --git a/derive/src/generate/generate_fn.rs b/derive/src/generate/generate_fn.rs index ff44ede..f63a390 100644 --- a/derive/src/generate/generate_fn.rs +++ b/derive/src/generate/generate_fn.rs @@ -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)>, @@ -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) -> 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(()) } } diff --git a/derive/src/generate/generator.rs b/derive/src/generate/generator.rs index b330476..7cc0bc0 100644 --- a/derive/src/generate/generator.rs +++ b/derive/src/generate/generator.rs @@ -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 for ` 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, PushParseError> { ImplFor::new(self, trait_name) } /// Generate an `for <'__de> for ` 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, PushParseError> { ImplFor::new_with_de_lifetime(self, trait_name) } diff --git a/derive/src/generate/impl_for.rs b/derive/src/generate/impl_for.rs index 7652848..db2ddf4 100644 --- a/derive/src/generate/impl_for.rs +++ b/derive/src/generate/impl_for.rs @@ -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 { 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 { 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 diff --git a/derive/src/generate/stream_builder.rs b/derive/src/generate/stream_builder.rs index 3ee6566..3c44647 100644 --- a/derive/src/generate/stream_builder.rs +++ b/derive/src/generate/stream_builder.rs @@ -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) { - 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) -> 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(&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, +}