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);