7 个不稳定版本 (3 个破坏性更新)
0.4.0 | 2024年5月3日 |
---|---|
0.3.0 | 2023年12月10日 |
0.2.2 | 2023年4月28日 |
0.2.1 | 2023年3月25日 |
0.1.1 | 2022年5月29日 |
#454 in 编码
每月下载量 116
在 5 crates 中使用
460KB
10K SLoC
expry
expry
是一个快速的无模式二进制数据格式,能够使用表达式对存储的二进制数据进行过滤和选择信息部分。表达式被编译并优化为字节码,在评估时解释这些字节码。可以使用 expry_parse_json
将 JSON 读取到这些数据结构中。由于 expry
支持二进制字符串,并非所有的 expry
值都可以导出到 JSON。支持以下数据类型:
null
;bool
;int64
;float
;double
;string
;array
;object
.
表达式
二进制对象上的表达式编译为字节码,并可以通过网络传输。由于字节码在底层对二进制对象存储的方式进行优化,因此可以快速评估字节码。对象内部键以有序方式存储。如果当前表达式的评估不再需要键,则它们将被永久跳过。
- 常量:
null
,false
,true
,数字(包括:0x...
,0b...
,...f
),字符串,使用'string'
或"string"
(包括使用r#"..."#
的原始字符串,以及带有x'hex'
和x"hex"
的十六进制字符串)。 - 条件语句:支持 if-then-else 与条件(三元)运算符:
cond ? then-part : else-part
。 - 带有
{
字段的对象表达式?}
,包含可选字段,字段之间使用,
(最后一个条目可以有尾随的,
)分隔。- 字段可以是
name: expr
,其中 expr 是一个表达式或基本数据类型(见上文); - 字段可以是
"name": expr
,其中 expr 是一个表达式或基本数据类型(见上文); - 字段可以是
field
(或field???
),它从this
对象中复制字段; - 字段可以是
(expr): expr
以动态生成字段名(必须是一个字符串),例如{ (somefield): 42, }
(如果somefield
是"x"
,则结果为{x: 42}
)。
- 字段可以是
- 数组表达式:
[
表达式?]
,包含可选的表达式,这些表达式由,
(最后一个条目可以有尾随的,
)分隔。示例:[ 42+42, 37+37, ]
。 - 算术运算符:
+
,-
,*
,/
,**
(幂),%
(取模)。 - 位运算符:
|
,&
,^
(异或),<<
,>>
- 逻辑运算符:
&&,
||,
a ? b : c,
==,
!=,
>,
>=,
<,
<=。
- 特殊的
this
字段,用于表示当前对象。 - 数组索引:支持
a[b]
(数组索引)来访问数组中的单个元素 - 长度运算符
field.len()
,如果字段是字符串(字节数),数组(元素数量),或对象(键值对数量),则返回该字段的长度。
- 字符串运算符
a .. b
:连接字符串a
和b
;a *= b
:如果字符串a
包含字符串b
,则为真。a $= b
:如果字符串a
以字符串b
结尾,则为真。a ^= b
:如果字符串a
以字符串b
开头,则为真。
- 字段运算符
a.b.c.d
支持访问子字段;a.get(b).get(c).get(d)
支持动态子字段;
- 错误运算符
- try 运算符:
a ??? b
:如果在评估a
(例如未定义的字段或除以零)时出现错误。简写a ???
等同于a ??? null
。另一种语法是try(a, b)
和try(a)
。 - 非空否则运算符:
a ?? b
:如果a
为空,则返回b
。 defined(x)
和undefined(x)
:检查值是否已定义(如字段查找)。
- try 运算符:
- 字符串方法
.trim()
.lower()
.upper()
.hex()
.htmlescape()
.urlescape()
.sub(int[, int])
(第三个参数是结果的字符串长度,默认为最大整数值).basename()
.dirname()
.splitn(max, split_on)
(split_on 是分隔字符串,max 是结果数组中元素的最大数量),结果是一个字符串数组
- 类型方法
.tostring()
.tointeger()
.tofloat()
.todouble()
- 数组方法
array.extend(array)
合并两个数组。
- 接受 lambda 函数作为参数的方法。lambda 函数指定为
|x| expr
,其中x
是 lambda 函数的参数。array.filter(lambda)
过滤数组,只包含e
元素,其中lambda(e)
返回 true(注意 lambda 应始终返回布尔值,否则过滤将失败)array.map(lambda)
将元素数组e
映射到元素数组lambda(e)
array.sort_by_key(lambda)
根据键lambda(e)
对元素数组e
进行排序。值的排序基于以下类型顺序:null,bool,int,float,double,string,array,object。如果类型匹配,则按内容本身进行排序。请注意,NaN 浮点数的排序将产生动态错误,因为这未定义。array.to_object(lamba)
将数组转换为对象,其中键是 lambda 返回的数组中的第一个值。值是 lambda 返回的数组的第二个值。array.to_map(lamba)
创建一个键 - 值数组对象。lambda 返回 [key, sort, value]。
用户定义函数
在评估过程中,还可以添加用户定义的函数。这些用户定义的函数只在评估时才知道,因此没有静态类型检查。如果参数数量或参数类型不匹配,则只生成运行时错误。
轻松将自定义数据类型转换为值
使用 From
特性,可以将自定义数据类型轻松转换为值,即使它们包含在 Vec
等数据结构中。
use expry::*;
struct Foo {
foo: u32,
bar: bool,
}
impl<'a> From<&'a Foo> for DecodedValue<'a> {
fn from(v: &'a Foo) -> Self {
value!({
"foo": v.foo as i64,
"bar": v.bar,
})
}
}
let foos = vec![
Foo{foo:1,bar:true},
Foo{foo:2,bar:false},
];
let encoded_value = value!({
"foo": Foo{foo:1,bar:true},
"foos": foos,
}).encode_to_vec(false);