代码编织梦想

我想实现一个read_integer() 函数,它接收一个&[u8] 切片,然后从切片中读取我们指定类型的整数

就像这样:

let slice = &[254, 255, 0, 0];

let i32_integer = read_integer::<i32>(slice);
let u32_integer = read_integer::<u32>(slice);
...

也就是我给函数传什么类型的整数,他就得从切片里给我返回什么类型的整数。

因为涉及了多种类型,我想到可以使用宏+trait来实现,如下:

use std::convert::TryInto;

pub trait ReadInteger<T> {
    fn from_le_bytes(data: &[u8]) -> T;
    fn from_be_bytes(data: &[u8]) -> T;
}

macro_rules! impl_read_integer {
    ($($t:ty),+) => {
        $(impl ReadInteger<$t> for $t {
            fn from_le_bytes(data: &[u8]) -> $t {
                <$t>::from_le_bytes(data.try_into().unwrap())
            }
            fn from_be_bytes(data: &[u8]) -> $t {
                <$t>::from_be_bytes(data.try_into().unwrap())
            }
        })+
    }
}

impl_read_integer!(u8, i16, i32, u32, i64);

遇到大端bytes时使用from_be_bytes,而小端bytes则是使用from_le_bytes

由于使用try_into()&[u8]转换成[u8; std::mem::size_of::<T>()],所以需要添加use std::convert::TryInto;以提供支持!

使用impl_read_integer!宏来添加对指定类型整数的支持。

trait和宏都准备好了,接下来就是read_integer()函数:

fn read_integer<T: ReadInteger<T>>(data: &[u8]) -> T {
    T::from_le_bytes(&data[..std::mem::size_of::<T>()])
}

由于我只需要处理小端的bytes,所以这样就搞定了,大端bytes直接使用from_be_bytes即可!

整体效果:

use std::convert::TryInto;

pub trait ReadInteger<T> {
    fn from_le_bytes(data: &[u8]) -> T;
    fn from_be_bytes(data: &[u8]) -> T;
}

macro_rules! impl_read_integer {
    ($($t:ty),+) => {
        $(impl ReadInteger<$t> for $t {
            fn from_le_bytes(data: &[u8]) -> $t {
                <$t>::from_le_bytes(data.try_into().unwrap())
            }
            fn from_be_bytes(data: &[u8]) -> $t {
                <$t>::from_be_bytes(data.try_into().unwrap())
            }
        })+
    }
}

impl_read_integer!(u8, i16, i32, u32, i64);

fn read_integer<T: ReadInteger<T>>(data: &[u8]) -> T {
    T::from_le_bytes(&data[..std::mem::size_of::<T>()])
}

let slice = &data[254, 255, 0, 0];

let i32_integer = read_integer::<i32>(slice);
let u32_integer = read_integer::<u32>(slice);
println!("{}, {}", i32_integer, u32_integer);

打印结果是65534,成功读取!

完毕!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/qq_26373925/article/details/111087884

Rust 工具之 rustup-爱代码爱编程

安装 rustup 是 Rust 的安装和管理工具,并且官网推荐使用 rustup 安装 Rust。 在不同操作系统的安装方式: 在 Unix 系统,使用curl https://sh.rustup.rs -sSf | sh命令,该命令会下载并运行rustup-init.sh。在 Windows 系统,下载并运行rustup-init.exe(32-

Rust学习笔记(二)——变量绑定-爱代码爱编程

Rust学习笔记(二)——变量绑定 常量变量不可变变量绑定与重影可变变量重新赋值 常量 Rust中用const来定义常量,常量的值不可变更。 例如: fn main(){ const PI: f32 = 3.14159265; println!("圆周率的大约数值为:{}。",PI); } 运行结果如下图: 变量 不可变变量绑定

Casper网络与以太坊2.0-爱代码爱编程

随着以太坊2.0(Eth2)信标链的推出,大家都很关注其对Casper及对我们开发工作的影响。其实,我们对标的不是以太坊2.0,而是以太坊3.0。   以太坊3.0至今没有路线图或实现日期,我们就先来说说Eth2。   Eth2可大致分为三个阶段:第0、第1和第2阶段。信标链版本就属于第0阶段,其本身并不能提升以太坊区块链的性能,Eth1也不会被信

对于某平台播放的简要修改代码-爱代码爱编程

F12直接上。 注:Internet Explorer 9及以上可用。 Blink 自便。 var ti = $("body"); var video = $(".catalogue_ul1 li[id*=video-] .catalogue_title"); var i = 1; var v = 1; var startTime = new Date(

Git分支-爱代码爱编程

大家暂时可以认为分支就是当前工作目录中代码的一份副本使用分支, 可以让我们从开发主线上分离出来,以免影响开发主线分支细分 1.主分支(master)第一次向git仓库中提交更新记录时自动产生的一个分支 2.开发分支(develop)作为开发的分支,基于master分支创建 3.功能分支(feature) 作为开发具体功能的分支,基于开发分支创建

详解格式化字符串漏洞利用(菜鸡向)-爱代码爱编程

详解格式化字符串漏洞利用 ​ 最近看了很多格式化字符串漏洞利用的文章,发现写得都差那么点意思,所以决定自己写一篇,结合实例,好好地把这个知识点捋一捋。 1、漏洞产生原理 ​ 对于一般的函数而言,应该按照cdecl (C Declaration) 函数调用规定把函数的参数从右到左依次压栈,**但是printf并不是一般的函数,它是C语言中少有的支持可变

搭建8086汇编语言学习环境——dosbox-爱代码爱编程

搭建8086汇编语言学习环境 资源网盘链接:链接:https://pan.baidu.com/s/1gamz6WYIWLOv5WP9H8L2Ng 提取码:ydvv 复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V3的分享 1、打开资料文件夹会发现有以下的资源 2、首先将MASM文件夹放到你常用的工作盘,这里我放到D盘中。

【入门】从零开始建网站-爱代码爱编程

欢迎关注微信公众号“Python小灶,和我一起每天学习Python新知识” 文章目录 基础入门,快速上手说明目标最终效果图流程购买服务器购买域名备案域名解析基本的配置让服务跑起来(上线)总结细节优化1--稳定运行为什么是flask + nginx + uWSGI部署先写一段简单的代码uWSGI安装下载在项目的目录创建一个uwsgi的配置文件启动其它命

【最佳实践】SequoiaDB集群扩容最佳实践-爱代码爱编程

前言 随着业务系统非结构化数据年增长量较大并且数据越来越多。在业务系统投产后,由于业务量的增加使得集群可使用存储容量逐渐变小,因此在业务系统接入集群前需考虑存储容量耗尽后整个集群的水平扩展。 SequoiaDB是分布式架构的多模数据库,因此可以通过集群的扩容实现集群性能的近线性增长。通过扩容后主要解决两个问题是数据存储的容量问题和整个集群的性能问题。因