use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::{pair, preceded, tuple};
use tezos_data_encoding::enc::{self, BinResult, BinSerializer, BinWriter};
use tezos_data_encoding::encoding::{Encoding, HasEncoding};
use tezos_data_encoding::has_encoding;
use tezos_data_encoding::nom::{self as nom_read, NomInput, NomReader, NomResult};
use tezos_data_encoding::types::Zarith;
use std::fmt::Debug;
pub const MICHELINE_INT_TAG: u8 = 0;
pub const MICHELINE_STRING_TAG: u8 = 1;
pub const MICHELINE_SEQ_TAG: u8 = 2;
pub const MICHELINE_PRIM_NO_ARGS_NO_ANNOTS_TAG: u8 = 3;
pub const MICHELINE_PRIM_NO_ARGS_SOME_ANNOTS_TAG: u8 = 4;
pub const MICHELINE_PRIM_1_ARG_NO_ANNOTS_TAG: u8 = 5;
pub const MICHELINE_PRIM_1_ARG_SOME_ANNOTS_TAG: u8 = 6;
pub const MICHELINE_PRIM_2_ARGS_NO_ANNOTS_TAG: u8 = 7;
pub const MICHELINE_PRIM_2_ARGS_SOME_ANNOTS_TAG: u8 = 8;
pub const MICHELINE_PRIM_GENERIC_TAG: u8 = 9;
pub const MICHELINE_BYTES_TAG: u8 = 10;
#[derive(Debug, PartialEq, Eq)]
pub struct MichelineInt(pub Zarith);
#[derive(Debug, PartialEq, Eq)]
pub struct MichelineString(pub String);
#[derive(Debug, PartialEq, Eq)]
pub struct MichelineBytes(pub Vec<u8>);
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrimNoArgsNoAnnots<const PRIM_TAG: u8>;
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrimNoArgsSomeAnnots<const PRIM_TAG: u8> {
pub(crate) annots: String,
}
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrim1ArgNoAnnots<Arg, const PRIM_TAG: u8>
where
Arg: Debug + PartialEq + Eq,
{
pub(crate) arg: Arg,
}
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrim1ArgSomeAnnots<Arg, const PRIM_TAG: u8>
where
Arg: Debug + PartialEq + Eq,
{
pub(crate) arg: Arg,
pub(crate) annots: String,
}
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrim2ArgsNoAnnots<Arg1, Arg2, const PRIM_TAG: u8>
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
{
pub(crate) arg1: Arg1,
pub(crate) arg2: Arg2,
}
#[derive(Debug, PartialEq, Eq)]
pub struct MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, const PRIM_TAG: u8>
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
{
pub(crate) arg1: Arg1,
pub(crate) arg2: Arg2,
pub(crate) annots: String,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Node {
Int(Zarith),
String(String),
Bytes(Vec<u8>),
Seq(Vec<Node>),
Prim {
prim_tag: u8,
args: Vec<Node>,
annots: Option<String>,
},
}
impl From<MichelineInt> for Node {
fn from(i: MichelineInt) -> Self {
let MichelineInt(i) = i;
Node::Int(i)
}
}
impl From<MichelineString> for Node {
fn from(s: MichelineString) -> Self {
let MichelineString(s) = s;
Node::String(s)
}
}
impl From<MichelineBytes> for Node {
fn from(s: MichelineBytes) -> Self {
let MichelineBytes(s) = s;
Node::Bytes(s)
}
}
impl<const PRIM_TAG: u8> From<MichelinePrimNoArgsNoAnnots<PRIM_TAG>> for Node {
fn from(_: MichelinePrimNoArgsNoAnnots<PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![],
annots: None,
}
}
}
impl<const PRIM_TAG: u8> From<MichelinePrimNoArgsSomeAnnots<PRIM_TAG>> for Node {
fn from(a: MichelinePrimNoArgsSomeAnnots<PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![],
annots: Some(a.annots),
}
}
}
impl<Arg, const PRIM_TAG: u8> From<MichelinePrim1ArgNoAnnots<Arg, PRIM_TAG>> for Node
where
Arg: Debug + PartialEq + Eq,
Node: From<Arg>,
{
fn from(a: MichelinePrim1ArgNoAnnots<Arg, PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![a.arg.into()],
annots: None,
}
}
}
impl<Arg, const PRIM_TAG: u8> From<MichelinePrim1ArgSomeAnnots<Arg, PRIM_TAG>> for Node
where
Arg: Debug + PartialEq + Eq,
Node: From<Arg>,
{
fn from(a: MichelinePrim1ArgSomeAnnots<Arg, PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![a.arg.into()],
annots: Some(a.annots),
}
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8>
From<MichelinePrim2ArgsNoAnnots<Arg1, Arg2, PRIM_TAG>> for Node
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
Node: From<Arg1>,
Node: From<Arg2>,
{
fn from(a: MichelinePrim2ArgsNoAnnots<Arg1, Arg2, PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![a.arg1.into(), a.arg2.into()],
annots: None,
}
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8>
From<MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, PRIM_TAG>> for Node
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
Node: From<Arg1>,
Node: From<Arg2>,
{
fn from(a: MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, PRIM_TAG>) -> Self {
Node::Prim {
prim_tag: PRIM_TAG,
args: vec![a.arg1.into(), a.arg2.into()],
annots: Some(a.annots),
}
}
}
impl From<i32> for MichelineInt {
fn from(int: i32) -> Self {
MichelineInt(Zarith(int.into()))
}
}
impl From<i32> for Node {
fn from(int: i32) -> Self {
Node::Int(Zarith(int.into()))
}
}
has_encoding!(MichelineInt, MICHELINE_INT_ENCODING, { Encoding::Custom });
has_encoding!(MichelineString, MICHELINE_STRING_ENCODING, {
Encoding::Custom
});
has_encoding!(MichelineBytes, MICHELINE_BYTES_ENCODING, {
Encoding::Custom
});
impl<const PRIM_TAG: u8> HasEncoding for MichelinePrimNoArgsNoAnnots<PRIM_TAG> {
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl<const PRIM_TAG: u8> HasEncoding for MichelinePrimNoArgsSomeAnnots<PRIM_TAG> {
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl<Arg, const PRIM_TAG: u8> HasEncoding for MichelinePrim1ArgNoAnnots<Arg, PRIM_TAG>
where
Arg: Debug + PartialEq + Eq,
{
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl<Arg, const PRIM_TAG: u8> HasEncoding for MichelinePrim1ArgSomeAnnots<Arg, PRIM_TAG>
where
Arg: Debug + PartialEq + Eq,
{
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> HasEncoding
for MichelinePrim2ArgsNoAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
{
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> HasEncoding
for MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: Debug + PartialEq + Eq,
Arg2: Debug + PartialEq + Eq,
{
fn encoding() -> Encoding {
Encoding::Custom
}
}
impl NomReader for MichelineInt {
fn nom_read(input: &[u8]) -> NomResult<Self> {
map(nom_read_micheline_int, MichelineInt)(input)
}
}
impl NomReader for MichelineString {
fn nom_read(input: &[u8]) -> NomResult<Self> {
map(nom_read_micheline_string, MichelineString)(input)
}
}
impl NomReader for MichelineBytes {
fn nom_read(input: &[u8]) -> NomResult<Self> {
map(nom_read_micheline_bytes(nom_read::bytes), MichelineBytes)(input)
}
}
impl<const PRIM_TAG: u8> NomReader for MichelinePrimNoArgsNoAnnots<PRIM_TAG> {
fn nom_read(input: &[u8]) -> NomResult<Self> {
map(
tag([MICHELINE_PRIM_NO_ARGS_NO_ANNOTS_TAG, PRIM_TAG]),
|_prim| MichelinePrimNoArgsNoAnnots {},
)(input)
}
}
impl<const PRIM_TAG: u8> NomReader for MichelinePrimNoArgsSomeAnnots<PRIM_TAG> {
fn nom_read(input: &[u8]) -> NomResult<Self> {
let parse = preceded(
tag([MICHELINE_PRIM_NO_ARGS_SOME_ANNOTS_TAG, PRIM_TAG]),
nom_read::string,
);
map(parse, |annots| MichelinePrimNoArgsSomeAnnots { annots })(input)
}
}
impl<Arg, const PRIM_TAG: u8> NomReader for MichelinePrim1ArgNoAnnots<Arg, PRIM_TAG>
where
Arg: NomReader + Debug + PartialEq + Eq,
{
fn nom_read(input: &[u8]) -> NomResult<Self> {
let parse = preceded(
tag([MICHELINE_PRIM_1_ARG_NO_ANNOTS_TAG, PRIM_TAG]),
Arg::nom_read,
);
map(parse, |arg| MichelinePrim1ArgNoAnnots { arg })(input)
}
}
impl<Arg, const PRIM_TAG: u8> NomReader for MichelinePrim1ArgSomeAnnots<Arg, PRIM_TAG>
where
Arg: NomReader + Debug + PartialEq + Eq,
{
fn nom_read(input: &[u8]) -> NomResult<Self> {
let parse = preceded(
tag([MICHELINE_PRIM_1_ARG_SOME_ANNOTS_TAG, PRIM_TAG]),
pair(Arg::nom_read, nom_read::string),
);
map(parse, |(arg, annots)| MichelinePrim1ArgSomeAnnots {
arg,
annots,
})(input)
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> NomReader
for MichelinePrim2ArgsNoAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: NomReader + Debug + PartialEq + Eq,
Arg2: NomReader + Debug + PartialEq + Eq,
{
fn nom_read(input: &[u8]) -> NomResult<Self> {
let parse = preceded(
tag([MICHELINE_PRIM_2_ARGS_NO_ANNOTS_TAG, PRIM_TAG]),
pair(Arg1::nom_read, Arg2::nom_read),
);
map(parse, |(arg1, arg2)| MichelinePrim2ArgsNoAnnots {
arg1,
arg2,
})(input)
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> NomReader
for MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: NomReader + Debug + PartialEq + Eq,
Arg2: NomReader + Debug + PartialEq + Eq,
{
fn nom_read(input: &[u8]) -> NomResult<Self> {
let parse = preceded(
tag([MICHELINE_PRIM_2_ARGS_SOME_ANNOTS_TAG, PRIM_TAG]),
pair(Arg1::nom_read, pair(Arg2::nom_read, nom_read::string)),
);
map(parse, |(arg1, (arg2, annots))| {
MichelinePrim2ArgsSomeAnnots { arg1, arg2, annots }
})(input)
}
}
fn nom_read_app_aux<'a, T>(
micheline_prim_tag: u8,
next: impl FnMut(NomInput<'a>) -> NomResult<T>,
into: impl Fn((u8, T)) -> Node,
) -> impl FnMut(NomInput<'a>) -> NomResult<Node> {
use nom::number::complete::u8;
preceded(tag([micheline_prim_tag]), map(pair(u8, next), into))
}
impl Node {
fn nom_read_app(input: NomInput) -> NomResult<Node> {
use nom::branch::alt;
use nom::combinator::success;
use Node::Prim;
alt((
nom_read_app_aux(
MICHELINE_PRIM_NO_ARGS_NO_ANNOTS_TAG,
success(()),
|(prim_tag, ())| Prim {
prim_tag,
args: vec![],
annots: None,
},
),
nom_read_app_aux(
MICHELINE_PRIM_NO_ARGS_SOME_ANNOTS_TAG,
nom_read::string,
|(prim_tag, annots)| Prim {
prim_tag,
args: vec![],
annots: Some(annots),
},
),
nom_read_app_aux(
MICHELINE_PRIM_1_ARG_NO_ANNOTS_TAG,
Self::nom_read,
|(prim_tag, arg)| Prim {
prim_tag,
args: vec![arg],
annots: None,
},
),
nom_read_app_aux(
MICHELINE_PRIM_1_ARG_SOME_ANNOTS_TAG,
pair(Self::nom_read, nom_read::string),
|(prim_tag, (arg, annots))| Prim {
prim_tag,
args: vec![arg],
annots: Some(annots),
},
),
nom_read_app_aux(
MICHELINE_PRIM_2_ARGS_NO_ANNOTS_TAG,
pair(Self::nom_read, Self::nom_read),
|(prim_tag, (arg1, arg2))| Prim {
prim_tag,
args: vec![arg1, arg2],
annots: None,
},
),
nom_read_app_aux(
MICHELINE_PRIM_2_ARGS_SOME_ANNOTS_TAG,
tuple((Self::nom_read, Self::nom_read, nom_read::string)),
|(prim_tag, (arg1, arg2, annots))| Prim {
prim_tag,
args: vec![arg1, arg2],
annots: Some(annots),
},
),
nom_read_app_aux(
MICHELINE_PRIM_GENERIC_TAG,
pair(
nom_read::dynamic(nom_read::list(Node::nom_read)),
nom_read::string,
),
|(prim_tag, (args, annots))| Prim {
prim_tag,
args,
annots: Some(annots),
},
),
))(input)
}
fn nom_read_seq(input: NomInput) -> NomResult<Node> {
let parse = preceded(
tag([MICHELINE_SEQ_TAG]),
nom_read::dynamic(nom_read::list(Node::nom_read)),
);
map(parse, Node::Seq)(input)
}
}
impl NomReader for Node {
fn nom_read(input: &[u8]) -> NomResult<Self> {
nom::branch::alt((
map(nom_read_micheline_int, Node::Int),
map(nom_read_micheline_string, Node::String),
map(nom_read_micheline_bytes(nom_read::bytes), Node::Bytes),
Self::nom_read_seq,
Self::nom_read_app,
))(input)
}
}
impl BinWriter for MichelineInt {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
enc::put_byte(&MICHELINE_INT_TAG, output);
self.0.bin_write(output)
}
}
impl BinWriter for MichelineString {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
enc::put_byte(&MICHELINE_STRING_TAG, output);
enc::string(&self.0, output)
}
}
impl BinWriter for MichelineBytes {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_micheline_bytes(enc::bytes)(self.0.as_slice(), output)
}
}
impl<const PRIM_TAG: u8> BinWriter for MichelinePrimNoArgsNoAnnots<PRIM_TAG> {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_no_args_no_annots(PRIM_TAG, output)
}
}
impl<const PRIM_TAG: u8> BinWriter for MichelinePrimNoArgsSomeAnnots<PRIM_TAG> {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_no_args_some_annots(PRIM_TAG, &self.annots, output)
}
}
impl<Arg, const PRIM_TAG: u8> BinWriter for MichelinePrim1ArgNoAnnots<Arg, PRIM_TAG>
where
Arg: BinWriter + Debug + PartialEq + Eq,
{
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_1_arg_no_annots(PRIM_TAG, &self.arg, output)
}
}
impl<Arg, const PRIM_TAG: u8> BinWriter for MichelinePrim1ArgSomeAnnots<Arg, PRIM_TAG>
where
Arg: BinWriter + Debug + PartialEq + Eq,
{
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_1_arg_some_annots(PRIM_TAG, &self.arg, &self.annots, output)
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> BinWriter
for MichelinePrim2ArgsNoAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: BinWriter + Debug + PartialEq + Eq,
Arg2: BinWriter + Debug + PartialEq + Eq,
{
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_2_args_no_annots(PRIM_TAG, &self.arg1, &self.arg2, output)
}
}
impl<Arg1, Arg2, const PRIM_TAG: u8> BinWriter
for MichelinePrim2ArgsSomeAnnots<Arg1, Arg2, PRIM_TAG>
where
Arg1: BinWriter + Debug + PartialEq + Eq,
Arg2: BinWriter + Debug + PartialEq + Eq,
{
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
bin_write_prim_2_args_some_annots(
PRIM_TAG,
&self.arg1,
&self.arg2,
&self.annots,
output,
)
}
}
impl BinWriter for Node {
fn bin_write(&self, output: &mut Vec<u8>) -> BinResult {
match self {
Node::Int(i) => bin_write_micheline_int(i, output),
Node::String(s) => bin_write_micheline_string(&s, output),
Node::Bytes(s) => bin_write_micheline_bytes(enc::bytes)(s.as_slice(), output),
Node::Seq(args) => bin_write_micheline_seq(args, output),
Node::Prim {
prim_tag,
args,
annots,
} => match (args.as_slice(), annots.as_deref()) {
([], None) => bin_write_prim_no_args_no_annots(*prim_tag, output),
([], Some(annots)) => {
bin_write_prim_no_args_some_annots(*prim_tag, annots, output)
}
([arg], None) => bin_write_prim_1_arg_no_annots(*prim_tag, arg, output),
([arg], Some(annots)) => {
bin_write_prim_1_arg_some_annots(*prim_tag, arg, annots, output)
}
([arg0, arg1], None) => {
bin_write_prim_2_args_no_annots(*prim_tag, arg0, arg1, output)
}
([arg0, arg1], Some(annots)) => bin_write_prim_2_args_some_annots(
*prim_tag, arg0, arg1, annots, output,
),
(_, annots) => bin_write_prim_generic(
*prim_tag,
args,
annots.unwrap_or_default(),
output,
),
},
}
}
}
fn nom_read_tagged_micheline<'a, T: Clone, const TAG: u8>(
parser: impl FnMut(NomInput<'a>) -> NomResult<'a, T>,
) -> impl FnMut(NomInput<'a>) -> NomResult<'a, T> {
preceded(tag([TAG]), parser)
}
pub(crate) fn nom_read_micheline_bytes<'a, T: Clone>(
parser: impl FnMut(NomInput) -> NomResult<T>,
) -> impl FnMut(NomInput<'a>) -> NomResult<'a, T> {
nom_read_tagged_micheline::<_, { MICHELINE_BYTES_TAG }>(nom_read::dynamic(parser))
}
pub(crate) fn nom_read_micheline_string(input: NomInput) -> NomResult<String> {
nom_read_tagged_micheline::<_, { MICHELINE_STRING_TAG }>(nom_read::string)(input)
}
pub(crate) fn nom_read_micheline_int(input: NomInput) -> NomResult<Zarith> {
nom_read_tagged_micheline::<_, { MICHELINE_INT_TAG }>(Zarith::nom_read)(input)
}
pub(crate) fn bin_write_prim_no_args_no_annots(
prim_tag: u8,
output: &mut Vec<u8>,
) -> BinResult {
enc::put_bytes(&[MICHELINE_PRIM_NO_ARGS_NO_ANNOTS_TAG, prim_tag], output);
Ok(())
}
pub(crate) fn bin_write_prim_no_args_some_annots(
prim_tag: u8,
annots: &str,
output: &mut Vec<u8>,
) -> BinResult {
enc::put_bytes(&[MICHELINE_PRIM_NO_ARGS_SOME_ANNOTS_TAG, prim_tag], output);
enc::string(annots, output)?;
Ok(())
}
pub(crate) fn bin_write_prim_1_arg_no_annots<Arg>(
prim_tag: u8,
arg: &Arg,
output: &mut Vec<u8>,
) -> BinResult
where
Arg: BinWriter,
{
enc::put_bytes(&[MICHELINE_PRIM_1_ARG_NO_ANNOTS_TAG, prim_tag], output);
arg.bin_write(output)?;
Ok(())
}
pub(crate) fn bin_write_prim_1_arg_some_annots<Arg>(
prim_tag: u8,
arg: &Arg,
annots: &str,
output: &mut Vec<u8>,
) -> BinResult
where
Arg: BinWriter,
{
enc::put_bytes(&[MICHELINE_PRIM_1_ARG_SOME_ANNOTS_TAG, prim_tag], output);
arg.bin_write(output)?;
enc::string(annots, output)?;
Ok(())
}
pub(crate) fn bin_write_prim_2_args_no_annots<Arg1, Arg2>(
prim_tag: u8,
arg1: &Arg1,
arg2: &Arg2,
output: &mut Vec<u8>,
) -> BinResult
where
Arg1: BinWriter,
Arg2: BinWriter,
{
enc::put_bytes(&[MICHELINE_PRIM_2_ARGS_NO_ANNOTS_TAG, prim_tag], output);
arg1.bin_write(output)?;
arg2.bin_write(output)?;
Ok(())
}
pub(crate) fn bin_write_prim_2_args_some_annots<Arg1, Arg2>(
prim_tag: u8,
arg1: &Arg1,
arg2: &Arg2,
annots: &str,
output: &mut Vec<u8>,
) -> BinResult
where
Arg1: BinWriter,
Arg2: BinWriter,
{
enc::put_bytes(&[MICHELINE_PRIM_2_ARGS_SOME_ANNOTS_TAG, prim_tag], output);
arg1.bin_write(output)?;
arg2.bin_write(output)?;
enc::string(annots, output)?;
Ok(())
}
pub(crate) fn bin_write_prim_generic<Arg>(
prim_tag: u8,
args: &Vec<Arg>,
annots: &str,
output: &mut Vec<u8>,
) -> BinResult
where
Arg: BinWriter,
{
enc::put_bytes(&[MICHELINE_PRIM_GENERIC_TAG, prim_tag], output);
enc::dynamic(enc::list(Arg::bin_write))(args, output)?;
enc::string(annots, output)?;
Ok(())
}
fn bin_write_tagged_micheline<T, const TAG: u8>(
writer: impl FnOnce(T, &mut Vec<u8>) -> BinResult,
data: T,
output: &mut Vec<u8>,
) -> BinResult {
enc::put_byte(&TAG, output);
writer(data, output)
}
pub(crate) fn bin_write_micheline_bytes<T>(
bytes: impl BinSerializer<T>,
) -> impl FnOnce(T, &mut Vec<u8>) -> BinResult {
move |data, output| {
bin_write_tagged_micheline::<_, { MICHELINE_BYTES_TAG }>(
enc::dynamic(bytes),
data,
output,
)
}
}
pub(crate) fn bin_write_micheline_string(
data: &impl AsRef<str>,
output: &mut Vec<u8>,
) -> BinResult {
bin_write_tagged_micheline::<_, { MICHELINE_STRING_TAG }>(enc::string, data, output)
}
pub(crate) fn bin_write_micheline_int(data: &Zarith, output: &mut Vec<u8>) -> BinResult {
bin_write_tagged_micheline::<_, { MICHELINE_INT_TAG }>(
Zarith::bin_write,
data,
output,
)
}
pub(crate) fn bin_write_micheline_seq(
args: &Vec<Node>,
output: &mut Vec<u8>,
) -> BinResult {
enc::put_bytes(&[MICHELINE_SEQ_TAG], output);
enc::dynamic(enc::list(Node::bin_write))(args, output)?;
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
const MICHELINE_INT_ENCODING: &[(&str, &str)] = &[
("0", "0000"),
("1", "0001"),
("7f", "00bf01"),
("80", "008002"),
("81", "008102"),
("ff", "00bf03"),
("100", "008004"),
("101", "008104"),
("7fff", "00bfff03"),
("8000", "00808004"),
("8001", "00818004"),
("ffff", "00bfff07"),
("10000", "00808008"),
("10001", "00818008"),
("9da879e", "009e9ed49d01"),
];
#[test]
fn micheline_int_encode() {
for (hex, enc) in MICHELINE_INT_ENCODING {
let num = hex_to_bigint(hex);
let enc = hex::decode(enc).unwrap();
let micheline_int = MichelineInt(Zarith(num));
let mut bin = Vec::new();
micheline_int
.bin_write(&mut bin)
.expect("serialization should work");
assert_eq!(bin, enc);
}
}
#[test]
fn micheline_int_decode() {
for (hex, enc) in MICHELINE_INT_ENCODING {
let num = hex_to_bigint(hex);
let input = hex::decode(enc).unwrap();
let (input, dec) = MichelineInt::nom_read(&input).unwrap();
assert!(input.is_empty());
let micheline_int = MichelineInt(Zarith(num));
assert_eq!(micheline_int, dec);
}
}
#[test]
fn micheline_string_encode() {
let test = "the quick brown fox jumps over the lazy dog";
let mut expected = vec![1, 0, 0, 0, 43];
expected.append(&mut test.as_bytes().to_vec());
let mut bin = Vec::new();
MichelineString(test.into()).bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_string_decode() {
let expected = "Little by little, one travels far.";
let mut test = vec![1, 0, 0, 0, 34];
test.append(&mut expected.as_bytes().to_vec());
let (input_remaining, value) =
MichelineString::nom_read(test.as_slice()).unwrap();
assert!(input_remaining.is_empty());
assert_eq!(MichelineString(expected.into()), value);
}
#[test]
fn micheline_bytes_encode() {
let test = "hello".as_bytes().to_vec();
let expected = vec![
b'\n', 0, 0, 0, 5, b'h', b'e', b'l', b'l', b'o',
];
let bytes = MichelineBytes(test);
let mut bin = Vec::new();
bytes.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_bytes_decode() {
let expected = MichelineBytes("world".as_bytes().to_vec());
let test = vec![
b'\n', 0, 0, 0, 5, b'w', b'o', b'r', b'l', b'd',
];
let (remaining_input, bytes) = MichelineBytes::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, bytes);
}
#[test]
fn micheline_unit_decode() {
let test = vec![
3, 11, ];
let expected = MichelinePrimNoArgsNoAnnots::<11> {};
let (remaining_input, unit) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, unit);
}
#[test]
fn micheline_unit_encode() {
let expected = vec![
3, 11, ];
let test = MichelinePrimNoArgsNoAnnots::<11> {};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_nat_annot_decode() {
let test = vec![
4, 98, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let expected = MichelinePrimNoArgsSomeAnnots::<98> {
annots: ":foo".into(),
};
let (remaining_input, natfoo) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, natfoo);
}
#[test]
fn micheline_nat_annot_encode() {
let expected = vec![
4, 98, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let test = MichelinePrimNoArgsSomeAnnots::<98> {
annots: ":foo".into(),
};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_some_decode() {
let test = vec![
5, 9, 1, 0, 0, 0, 3, b'r', b'e', b'd', ];
let expected = MichelinePrim1ArgNoAnnots::<_, 9> {
arg: MichelineString("red".into()),
};
let (remaining_input, some) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, some);
}
#[test]
fn micheline_some_encode() {
let expected = vec![
5, 9, 0, 2, ];
let test = MichelinePrim1ArgNoAnnots::<MichelineInt, 9> { arg: 2.into() };
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_option_annot_decode() {
let test = vec![
6, 99, 3, 98, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let nat = MichelinePrimNoArgsNoAnnots::<98> {};
let expected = MichelinePrim1ArgSomeAnnots::<_, 99> {
arg: nat,
annots: ":foo".into(),
};
let (remaining_input, optnatfoo) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, optnatfoo);
}
#[test]
fn micheline_option_annot_encode() {
let expected = vec![
6, 99, 3, 98, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let nat = MichelinePrimNoArgsNoAnnots::<98> {};
let test = MichelinePrim1ArgSomeAnnots::<_, 99> {
arg: nat,
annots: ":foo".into(),
};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_pair_decode() {
let test = vec![
7, 7, 1, 0, 0, 0, 3, b'r', b'e', b'd', 0, 1, 4, b'!', ];
let expected = MichelinePrim2ArgsNoAnnots::<_, MichelineInt, 7> {
arg1: MichelineString("red".into()),
arg2: 1.into(),
};
let (remaining_input, pair) = NomReader::nom_read(test.as_slice()).unwrap();
assert_eq!(&[4, b'!'], remaining_input);
assert_eq!(expected, pair);
}
#[test]
fn micheline_pair_encode() {
let expected = vec![
7, 7, 0, 2, 1, 0, 0, 0, 5, b'g', b'r', b'e', b'e', b'n', ];
let test = MichelinePrim2ArgsNoAnnots::<MichelineInt, _, 7> {
arg1: 2.into(),
arg2: MichelineString("green".into()),
};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_or_annot_decode() {
let test = vec![
8, 100, 3, 98, 3, 91, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let nat = MichelinePrimNoArgsNoAnnots::<98> {};
let int = MichelinePrimNoArgsNoAnnots::<91> {};
let expected = MichelinePrim2ArgsSomeAnnots::<_, _, 100> {
arg1: nat,
arg2: int,
annots: ":foo".into(),
};
let (remaining_input, optnatfoo) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, optnatfoo);
}
#[test]
fn micheline_or_annot_encode() {
let expected = vec![
8, 100, 3, 98, 3, 91, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let nat = MichelinePrimNoArgsNoAnnots::<98> {};
let int = MichelinePrimNoArgsNoAnnots::<91> {};
let test = MichelinePrim2ArgsSomeAnnots::<_, _, 100> {
arg1: nat,
arg2: int,
annots: ":foo".into(),
};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_pair3_annot_decode() {
let test = vec![
9, 7, 0, 0, 0, 6, 3, 11, 0, 0, 0, 0, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let unit = MichelinePrimNoArgsNoAnnots::<11> {};
let expected = Node::Prim {
prim_tag: 7,
args: vec![unit.into(), 0.into(), 0.into()],
annots: Some(":foo".into()),
};
let (remaining_input, optnatfoo) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, optnatfoo);
}
#[test]
fn micheline_pair3_annot_encode() {
let expected = vec![
9, 7, 0, 0, 0, 6, 3, 11, 0, 0, 0, 0, 0, 0, 0, 4, b':', b'f', b'o', b'o', ];
let unit = MichelinePrimNoArgsNoAnnots::<11> {};
let test = Node::Prim {
prim_tag: 7,
args: vec![unit.into(), 0.into(), 0.into()],
annots: Some(":foo".into()),
};
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
#[test]
fn micheline_seq_decode() {
let test = vec![
2, 0, 0, 0, 6, 3, 11, 0, 0, 0, 0, ];
let unit = MichelinePrimNoArgsNoAnnots::<11> {};
let expected = Node::Seq(vec![unit.into(), 0.into(), 0.into()]);
let (remaining_input, optnatfoo) = NomReader::nom_read(test.as_slice()).unwrap();
assert!(remaining_input.is_empty());
assert_eq!(expected, optnatfoo);
}
#[test]
fn micheline_seq_encode() {
let expected = vec![
2, 0, 0, 0, 6, 3, 11, 0, 0, 0, 0, ];
let unit = MichelinePrimNoArgsNoAnnots::<11> {};
let test = Node::Seq(vec![unit.into(), 0.into(), 0.into()]);
let mut bin = Vec::new();
test.bin_write(&mut bin).unwrap();
assert_eq!(expected, bin);
}
fn hex_to_bigint(s: &str) -> num_bigint::BigInt {
use num_traits::FromPrimitive;
num_bigint::BigInt::from_u64(u64::from_str_radix(s, 16).unwrap()).unwrap()
}
}