项目地址:https://github.com/caizhengxin/jbytes
use jbytes::{ByteEncode, ByteDecode};
#[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
pub struct SimpleExample {
pub length: u16,
#[jbytes(length="length")]
pub value: String,
pub cmd: u8,
#[jbytes(branch="cmd")]
pub body: SimpleExampleBody,
}
#[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
pub enum SimpleExampleBody {
#[jbytes(branch_value=1)] // Set 1
Read {
address: u8,
},
Write {
address: u8,
value: [u8; 3],
}, // Increment to 2
#[jbytes(branch_default)]
Unknown, // _ => { ... }
}
fn main() {
let input = b"\x00\x03\x31\x32\x33\x01\x05";
let value: SimpleExample = jbytes::decode(input).unwrap();
assert_eq!(value, SimpleExample { length: 3, value: "123".to_string(), cmd: 1, body: SimpleExampleBody::Read { address: 5 } });
assert_eq!(*jbytes::encode(value).unwrap(), input);
}
Enum 解析简单例子:
use jbytes::{ByteEncode, ByteDecode};
use jbytes::prelude::*;
#[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
pub struct SimpleExample {
pub version: u8,
pub cmd: u8,
#[jbytes(branch="cmd")]
pub body: SimpleExampleBody,
}
#[derive(Debug, PartialEq, Eq, ByteEncode, ByteDecode)]
pub enum SimpleExampleBody {
#[jbytes(branch_value=1)]
Stop, // Set 1
Start, // Increment to 2
#[jbytes(branch_value="4..=7")]
Read {
address: u16,
length: u16,
}, // Set 4..=7, including: 4、5、6、7
Write {
address: u16,
length: u16,
#[jbytes(count="length")]
data: Vec<u8>,
}, // Increment to 8
#[jbytes(branch_default)]
Unknown {
address: u16,
}, // _ => { ... }
}
fn main() -> JResult<()> {
// Start
let input = [
0x01, // version
0x02, // cmd => Start
];
let value: SimpleExample = jbytes::decode(&input)?;
assert_eq!(value, SimpleExample {
version: 1,
cmd: 2,
body: SimpleExampleBody::Start
});
assert_eq!(*jbytes::encode(value)?, input);
// Read
let input = [
0x01, // version
0x05, // cmd => Read
0x00, 0x01, // Read, address
0x00, 0x0a, // Read, length
];
let value: SimpleExample = jbytes::decode(&input)?;
assert_eq!(value, SimpleExample {
version: 1,
cmd: 5,
body: SimpleExampleBody::Read {
address: 0x0001,
length: 0x000a,
}
});
assert_eq!(*jbytes::encode(value)?, input);
// Write
let input = [
0x01, // version
0x08, // cmd => Write
0x00, 0x01, // Write, address
0x00, 0x03, // Write, length
0x01, 0x02, 0x03, // Write, data
];
let value: SimpleExample = jbytes::decode(&input)?;
assert_eq!(value, SimpleExample {
version: 1,
cmd: 8,
body: SimpleExampleBody::Write {
address: 0x0001,
length: 0x0003,
data: vec![0x01, 0x02, 0x03],
}
});
assert_eq!(*jbytes::encode(value)?, input);
// Unknown
let input = [
0x01, // version
0x09, // cmd => Unknown
0x00, 0x01, // Unknown, address
];
let value: SimpleExample = jbytes::decode(&input).unwrap();
assert_eq!(value, SimpleExample {
version: 1,
cmd: 9,
body: SimpleExampleBody::Unknown {
address: 0x0001,
}
});
assert_eq!(*jbytes::encode(value)?, input);
Ok(())
}
HTTP Header 解析简单例子:
use jkcenum::JkcEnum;
use jbytes::{BorrowByteEncode, BorrowByteDecode};
use jbytes::prelude::*;
#[derive(Debug, Default, PartialEq, Eq, BorrowByteEncode, BorrowByteDecode)]
pub struct Http<'a> {
#[jbytes(linend=b"\x20", from_str)]
pub method: HttpMethodEnum,
#[jbytes(linend=b"\x20")]
pub uri: &'a str,
#[jbytes(linend=b"\r\n")]
pub version: &'a str,
#[jbytes(try_count=20)]
pub headers: Vec<HttpHeader<'a>>,
}
#[derive(Debug, Default, PartialEq, Eq, BorrowByteEncode, BorrowByteDecode)]
pub struct HttpHeader<'a> {
#[jbytes(linend=b": ")]
pub key: &'a str,
#[jbytes(linend=b"\r\n")]
pub value: &'a str,
}
#[derive(Debug, Default, PartialEq, Eq, BorrowByteDecode, BorrowByteEncode, JkcEnum)]
#[jbytes(byte_count_disable)]
pub enum HttpMethodEnum {
#[default]
GET,
POST,
HEAD,
PUT,
DELETE,
CONNECT,
OPTIONS,
TRACE,
PATCH,
}
fn main() {
// decode
let data = b"GET http://www.jankincai.com/ HTTP/1.1\r\nHost: www.jankincai.com\r\nAccept-Encoding: gzip, deflate\r\n";
let bytes = Bytes::new(data);
let value: Http = jbytes::decode_borrow(&bytes).unwrap();
println!("{value:?}");
// encode
assert_eq!(*jbytes::encode_borrow(value).unwrap(), data);
// error
let data: &[u8; 97] = b"SET http://www.jankincai.com/ HTTP/1.1\r\nHost: www.jankincai.com\r\nAccept-Encoding: gzip, deflate\r\n";
let bytes = Bytes::new(data);
let value: JResult<Http> = jbytes::decode_borrow(&bytes);
assert_eq!(value.is_err(), true);
}
Ext Link: https://github.com/caizhengxin/jbytes
1
共 13 条评论, 1 页
评论区
写评论你好,zerocopy我没有实际使用过,看起来使用方式和bincode差不多,jbytes主要在网络数据包解析、文件格式解析等可能有优势,不支持跨语言,目前还不完善,主要根据我对数据解析理解,简单封装了一个库,在于学习,哈哈。
--
👇
miaomiao1992: 和zerocopy有和异同?
跨语言,该协议是否通用?
和zerocopy有和异同?
跨语言,该协议是否通用?
字节流结构化 不是字节跳动结构化
--
👇
liangyongrui: 好奇为啥是私人仓库。这种不应该是审计后 用公司的名义发吗?
嗯,没事,第一版在2024年3月份就开源了,陆陆续续也更新了很久,目前这个是重构了大部分底层逻辑,换了个名字,重新开源了。
--
👇
liangyongrui: 不好意思,看错了。。
--
👇
jankincai: 很好奇,你从哪看到是公司项目,这个是我最近从头重新构思的个人项目。
--
👇
liangyongrui: 好奇为啥是私人仓库。这种不应该是审计后 用公司的名义发吗?
不好意思,看错了。。
--
👇
jankincai: 很好奇,你从哪看到是公司项目,这个是我最近从头重新构思的个人项目。
--
👇
liangyongrui: 好奇为啥是私人仓库。这种不应该是审计后 用公司的名义发吗?
好的,谢谢建议!
--
👇
regomne: 给个建议,要推广的话,还是要在页面中提一下竞品和跟竞品相比的区别,比如评论区就有人问和bincode啥区别,虽然在我看来其实不完全构成竞品
很好奇,你从哪看到是公司项目,这个是我最近从头重新构思的个人项目。
--
👇
liangyongrui: 好奇为啥是私人仓库。这种不应该是审计后 用公司的名义发吗?
给个建议,要推广的话,还是要在页面中提一下竞品和跟竞品相比的区别,比如评论区就有人问和bincode啥区别,虽然在我看来其实不完全构成竞品
好奇为啥是私人仓库。这种不应该是审计后 用公司的名义发吗?
可以的,很多修饰符可以通过数据内容动态解析后面的内容
--
👇
regomne: 这个不错啊,感觉也适合写各种文件格式的parser
这个不错啊,感觉也适合写各种文件格式的parser
有的,bincode功能很单一,这个更适合网络数据包解析。
--
👇
我心飞翔: 与 bincode 有什么区别吗
与 bincode 有什么区别吗