mirror of https://git.sr.ht/~stygianentity/bincode
Removed a panic in the derive/src/generate module, moved it to derive/src/derive_* instead
This commit is contained in:
parent
baad206c6c
commit
435e030182
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue