#epee #monero #binary-format #read-write #no-std #io-read

no-std epee-encoding

Epee 二进制格式库

4 个版本 (重大变更)

0.5.0 2023年7月22日
0.4.0 2023年7月14日
0.3.0 2023年7月14日
0.2.0 2023年7月5日
0.1.0 2023年7月5日

10#monero

每月23次 下载

MIT 许可证

35KB
709 代码行

Epee 编码

是什么

此包实现了 Monero 中使用的 epee 二进制格式;与其他包不同,此包不使用 serde,这并不是因为 serde 很差,而是为了减少维护者的负担,因为这个库中的所有特质都是针对 epee 的,而不是通用的。

特性

默认

默认功能启用了 derive 功能。

派生

此功能启用了 derive 宏,用于创建 epee 对象,例如

use epee_encoding::EpeeObject;
#[derive(EpeeObject)]
struct Test {
    val: u8
}

用法

无 derive 的示例

use epee_encoding::{EpeeObject, EpeeObjectBuilder, read_epee_value, write_field, to_bytes, from_bytes};
use epee_encoding::io::{Read, Write};

pub struct Test {
    val: u64
}

#[derive(Default)]
pub struct __TestEpeeBuilder {
    val: Option<u64>,
}

impl EpeeObjectBuilder<Test> for __TestEpeeBuilder {
    fn add_field<R: Read>(&mut self, name: &str, r: &mut R) -> epee_encoding::error::Result<bool> {
        match name {
            "val" => {self.val = Some(read_epee_value(r)?);}
            _ => return Ok(false),
        }
        Ok(true)
    }

    fn finish(self) -> epee_encoding::error::Result<Test> {
        Ok(
            Test {
                val: self.val.ok_or_else(|| epee_encoding::error::Error::Format("Required field was not found!"))?
            }
        )
    }
}

impl EpeeObject for Test {
    type Builder = __TestEpeeBuilder;
    
    fn number_of_fields(&self) -> u64 {
        1
    }

    fn write_fields<W: Write>(&self, w: &mut W) -> epee_encoding::error::Result<()> {
       // write the fields
       write_field(&self.val, "val", w)
   }
}


let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode;
let val: Test = from_bytes(&data).unwrap();
let data = to_bytes(&val).unwrap();


带 derive 的示例

use epee_encoding::{EpeeObject, from_bytes, to_bytes};

#[derive(EpeeObject)]
struct Test {
    val: u64
}


let data = [1, 17, 1, 1, 1, 1, 2, 1, 1, 4, 3, 118, 97, 108, 5, 4, 0, 0, 0, 0, 0, 0, 0]; // the data to decode;
let val: Test = from_bytes(&data).unwrap();
let data = to_bytes(&val).unwrap();

派生属性

EpeeObject 派生宏有几个属性,对应于特定的 C/C++ 宏字段。

epee_flatten

这相当于 KV_SERIALIZE_PARENT,它将对象中的所有字段扁平化到父对象中。

在 C/C++ 中是这样的

struct request_t: public rpc_request_base
    {
      uint8_t major_version;

      BEGIN_KV_SERIALIZE_MAP()
        KV_SERIALIZE_PARENT(rpc_request_base)
        KV_SERIALIZE(major_version)
      END_KV_SERIALIZE_MAP()
    };

在 Rust 中看起来是这样的

#[derive(EpeeObject)]
struct RequestT {
    #[epee_flatten]
    rpc_request_base: RequestBase,
    major_version: u8,
}

epee_alt_name

这允许您在编码时重新命名字段,尽管这与 C/C++ 中的特定宏无关,但这被包含在内,因为 Monero 有一些奇特的名称。

示例

#[derive(EpeeObject)]
pub struct HandshakeR {
    #[epee_alt_name("node_data")]
    pub node_daa: BasicNodeData,
}

epee_default

这相当于 KV_SERIALIZE_OPT,允许您指定字段的默认值,当指定默认值时,如果数据中不包含该值,则使用该值,如果值是默认值,则不会编码该字段。

在 C/C++ 中是这样的

struct request_t
{
  std::vector<blobdata>   txs;
  std::string _; // padding
  bool dandelionpp_fluff; //zero initialization defaults to stem mode

  BEGIN_KV_SERIALIZE_MAP()
    KV_SERIALIZE(txs)
    KV_SERIALIZE(_)
    KV_SERIALIZE_OPT(dandelionpp_fluff, true) // backwards compatible mode is fluff
  END_KV_SERIALIZE_MAP()
};

在 Rust 中看起来是这样的

#[derive(EpeeObject)]
struct RequestT {
    txs: Vec<Vec<u8>>,
    #[epee_alt_name("_")]
    padding: Vec<u8>,
    #[epee_default(true)]
    dandelionpp_fluff: bool,
}

无 std

此包是无 std 的。

选项

要有一个可选字段,您应使用 Option 包装类型,并使用 epee_default 属性。因此,它将看起来像这样

#[derive(EpeeObject)]
struct T {
    #[epee_default(None)]
    val: Option<u8>,
}

依赖项

~285–740KB
~17K SLoC