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

tezos-encoding + derive: keep track of lifetime in NomReader #46

Merged
merged 1 commit into from
Dec 8, 2023
Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Changed

- Nothing.
- `tezos_data_encoding`: The `NomReader` trait is now explicitly
parameterized by the lifetime of the input byte slice.

### Deprecated

Expand Down
14 changes: 11 additions & 3 deletions tezos-encoding-derive/src/nom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use once_cell::sync::Lazy as SyncLazy;
use crate::encoding::*;
use proc_macro2::{Span, TokenStream};
emturner marked this conversation as resolved.
Show resolved Hide resolved
use quote::{format_ident, quote, quote_spanned};
use syn::parse_quote;
use syn::spanned::Spanned;

const NOM_TUPLE_MAX: usize = 26;
Expand All @@ -18,14 +19,21 @@ pub fn generate_nom_read_for_data(
) -> TokenStream {
let name = data.name;
let nom_read = generate_nom_read(&data.encoding);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// We want to derive NomReader<'a> for a fresh 'a. To do this we
// use a mix of the solutions proposed in
// https://github.com/dtolnay/syn/issues/90
let a: syn::GenericParam = parse_quote!('_a);
let mut extended_generics = generics.clone();
extended_generics.params.push(a.clone());
let (impl_generics, _, _) = extended_generics.split_for_impl();
let (_, ty_generics, where_clause) = generics.split_for_impl();
quote_spanned! {
data.name.span()=>
#[allow(unused_parens)]
#[allow(clippy::unnecessary_cast)]
#[allow(clippy::redundant_closure_call)]
impl #impl_generics tezos_data_encoding::nom::NomReader for #name #ty_generics #where_clause {
fn nom_read(bytes: &[u8]) -> tezos_data_encoding::nom::NomResult<Self> {
impl #impl_generics tezos_data_encoding::nom::NomReader<#a> for #name #ty_generics #where_clause {
fn nom_read(bytes: &#a [u8]) -> tezos_data_encoding::nom::NomResult<#a, Self> {
#nom_read(bytes)
}
}
Expand Down
2 changes: 1 addition & 1 deletion tezos-encoding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//!
//! #[derive(Debug, PartialEq, HasEncoding, NomReader, BinWriter)]
//! struct Outer<T>
//! where T: Debug + PartialEq + HasEncoding + NomReader + BinWriter {
//! where T: Debug + PartialEq + HasEncoding + for<'a> NomReader<'a> + BinWriter {
//! #[encoding(dynamic)]
//! dynamic_size: Vec<T>
//! }
Expand Down
10 changes: 5 additions & 5 deletions tezos-encoding/src/nom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,13 @@ pub type NomError<'a> = error::DecodeError<NomInput<'a>>;
pub type NomResult<'a, T> = nom::IResult<NomInput<'a>, T, NomError<'a>>;

/// Traits defining message decoding using `nom` primitives.
pub trait NomReader: Sized {
fn nom_read(input: &[u8]) -> NomResult<Self>;
pub trait NomReader<'a>: Sized {
fn nom_read(input: &'a [u8]) -> NomResult<'a, Self>;
}

macro_rules! hash_nom_reader {
($hash_name:ident) => {
impl NomReader for crypto::hash::$hash_name {
impl<'a> NomReader<'a> for crypto::hash::$hash_name {
#[inline(always)]
fn nom_read(input: &[u8]) -> NomResult<Self> {
map(take(Self::hash_size()), |bytes| {
Expand Down Expand Up @@ -270,13 +270,13 @@ hash_nom_reader!(BlsSignature);
hash_nom_reader!(NonceHash);
hash_nom_reader!(SmartRollupHash);

impl NomReader for Zarith {
impl<'a> NomReader<'a> for Zarith {
fn nom_read(bytes: &[u8]) -> NomResult<Self> {
map(z_bignum, |big_int| big_int.into())(bytes)
}
}

impl NomReader for Mutez {
impl<'a> NomReader<'a> for Mutez {
fn nom_read(bytes: &[u8]) -> NomResult<Self> {
map(n_bignum, |big_uint| {
BigInt::from_biguint(Sign::Plus, big_uint).into()
Expand Down
4 changes: 2 additions & 2 deletions tezos-encoding/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ impl<'de, const SIZE: usize> Deserialize<'de> for SizedBytes<SIZE> {
}
}

impl<const SIZE: usize> NomReader for SizedBytes<SIZE> {
impl<'a, const SIZE: usize> NomReader<'a> for SizedBytes<SIZE> {
fn nom_read(input: &[u8]) -> crate::nom::NomResult<Self> {
use crate::nom;
let (input, slice) = nom::sized(SIZE, nom::bytes)(input)?;
Expand Down Expand Up @@ -387,7 +387,7 @@ impl HasEncoding for Bytes {
}
}

impl NomReader for Bytes {
impl<'a> NomReader<'a> for Bytes {
fn nom_read(input: &[u8]) -> crate::nom::NomResult<Self> {
use crate::nom::bytes;
let (input, b) = bytes(input)?;
Expand Down