diff --git a/sdk/rust/CHANGELOG.md b/sdk/rust/CHANGELOG.md index 14fa644d138e074851b6884a28fc6186faa47f3b..8b465ca8c5aa31c393d7fb84aab5df330884ff3d 100644 --- a/sdk/rust/CHANGELOG.md +++ b/sdk/rust/CHANGELOG.md @@ -13,11 +13,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed -- Nothing. +- Add `types::Narith`, which wraps a `BigUint`. +- Deprecate `types::Mutez`. It is left as a type-alias to `types::Narith`. + *NB* The internally wrapped type is changed from `BigInt` to `BigUint` as a result. +- Add `#[encoding]` attribute support for enum fields, in addition to struct fields. ### Fixed -- Nothing. +- Fix `short_dynamic` function in `encoding` - was incorrectly using `dynamic` internally. ### Security diff --git a/sdk/rust/encoding-derive/src/bin.rs b/sdk/rust/encoding-derive/src/bin.rs index 075f6a22638e8abd2ee0299eb4eae5350120ac9a..768c53149a5deb69fba8684e89f82740043cad80 100644 --- a/sdk/rust/encoding-derive/src/bin.rs +++ b/sdk/rust/encoding-derive/src/bin.rs @@ -50,7 +50,7 @@ fn generate_bin_write(encoding: &Encoding) -> TokenStream { generate_dynamic_bin_write(size, encoding, *span) } Encoding::Zarith(span) => quote_spanned!(*span=> tezos_data_encoding::enc::zarith), - Encoding::MuTez(span) => quote_spanned!(*span=> tezos_data_encoding::enc::mutez), + Encoding::Narith(span) => quote_spanned!(*span=> tezos_data_encoding::enc::narith), } } diff --git a/sdk/rust/encoding-derive/src/enc.rs b/sdk/rust/encoding-derive/src/enc.rs index fc2f139a4606c890aa7ffbfef7aa0bd3dede8f22..fb851db2cc671adc975bed3341084d77be0925c8 100644 --- a/sdk/rust/encoding-derive/src/enc.rs +++ b/sdk/rust/encoding-derive/src/enc.rs @@ -46,8 +46,8 @@ pub(crate) fn generate_encoding(encoding: &Encoding) -> TokenStream { Encoding::Zarith(span) => { quote_spanned!(*span=> tezos_data_encoding::encoding::Encoding::Z) } - Encoding::MuTez(span) => { - quote_spanned!(*span=> tezos_data_encoding::encoding::Encoding::Mutez) + Encoding::Narith(span) => { + quote_spanned!(*span=> tezos_data_encoding::encoding::Encoding::N) } } } diff --git a/sdk/rust/encoding-derive/src/encoding.rs b/sdk/rust/encoding-derive/src/encoding.rs index f52f1be7a32244d9aaaa72bea1539695ce2c0565..298e0a62b3901c8d276468d21ba30c86bacb6b28 100644 --- a/sdk/rust/encoding-derive/src/encoding.rs +++ b/sdk/rust/encoding-derive/src/encoding.rs @@ -67,7 +67,7 @@ pub enum Encoding<'a> { Bytes(Span), Path(&'a syn::Path), Zarith(Span), - MuTez(Span), + Narith(Span), String(Option, Span), diff --git a/sdk/rust/encoding-derive/src/make.rs b/sdk/rust/encoding-derive/src/make.rs index e1bc66caa1b54067614683ceaead803362a012b9..c48f80ea9022f598baf23823b78f94b4c1dcb628 100644 --- a/sdk/rust/encoding-derive/src/make.rs +++ b/sdk/rust/encoding-derive/src/make.rs @@ -187,8 +187,10 @@ fn get_basic_encoding_from_meta<'a>( Encoding::String(string.param, string.span) } else if let Some(zarith) = get_attribute_no_param(meta, &symbol::Z_ARITH)? { Encoding::Zarith(zarith.span) + } else if let Some(mutez) = get_attribute_no_param(meta, &symbol::N_ARITH)? { + Encoding::Narith(mutez.span) } else if let Some(mutez) = get_attribute_no_param(meta, &symbol::MU_TEZ)? { - Encoding::MuTez(mutez.span) + Encoding::Narith(mutez.span) } else if let Some(builtin) = get_attribute_with_param(meta, &symbol::BUILTIN, Some(&symbol::KIND), true)? { @@ -488,10 +490,7 @@ fn make_tag<'a>( } syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { let ty = &fields.unnamed.first().unwrap().ty; - match ty { - syn::Type::Path(type_path) => Encoding::Path(&type_path.path), - _ => return Err(error_spanned(ty, "Unsupported type for enum variant")), - } + make_type_encoding(ty, meta)? } syn::Fields::Unnamed(fields) => { return Err(error_spanned(fields, "Only single field is supported")) diff --git a/sdk/rust/encoding-derive/src/nom.rs b/sdk/rust/encoding-derive/src/nom.rs index 0e75fa53b89ca56fba63cada4321851ccfd48557..76724f031f3364210ff5b368979ef64d0d34eddc 100644 --- a/sdk/rust/encoding-derive/src/nom.rs +++ b/sdk/rust/encoding-derive/src/nom.rs @@ -59,7 +59,7 @@ fn generate_nom_read(encoding: &Encoding) -> TokenStream { Encoding::ShortDynamic(encoding, span) => generate_short_dynamic_nom_read(encoding, *span), Encoding::Dynamic(size, encoding, span) => generate_dynamic_nom_read(size, encoding, *span), Encoding::Zarith(span) => quote_spanned!(*span=> tezos_data_encoding::nom::zarith), - Encoding::MuTez(span) => quote_spanned!(*span=> tezos_data_encoding::nom::mutez), + Encoding::Narith(span) => quote_spanned!(*span=> tezos_data_encoding::nom::narith), } } diff --git a/sdk/rust/encoding-derive/src/symbol.rs b/sdk/rust/encoding-derive/src/symbol.rs index 9285d71ad8d9ed091608f9badd93b171792eb733..ee248fdda1565aecd21fd7711eaf1e3c9ad40d51 100644 --- a/sdk/rust/encoding-derive/src/symbol.rs +++ b/sdk/rust/encoding-derive/src/symbol.rs @@ -68,6 +68,7 @@ pub const IGNORE_UNKNOWN: Symbol = Symbol("ignore_unknown"); pub const TAG: Symbol = Symbol("tag"); pub const Z_ARITH: Symbol = Symbol("zarith"); +pub const N_ARITH: Symbol = Symbol("narith"); pub const MU_TEZ: Symbol = Symbol("mutez"); pub const RESERVE: Symbol = Symbol("reserve"); diff --git a/sdk/rust/encoding/src/enc.rs b/sdk/rust/encoding/src/enc.rs index 2f4f0078346b40f6029a4e1696c4bb9f9dbb1851..958008dd12fbad399c17d5f5b50d722b7c0be3a0 100644 --- a/sdk/rust/encoding/src/enc.rs +++ b/sdk/rust/encoding/src/enc.rs @@ -6,7 +6,7 @@ use std::convert::TryFrom; use std::fmt; use crate::bit_utils::BitReverse; -use crate::types::{Mutez, Zarith}; +use crate::types::{Narith, Zarith}; use num_bigint::BigUint; pub use tezos_data_encoding_derive::BinWriter; @@ -318,9 +318,9 @@ mod integers { pub use integers::*; -impl BinWriter for Mutez { +impl BinWriter for Narith { fn bin_write(&self, out: &mut Vec) -> BinResult { - n_bignum(self.0.magnitude(), out) + n_bignum(&self.0, out) } } @@ -543,7 +543,7 @@ mod test { } #[test] - fn mutez() { + fn narith() { let data = [ ("0", "00"), ("1", "01"), @@ -561,12 +561,11 @@ mod test { ("10001", "818004"), ]; - use super::{BinWriter, Mutez}; - use num_traits::FromPrimitive; + use super::{BinWriter, Narith}; for (hex, enc) in data { - let num = num_bigint::BigInt::from_u64(u64::from_str_radix(hex, 16).unwrap()).unwrap(); - let num = Mutez(num); + let num: num_bigint::BigUint = u64::from_str_radix(hex, 16).unwrap().into(); + let num = Narith(num); let mut bytes = vec![]; num.bin_write(&mut bytes).unwrap(); assert_eq!(enc, hex::encode(bytes)); diff --git a/sdk/rust/encoding/src/encoding.rs b/sdk/rust/encoding/src/encoding.rs index f41001a773b946df4865273966f31d8f00b05ab1..35e8df52416d449b25205fa0045500ba0461a828 100644 --- a/sdk/rust/encoding/src/encoding.rs +++ b/sdk/rust/encoding/src/encoding.rs @@ -142,7 +142,7 @@ pub enum Encoding { /// Big number /// Almost identical to [Encoding::Z], but does not contain the sign bit in the second most /// significant bit of the first byte - Mutez, + N, /// Encoding of floating point number (encoded as a floating point number in JSON and a double in binary). Float, /// Float with bounds in a given range. Both bounds are inclusive. @@ -231,7 +231,7 @@ impl Encoding { Encoding::List(Box::new(encoding)) } - /// Utility function to construct [Encoding::List] without the need + /// Utility function to construct [Encoding::BoundedList] without the need /// to manually create new [Box]. #[inline] pub fn bounded_list(max: usize, encoding: Encoding) -> Encoding { @@ -245,7 +245,7 @@ impl Encoding { Encoding::Sized(bytes_sz, Box::new(encoding)) } - /// Utility function to construct [Encoding::Sized] without the need + /// Utility function to construct [Encoding::Bounded] without the need /// to manually create new [Box]. #[inline] pub fn bounded(max: usize, encoding: Encoding) -> Encoding { @@ -263,7 +263,7 @@ impl Encoding { /// to manually create new [Box]. #[inline] pub fn short_dynamic(encoding: Encoding) -> Encoding { - Encoding::Dynamic(Box::new(encoding)) + Encoding::ShortDynamic(Box::new(encoding)) } /// Utility function to construct [Encoding::Dynamic] without the need @@ -273,7 +273,7 @@ impl Encoding { Encoding::Dynamic(Box::new(encoding)) } - /// Utility function to construct [Encoding::Dynamic] without the need + /// Utility function to construct [Encoding::BoundedDynamic] without the need /// to manually create new [Box]. #[inline] pub fn bounded_dynamic(max: usize, encoding: Encoding) -> Encoding { @@ -311,3 +311,34 @@ macro_rules! has_encoding { } }; } + +#[cfg(test)] +mod tests { + use crate as tezos_data_encoding; + use tezos_data_encoding_derive::{BinWriter, NomReader}; + + #[derive(Debug, PartialEq, BinWriter, NomReader)] + struct Bytes { + #[encoding(short_dynamic, list)] + data: Vec, + } + + #[test] + fn short_dynamic() { + let test = Bytes { + data: vec![1_u8, 2_u8, 3_u8], + }; + let mut output = Vec::new(); + crate::enc::BinWriter::bin_write(&test, &mut output) + .expect("BinWriting should have succeed"); + + // Verify that the size of the encoded data is a short (one byte) + assert_eq!(output, vec![3_u8, 1_u8, 2_u8, 3_u8]); + + let (rem, decoded_test) = + crate::nom::NomReader::nom_read(&output).expect("NomReading should have succeed"); + assert!(rem.is_empty()); + + assert_eq!(test, decoded_test); + } +} diff --git a/sdk/rust/encoding/src/lib.rs b/sdk/rust/encoding/src/lib.rs index 163bb5d9de152c3af908353267ec9b77fff9b0ee..a6327a263ba61db15e8179e20a03e0412b867e29 100644 --- a/sdk/rust/encoding/src/lib.rs +++ b/sdk/rust/encoding/src/lib.rs @@ -47,6 +47,41 @@ //! # assert!(_remaining_input.is_empty()); //! # assert_eq!(outer, result); //! ``` +//! Derivation is also supported for rust enum with one unnamed field. +//! +//! Let's create encoding for a simple enum that holds a String or a Vec +//! ```rust +//! use tezos_data_encoding::nom::NomReader; +//! use tezos_data_encoding::enc::BinWriter; +//! use tezos_data_encoding::encoding::HasEncoding; +//! +//! #[derive(Debug, PartialEq, HasEncoding, NomReader, BinWriter)] +//! enum Message { +//! Readable(String), +//! Bytes(Vec), +//! } +//! +//! # let message_1 = Message::Readable(String::from("Hello World !")); +//! # let message_2 = Message::Bytes(vec![1_u8; 10_usize]); +//! # +//! # let mut encoded_1 = Vec::new(); +//! # message_1.bin_write(&mut encoded_1).expect("encoding works"); +//! # +//! # let (_remaining_input_1, result_1) = Message::nom_read(&encoded_1) +//! # .expect("decoding works"); +//! # +//! # assert!(_remaining_input_1.is_empty()); +//! # assert_eq!(message_1, result_1); +//! +//! # let mut encoded_2 = Vec::new(); +//! # message_2.bin_write(&mut encoded_2).expect("encoding works"); +//! # +//! # let (_remaining_input_2, result_2) = Message::nom_read(&encoded_2) +//! # .expect("decoding works"); +//! # +//! # assert!(_remaining_input_2.is_empty()); +//! # assert_eq!(message_2, result_2); +//! ``` mod bit_utils; pub mod types; diff --git a/sdk/rust/encoding/src/nom.rs b/sdk/rust/encoding/src/nom.rs index 9abfa7ec3a23d9cf5436d89b25f2bf36769feb1f..7bfd016c18491dcff501c199a9a619eae49cde5d 100644 --- a/sdk/rust/encoding/src/nom.rs +++ b/sdk/rust/encoding/src/nom.rs @@ -18,7 +18,7 @@ use nom::{ use num_bigint::{BigInt, BigUint, Sign}; pub use tezos_data_encoding_derive::NomReader; -use crate::types::{Mutez, Zarith}; +use crate::types::{Narith, Zarith}; use self::error::{BoundedEncodingKind, DecodeError, DecodeErrorKind}; @@ -225,11 +225,9 @@ impl NomReader<'_> for Zarith { } } -impl NomReader<'_> for Mutez { +impl NomReader<'_> for Narith { fn nom_read(bytes: &[u8]) -> NomResult { - map(n_bignum, |big_uint| { - BigInt::from_biguint(Sign::Plus, big_uint).into() - })(bytes) + map(n_bignum, |big_uint| big_uint.into())(bytes) } } diff --git a/sdk/rust/encoding/src/types.rs b/sdk/rust/encoding/src/types.rs index d12f19233d2fc8056bc991fb7e3b7875f341fd10..ecd2250692d2b87224e6bc3616931dba70fe6f3f 100644 --- a/sdk/rust/encoding/src/types.rs +++ b/sdk/rust/encoding/src/types.rs @@ -12,7 +12,6 @@ use crate::has_encoding; use crate::nom::NomReader; use hex::FromHexError; -use num_bigint::Sign; use serde::{Deserialize, Serialize}; /// This is a wrapper for [num_bigint::BigInt] type. @@ -86,30 +85,30 @@ impl From<&Zarith> for BigInt { has_encoding!(Zarith, ZARITH_ENCODING, { Encoding::Z }); /// Mutez number -#[derive(Clone, Debug)] -pub struct Mutez(pub num_bigint::BigInt); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Narith(pub num_bigint::BigUint); -impl<'de> Deserialize<'de> for Mutez { +#[deprecated = "Mutez has been replaced by Narith, which has identical semantics for encoding & decoding"] +pub type Mutez = Narith; + +impl<'de> Deserialize<'de> for Narith { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { if deserializer.is_human_readable() { let string: String = serde::Deserialize::deserialize(deserializer)?; - let big_int: num_bigint::BigInt = string + let big_uint: num_bigint::BigUint = string .parse() .map_err(|err| serde::de::Error::custom(format!("cannot parse big int: {err}")))?; - if big_int.sign() == Sign::Minus { - return Err(serde::de::Error::custom("negative number for natural")); - } - Ok(Self(big_int)) + Ok(Self(big_uint)) } else { Ok(Self(serde::Deserialize::deserialize(deserializer)?)) } } } -impl Serialize for Mutez { +impl Serialize for Narith { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -123,43 +122,37 @@ impl Serialize for Mutez { } } -impl From for Mutez { - fn from(from: num_bigint::BigInt) -> Self { - Mutez(from) +impl From for Narith { + fn from(from: num_bigint::BigUint) -> Self { + Narith(from) } } -impl From for num_bigint::BigInt { - fn from(from: Mutez) -> Self { +impl From for num_bigint::BigUint { + fn from(from: Narith) -> Self { from.0 } } -impl From<&num_bigint::BigInt> for Mutez { - fn from(from: &num_bigint::BigInt) -> Self { - Mutez(from.clone()) +impl From<&num_bigint::BigUint> for Narith { + fn from(from: &num_bigint::BigUint) -> Self { + Narith(from.clone()) } } -impl From<&Mutez> for num_bigint::BigInt { - fn from(from: &Mutez) -> Self { +impl From<&Narith> for num_bigint::BigUint { + fn from(from: &Narith) -> Self { from.0.clone() } } -impl From for BigInt { - fn from(source: Mutez) -> Self { - Self(source.0) - } -} - -impl From<&Mutez> for BigInt { - fn from(source: &Mutez) -> Self { - Self(source.0.clone()) +impl From for Narith { + fn from(value: u64) -> Self { + Narith(value.into()) } } -has_encoding!(Mutez, MUTEZ_ENCODING, { Encoding::Mutez }); +has_encoding!(Narith, NARITH_ENCODING, { Encoding::N }); #[derive(Clone, PartialEq, Eq)] pub struct SizedBytes(pub [u8; SIZE]);