6 个版本 (3 个主要版本)

3.0.0 2024 年 7 月 16 日
2.0.6 2024 年 7 月 15 日
1.0.5 2024 年 6 月 3 日
1.0.4 2024 年 5 月 8 日
0.0.1 2024 年 2 月 12 日

#55调试

Download history 469/week @ 2024-05-03 36/week @ 2024-05-10 11/week @ 2024-05-17 5/week @ 2024-05-24 128/week @ 2024-05-31 29/week @ 2024-06-07 5/week @ 2024-06-14 389/week @ 2024-07-05 443/week @ 2024-07-12 53/week @ 2024-07-19 11/week @ 2024-07-26

每月 79 次下载

MIT 和可能 Apache-2.0…

1MB
20K SLoC

gearbox

Maintenance pipeline status coverage report Latest Release

Gearbox 是一个功能丰富的库,包括网络、日志记录、面向铁路的编程扩展和时间管理等功能。最初设计为一组实用工具,Gearbox 的最终愿景是发展成为一个高度优化的独立工具包。目标是逐步减少外部依赖,最终创建一个轻量级、高效的库。通过这样做,Gearbox 力求具有通用兼容性,从嵌入式系统到 WebAssembly(WASM)环境,同时保持简单并最小化样板代码的需求。这种开发策略使 Gearbox 成为寻求在广泛平台上构建高效、可扩展应用的开发者的综合解决方案。

功能

类别 功能 使用 描述 状态
通用 TryDefault gearbox::common::TryDefault 这是一个在 Gearbox 内部使用的特质,定义了一个返回 Result<T,Self::Error> 的 TryDefault 特质。它也可以用于其他系统。
BoxedFuture gearbox::common::BoxedFuture 固定装箱未来的类型别名。用于返回动态分派的未来。
Error ErrorTracer gearbox::error::tracer::* 一个构建可追溯错误堆栈的错误结构。它允许将错误分解为TypeId,以定义封装的错误,以便进行进一步操作。包含有关文件、行、模块路径和可选的错误码的信息,以及显示和调试。还包括宏 Error!(),该宏设置ErrorTracerExtInfo,包含所有所需的信息(文件、行、模块)。 ⚠️
Rail ErrorTracer gearbox::rails::ext::map_err_tracer 简化了与ErrorTracer一起操作的map_err,允许传递一个Error!()或一个ErrorTracerExtInfo以收集所有信息。
日志记录 跟踪日志格式化程序 gearbox::log::fmt::* 当使用rust Tracing库时,自定义订阅者用于格式化日志。 ⚠️
网络 主机名 gearbox::net::hostname 获取本地机器的主机名。
HTTP请求 gearbox::net::http::request 发送HTTP请求。这是在Reqwest之上的扩展,简化了mTLS和有效负载签名的实现。 ⚠️
HTTP请求链式操作 gearbox::net::http::request_chain HTTP请求链式系统,允许链式请求和响应,以进行更高级的请求/响应处理。
路径 常用路径 gearbox::path::* Windows、Linux等操作系统下的常用路径。例如,在Linux下,配置路径通常是~/.config/
Rails 常用扩展 gearbox::rails::ext::* 针对ResultOption和其他标准类型的不同扩展特性,提供额外的错误处理、合并结果和访问值的方法。 ⚠️
未来扩展 gearbox::rails::ext::future::* 针对Future类型的扩展,提供映射、链式操作和合并未来的方法。
serde 动态序列化 gearbox::serde::dynamic::* 允许对多种格式进行编码和解码的动态序列化系统。这是serde库的简化版本。 ⚠️
Wasm Bindgen Ser/de gearbox::serde::wasm_bindgen::* 为WASM Bind Generator实现,允许对JsValue进行序列化和反序列化。
存储 Web存储 gearbox::storage::web::local_storage::* 用于与Web环境中的本地存储交互的接口,包括设置、获取和删除数据的功能,支持JSON序列化和反序列化。 🚧
文件存储 gearbox::storage::io::file::* 用于与文件存储交互的接口,包括使用JSON和YAML序列化和反序列化设置、获取和删除数据的功能。 🧪
选择性存储 gearbox::storage::selective_storage 提供创建、设置、获取和删除存储条目的方法的选择性存储操作特性。 🚧
时间 时间戳及其他 gearbox::time::* 类似于Chrono的时间戳系统,处理时间和时间计算。在Gearbox中用于Chrono代替。 ⚠️
模板 模板引擎 gearbox::template::* 负责使用上下文数据和应用管道进行数据转换来渲染模板的模板引擎。它支持日期格式化和字符串前缀等操作的管道。 ⚠️

状态图标说明

  • ✅ 完成:功能已完全实现和测试。
  • ❌ 未完成:功能尚未实现。
  • ⚠️ 部分完成:功能部分实现。
  • 🚧 开发中:功能目前正在开发中。
  • 🧪 缺少测试:功能已实现,但缺乏测试。

测试状态

文件 覆盖率条形图 行覆盖率 已覆盖行数 总行数
src/collections/const_hash_map 0.0% 0 240
src/collections/hash_map 25.76% 51 198
src/collections/simple_linked_list 100.0% 138 138
src/collections/vec_deque 95.79% 182 190
src/common 70.37% 19 27
src/error 33.33% 12 36
src/error/tracer 27.32% 150 549
src/log/fmt 35.84% 396 1105
src/log/fmt/layer 0.0% 0 128
src/log/syslog 95.4% 166 174
src/net 68.63% 35 51
src/net/http/request 43.78% 401 916
src/net/http/request/header 47.78% 129 270
src/net/http/request_chaining 88.85% 526 592
src/net/http/test 79.63% 43 54
src/net/signature 85.17% 333 391
src/rails/ext/blocking 30.52% 159 521
src/rails/ext/future 97.57% 643 659
src/rails/ext/future/ext/option 86.65% 305 352
src/rails/ext/future/ext/result 82.57% 270 327
src/rails/tracing 100.0% 113 113
src/serde/dynamic 75.38% 251 333
src/serde/dynamic/test 14.71% 5 34
src/storage 0.0% 0 39
src/storage/io/file 57.39% 163 284
src/sync 100.0% 6 6
src/sync/rw_arc 74.82% 523 699
src/task 96.74% 297 307
src/task/multicommand 62.05% 103 166
src/template 83.16% 242 291
src/template/pipelines 80.3% 53 66
src/time 47.66% 1029 2159

Http 请求 (gearbox::net::http::request)

完整的架构概述

classDiagram
    %% Package: request
    namespace request {
        class Client {
            +client: reqwest::Client
            +new()
            +with_client(reqwest::Client)
            +set_global_signing(Signature)
        }

        class Error {
            +UrlParser(ParseError)
            +Request(reqwest::Error)
            +NoUrl
            +HeaderValue(reqwest::header::InvalidHeaderValue)
            +DeserializeContentType(String)
            +DeserializeJson(serde_json::Error)
            +BodyError(TracerError)
        }

        class Method {
            <<enumeration>>
            Get
            Post
            Put
            Delete
            Patch
            Head
            Options
            Connect
            Trace
            None
        }

        class RequestBuilder {
            +client: Option<Arc<Client>>
            +method: Method
            +uri: Option<Url>
            +headers: HeaderMap
            +body: Body
            +content_type: String
            +signature: Option<Signature>
            +new_with_client(client: Option<Client>, method: Method, uri: Url)
            +method(T: Into<Method>)
            +uri(uri: &str)
            +header(H: Into<Header>)
            +headers(H: Into<HeaderMap>)
            +body(B: Into<Body>)
            +content_type(content_type: &str)
            +with_signing_default()
            +with_signing(signature: Signature)
            +send()
        }

        class Response {
            +status: StatusCode
            +headers: HeaderMap
            +content_length: Option<u64>
            +url: Url
            +body: BodyOwned
            +status()
            +to(T: DeserializeOwned)
        }

        class StatusCode {
            +code: u16
            +reason: &'static str
            +as_u16()
            +as_str()
        }

        class Url {
            +Simple(url: String)
        }

        class Body {
            +Empty
        }

        class BodyOwned {
            +from(box_raw: Box<reqwest::Response>)
        }
    }

    %% Relationships
    Client --> RequestBuilder
    RequestBuilder --> Response
    RequestBuilder --> Error
    Response --> StatusCode
    Response --> HeaderMap
    Response --> Url
    Response --> BodyOwned
    HeaderMap --> Header
    Header --> Name
    Header --> Values
    Values --> Value

Http 请求链式调用 (gearbox::net::http::request_chaining)

完整的架构概述

classDiagram
    %% Package: request
    namespace request {
        class Client {
            +client: reqwest::Client
            +new()
            +with_client(reqwest::Client)
            +set_global_signing(Signature)
        }

        class Error {
            +UrlParser(ParseError)
            +Request(reqwest::Error)
            +NoUrl
            +HeaderValue(reqwest::header::InvalidHeaderValue)
            +DeserializeContentType(String)
            +DeserializeJson(serde_json::Error)
            +BodyError(TracerError)
        }

        class Method {
            <<enumeration>>
            Get
            Post
            Put
            Delete
            Patch
            Head
            Options
            Connect
            Trace
            None
        }

        class RequestBuilder {
            +client: Option<Arc<Client>>
            +method: Method
            +uri: Option<Url>
            +headers: HeaderMap
            +body: Body
            +content_type: String
            +signature: Option<Signature>
            +new_with_client(client: Option<Client>, method: Method, uri: Url)
            +method(T: Into<Method>)
            +uri(uri: &str)
            +header(H: Into<Header>)
            +headers(H: Into<HeaderMap>)
            +body(B: Into<Body>)
            +content_type(content_type: &str)
            +with_signing_default()
            +with_signing(signature: Signature)
            +send()
        }

        class Response {
            +status: StatusCode
            +headers: HeaderMap
            +content_length: Option<u64>
            +url: Url
            +body: BodyOwned
            +status()
            +to(T: DeserializeOwned)
        }

        class StatusCode {
            +code: u16
            +reason: &'static str
            +as_u16()
            +as_str()
        }

        class Url {
            +Simple(url: String)
        }

        class Body {
            +Empty
        }

        class BodyOwned {
            +from(box_raw: Box<reqwest::Response>)
        }
    }

    %% Package: request_chaining
    namespace request_chaining {
        class Header {
            +name: Name
            +values: Values
        }

        class HeaderMap {
            +inner: HashMap<Name, Values>
            +get(K: Into<Name>)
            +insert(header: Header)
            +extend(headers: HeaderMap)
        }

        class Name {
            +String name
        }

        class Values {
            +Vec<Value> values
            +iter()
        }

        class Value {
            +Vec<u8> value
            +as_bytes()
            +to_vec()
        }

        class TracerError
        class Signature
        class ParseError
    }

    %% Relationships
    Client --> RequestBuilder
    RequestBuilder --> Response
    RequestBuilder --> Error
    Response --> StatusCode
    Response --> HeaderMap
    Response --> Url
    Response --> BodyOwned
    HeaderMap --> Header
    Header --> Name
    Header --> Values
    Values --> Value

签名 (gearbox::net::signature)

有效载荷签名配置/生成器 此对象用于创建 API 密钥签名。

在此示例中,使用静态随机数生成 API 签名,以确认签名符合预期。示例还使用默认签名配置。

extern crate alloc;

use alloc::sync::Arc;
use gearbox::net::signature::Signature;
use base64;

let mut signing = Signature::default();
let nonce = 1616492376594usize;

let validated_sign = base64::decode("4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ==").unwrap();

let cal_sign = signing
  .var("payload", "ordertype=limit&pair=XBTUSD&price=37500&type=buy&volume=1.25")
  .var("secret_key", "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==")
  .var("url", "/0/private/AddOrder")
  .nonce(Arc::new(move || -> Vec<u8> {nonce.to_string().as_bytes().to_vec()}))
  .sign();

assert_eq!(validated_sign, cal_sign)

在签名时,锁定随机数可能很有用。通过锁定随机数,您将防止下一次签名时的更改。这对于默认签名配置以及不可预测的随机数非常有用。

在此示例中,签名将仅生成一个 base64 编码的值。

extern crate alloc;

use alloc::sync::Arc;
use gearbox::net::signature::*;
use base64;

let mut signing = Signature::default();

let cal_sign = signing
    .config(SignCal::Base64Encode(SignCal::VarString("nonce".to_string()).into())).nonce_default();
let nonce = cal_sign.nonce_lock();

let b64_nonce = base64::encode(nonce.unwrap()).into_bytes();


assert_eq!(b64_nonce, cal_sign.sign());

注意:使用 nonce_lock 将锁定随机数,直到下一次签名。一旦发生签名,锁定将被移除!另外,多次运行锁定将强制签名生成器创建新的随机数值。

Railway Future 扩展 (gearbox::rails::ext::future)

FutureOptional 和 FutureResult 文档

FutureOptional

一个扩展特质,用于 Future,它产生 Option<T>,并提供各种方便的适配器。

map

将此未来的可选输出映射到不同类型,返回一个新类型的未来。

此函数类似于 Option::map,其中它会更改底层未来的类型。这对于在未来的结果解析后进行计算链非常有用。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(1) };
let res = future_opt.map(|t| async move { 5 });
let final_res = res.await;
assert_eq!(final_res, Some(5));
and_then

如果输出为 Some,则将此未来与另一个未来链式连接,返回一个新类型的未来。

此函数类似于 Option::and_then,其中如果未来解析为 Some,则将链式连接另一个计算。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(1) };
let res = future_opt.and_then(|t| async move { Some(t + 1) });
let final_res = res.await;
assert_eq!(final_res, Some(2));
filter

过滤此未来的输出,如果谓词返回 false,则返回 None

此函数类似于 Option::filter,其中如果谓词返回 false,则返回 None

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(4) };
let res = future_opt.filter(|x| *x > 2);
let final_res = res.await;
assert_eq!(final_res, Some(4));
or

如果此未来的输出为 Some,则返回此未来的输出,否则返回提供的回退值。

此函数类似于Option::or,如果将来的结果为None,则返回提供的回退值。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(4) };
let res = future_opt.or(Some(10));
let final_res = res.await;
assert_eq!(final_res, Some(4));

let future_opt = async { None };
let res = future_opt.or(Some(10));
let final_res = res.await;
assert_eq!(final_res, Some(10));
or_else

如果此future的输出为Some,则返回此future的输出,否则调用提供的回退函数。

此函数类似于Option::or_else,如果将来的结果为None,则调用提供的回退函数。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(4) };
let res = future_opt.or_else(|| async { Some(10) });
let final_res = res.await;
assert_eq!(final_res, Some(4));

let future_opt = async { None };
let res = future_opt.or_else(|| async { Some(10) });
let final_res = res.await;
assert_eq!(final_res, Some(10));
unwrap_or

如果此future的输出为Some,则返回此future的输出,否则返回提供的默认值。

此函数类似于Option::unwrap_or,如果将来的结果为None,则返回提供的默认值。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(4) };
let res = future_opt.unwrap_or(10);
let final_res = res.await;
assert_eq!(final_res, 4);

let future_opt = async { None };
let res = future_opt.unwrap_or(10);
let final_res = res.await;
assert_eq!(final_res, 10);
unwrap_or_else

如果此future的输出为Some,则返回此future的输出,否则调用提供的回退函数。

此函数类似于Option::unwrap_or_else,如果将来的结果为None,则调用提供的回退函数。

示例
use gearbox::rails::ext::future::FutureOptional;

let future_opt = async { Some(4) };
let res = future_opt.unwrap_or_else(|| async { 10 });
let final_res = res.await;
assert_eq!(final_res, 4);

let future_opt = async { None };
let res = future_opt.unwrap_or_else(|| async { 10 });
let final_res = res.await;
assert_eq!(final_res, 10);
merge

将此future与一个可选值合并,生成一个新的future。

此函数还接受一个额外的选项和一个函数,用于将future解析出的值和选项合并成一个新的future。

示例
use gearbox::rails::ext::future::FutureOptional;

async fn func(x: u32, y: u32) -> Option<u32> {
    Some(x + y)
}

let x = async { Some(1) };
let y = Some(2);

let res = x.merge(y, |var_x, var_y| func(var_x, var_y));
assert_eq!(res.await, Some(3));
merge2

将此future与两个可选值合并,生成一个新的future。

此函数接受两个额外的选项和一个函数,用于将future解析出的值和选项合并成一个新的future。

示例
use gearbox::rails::ext::future::FutureOptional;

async fn func(x: u32, y: u32, z: u32) -> Option<u32> {
    Some(x + y + z)
}

let x = async { Some(1) };
let y = Some(2);
let z = Some(3);

let res = x.merge2(y, z, |var_x, var_y, var_z| func(var_x, var_y, var_z));
assert_eq!(res.await, Some(6));
merge3

将此future与三个可选值合并,生成一个新的future。

此函数接受三个额外的选项和一个函数,用于将future解析出的值和选项合并成一个新的future。

示例
use gearbox::rails::ext::future::FutureOptional;

async fn func(x: u32, y: u32, z: u32, a: u32) -> Option<u32> {
    Some(x + y + z + a)
}

let x = async { Some(1) };
let y = Some(2);
let z = Some(3);
let a = Some(4);

let res = x.merge3(y, z, a, |var_x, var_y, var_z, var_a| func(var_x, var_y, var_z, var_a));
assert_eq!(res.await, Some(10));
merge4

将此future与四个可选值合并,生成一个新的future。

此函数接受四个额外的选项和一个函数,用于将future解析出的值和选项合并成一个新的future。

示例
use gearbox::rails::ext::future::FutureOptional;

async fn func(x: u32, y: u32, z: u32, a: u32, b: u32) -> Option<u32> {
    Some(x + y + z + a + b)
}

let x = async { Some(1) };
let y = Some(2);
let z = Some(3);
let a = Some(4);
let b = Some(5);

let res = x.merge4(y, z, a, b, |var_x, var_y, var_z, var_a, var_b| func(var_x, var_y, var_z, var_a, var_b));
assert_eq!(res.await, Some(15));

FutureResult

这是一个为Future扩展的特质,它产生Result<T, E>,提供了各种方便的适配器。

map

将此future的结果输出映射到不同的类型,返回一个新类型的future。

此函数类似于Result::map,它将更改底层future的类型。当future解析后,如果它是Ok,这非常有用。

示例
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Ok::<_, ()>(1) };
let res = future_res.map(|t| async move { 5 });
let final_res = res.await;
assert_eq!(final_res, Ok(5));
map_or

通过应用一个函数到包含的Ok值来映射一个Result,如果它是Err,则使用默认值。

此函数类似于Result::map_or

示例

 {
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Ok::<_, ()>(1) };
let res = future_res.map_or(10, |t| async move { t + 1 });
let final_res = res.await;
assert_eq!(final_res, 2);

let future_res = async { Err::<i32, _>(()) };
let res = future_res.map_or(10, |t| async move { t + 1 });
let final_res = res.await;
assert_eq!(final_res, 10);
map_err

通过应用一个函数到包含的Err值来映射一个Result

此函数类似于Result::map_err

示例
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Err::<u32, _>(1) };
let res = future_res.map_err(|e| async move { e + 1 });
let final_res = res.await;
assert_eq!(final_res, Err(2));
and_then

如果输出为Ok,则与此future链式调用另一个future,返回一个新类型的future。

此函数类似于 Result::and_then,当未来解析为 Ok 时,它会链式调用另一个计算。

示例
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Ok::<_, ()>(1) };
let res = future_res.and_then(|t| async move { Ok(t + 1) });
let final_res = res.await;
assert_eq!(final_res, Ok(2));
or_else

如果未来解析为 Ok,则返回此未来的结果;否则调用提供的后备函数。

此函数类似于 Result::or_else,当未来解析为 Err 时,它会调用提供的后备函数。

示例
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Ok::<_, ()>(4) };
let res = future_res.or_else(|_| async { Ok(10) });
let final_res = res.await;
assert_eq!(final_res, Ok(4));

let future_res = async { Err::<i32, _>(()) };
let res = future_res.or_else(|_| async { Ok(10) });
let final_res = res.await;
assert_eq!(final_res, Ok(10));
unwrap_or_else

如果未来解析为 Ok,则返回此未来的结果;否则调用提供的后备函数。

此函数类似于 Result::unwrap_or_else,当未来解析为 Err 时,它会调用提供的后备函数。

示例
use gearbox::rails::ext::future::FutureResult;

let future_res = async { Ok::<_, ()>(4) };
let res = future_res.unwrap_or_else(|_| async { 10 });
let final_res = res.await;
assert_eq!(final_res, 4);

let future_res = async { Err::<i32, _>(()) };
let res = future_res.unwrap_or_else(|_| async { 10 });
let final_res = res.await;
assert_eq!(final_res, 10);
merge

将此未来与结果值合并,生成一个新的未来。

此函数接受一个额外的结果和一个函数,用于将未来的解析值和结果组合成一个新的未来。

示例
use gearbox::rails::ext::future::FutureResult;

async fn func(x: u32, y: u32) -> Result<u32, ()> {
    Ok(x + y)
}

let x = async { Ok::<_, ()>(1) };
let y = Ok(2);

let res = x.merge(y, |var_x, var_y| func(var_x, var_y));
assert_eq!(res.await, Ok(3));
merge2

将此未来与两个结果值合并,生成一个新的未来。

此函数接受两个额外的结果和一个函数,用于将未来的解析值和结果组合成一个新的未来。

示例
use gearbox::rails::ext::future::FutureResult;

async fn func(x: u32, y: u32, z: u32) -> Result<u32, ()> {
    Ok(x + y + z)
}

let x = async { Ok::<_, ()>(1) };
let y = Ok(2);
let z = Ok(3);

let res = x.merge2(y, z, |var_x, var_y, var_z| func(var_x, var_y, var_z));
assert_eq!(res.await, Ok(6));
merge3

将此未来与三个结果值合并,生成一个新的未来。

此函数接受三个额外的结果和一个函数,用于将未来的解析值和结果组合成一个新的未来。

示例
use gearbox::rails::ext::future::FutureResult;

async fn func(x: u32, y: u32, z: u32, a: u32) -> Result<u32, ()> {
    Ok(x + y + z + a)
}

let x = async { Ok::<_, ()>(1) };
let y = Ok(2);
let z = Ok(3);
let a = Ok(4);

let res = x.merge3(y, z, a, |var_x, var_y, var_z, var_a| func(var_x, var_y, var_z, var_a));
assert_eq!(res.await, Ok(10));
merge4

将此未来与四个结果值合并,生成一个新的未来。

此函数接受四个额外的结果和一个函数,用于将未来的解析值和结果组合成一个新的未来。

示例
use gearbox::rails::ext::future::FutureResult;

async fn func(x: u32, y: u32, z: u32, a: u32, b: u32) -> Result<u32, ()> {
    Ok(x + y + z + a + b)
}

let x = async { Ok::<_, ()>(1) };
let y = Ok(2);
let z = Ok(3);
let a = Ok(4);
let b = Ok(5);

let res = x.merge4(y, z, a, b, |var_x, var_y, var_z, var_a, var_b| func(var_x, var_y, var_z, var_a, var_b));
assert_eq!(res.await, Ok(15));

动态序列化/反序列化(gearbox::serde::dynamic)

简单的 serde 如其名所示,是对多个序列化和反序列化仓库的简化实现。

简而言之,目标是拥有一个用于序列化和反序列化的单一工具,具有统一的接口。

用法

Simple Serde 使用 .encode.decode 进行编码和解码。解码可以应用于任何 Vec<u8>&[u8],这允许实现最干净。对于需要序列化/编码的任何内容也是如此。任何实现了 #[derive(Serialize)] 的类型都可以使用 .encode 简单编码。

编码/解码

.encode.decode 都接受一个 ContentType 参数,它定义了你正在编码/解码的内容类型。例如,可以是 [一些 Vec<u8>].decode("bson")my_struct.encode("bson")。这是可能的,因为 ContentType&strString 实现了 TryFrom 特性。如果实现无法从你试图编码/解码的类型中解码,编码器/解码器将返回一个包含 Error::UnknownContentTypeMatchFromStrErr 结果。

编码器输出的任何内容都将为 Vec<u8> 类型,进一步地,这个 Vec<u8> 被封装在一个名为 Encoded 的结构体中,这允许在实现上进行进一步的简化,例如,TryToString 将自动尝试将 Encoded 转换为 String。此外,Encoded 还实现了 DerefDerefMut,这使它更容易访问封装的数据。

支持的格式

  • Bson
  • Cbor
  • FlexBuffers
  • Json
  • Json5
  • Lexpr
  • MessagePack
  • Pickle
  • Postcard
  • Ron
  • Toml
  • Url
  • Yaml
  • Xml (Awaiting serde-xml-rs v. >0.51)

所有 ContentType 的字符串定义都是不区分大小写的,并提供有备选

  • 应用/[格式]
  • 应用/x-[格式]

序列化/编码示例

use core::ops::Deref;
use serde::Serialize;
#[macro_use]
use serde_derive;
use gearbox::serde::dynamic::{Encoded, SimpleEncoder, TryToString};

#[derive(Serialize)]
struct Foo {
    bar: String,
}

let my_foo = Foo {
  bar: "foobar".to_string(),
};

let encoded: Encoded = my_foo
  .encode("yaml")
  .expect("Should have been encoded in yaml");

assert_eq!(
    &vec![98, 97, 114, 58, 32, 102, 111, 111, 98, 97, 114, 10],
    encoded.deref()
);
assert_eq!(r#"bar: foobar
"#, encoded.try_to_string().unwrap())

反序列化/解码示例

use core::ops::Deref;
use serde::Deserialize;
#[macro_use]
use serde_derive;
use gearbox::serde::dynamic::{Decoded, SimpleDecoder};

#[derive(Deserialize, Debug, PartialEq)]
struct Foo {
    bar: String,
}

let my_foo = Foo {
  bar: "foobar".to_string(),
};

let v_u8_data = &vec![45, 45, 45, 10, 98, 97, 114, 58, 32, 102, 111, 111, 98, 97, 114, 10];
let string_data = r#"---
bar: foobar
"#;

let decoded_from_v_u8: Decoded<Foo> = v_u8_data.decode("yaml").expect("Should have decoded the Vec<u8>");
let decoded_from_string: Decoded<Foo> = string_data.decode("yaml").expect("Should have decoded the String");

assert_eq!(
    Foo{bar: "foobar".to_string()},
    decoded_from_v_u8.into()
);
assert_eq!(
    Foo{bar: "foobar".to_string()},
    decoded_from_string.into()
);

RwArc (gearbox::sync::rw_arc)

rw_arc 模块提供了一种强大而灵活的机制,用于在 Rust 中处理并发数据访问,允许多个读取器或单个写入器访问数据。此模块旨在为多线程环境提供高性能和安全,包括诸如 ReadArcDetachedArcHyperWriteArcUpgradableArcWriteArc 等各种结构体,每个结构体都针对特定的并发访问模式进行了优化。它结合了 ArcRwLock 的功能,同时避免了生命周期的限制,提供了更多的灵活性和一些固有的风险。

概述

功能

  • 读写锁:允许多个读取器或单个写入器访问数据,确保高效的数据访问而不会出现冲突。
  • 可升级锁:允许将锁从读取访问升级为写入访问,从而实现更灵活和高效的锁管理。
  • 分离的 Arc:提供创建锁的分离实例的方法,这些实例可以在不同的上下文中使用,从而实现灵活的锁管理。
  • 超锁(写时销毁):高效地执行写操作,确保数据在销毁时写回到主存储,优化了延迟写操作的场景。

优势和风险

  • 通用性:通过结合ArcRwLock的功能,rw_arc允许进行跨克隆和其他不受生命周期限制的操作。这增加了并发编程的灵活性。
  • 危险:由于没有生命周期限制,rw_arc模块更危险,因为它依赖于手动保证的安全性,这通常由Rust编译器的借用检查器强制执行。

架构

graph TD;
    RwArc -->|Has| RwArcInner;
    RwArcInner -->|Contains| Arc;
    Arc -->|References| Data;
    RwArc -->|Provides| ReadArc;
    RwArc -->|Provides| WriteArc;
    RwArc -->|Provides| UpgradableArc;
    RwArc -->|Provides| DetachedArc;
    RwArc -->|Provides| HyperReadArc;
    RwArc -->|Provides| HyperWriteArc;

使用示例

use gearbox::sync::rw_arc::RwArc;
use std::sync::Arc;

let lock: RwArc<i32> = RwArc::new(0);

// Read access
{
    let read_guard = lock.read();
    println!("Read: {}", *read_guard);
}

// Write access
{
    let mut write_guard = lock.write();
    *write_guard += 1;
    println!("Write: {}", *write_guard);
}

// Upgradeable read//!
{
    let upgradable_guard = lock.upgradeable_read();
    let write_guard = upgradable_guard.upgrade();
    println!("Upgradeable to Write: {}", *write_guard);
}

详细描述

ReadArc

一个只读锁保护器,允许多个并发读取者。即使底层数据被丢弃,ReadArc也会继续保留数据,使其成为现有数据的真正克隆。

示例
use gearbox::sync::rw_arc::RwArc;
use std::sync::Arc;

let lock : RwArc<i32>= RwArc::new(0);

let read_arc = lock.read();
println!("ReadArc value: {}", *read_arc);

DetachedArc

一个可以附加到现有RwArc的分离锁保护器。这允许灵活的锁管理,其中锁可以在稍后创建和附加。

示例
use gearbox::sync::rw_arc::{DetachedArc, RwArc};

let rw_arc: RwArc<i32> = RwArc::new(10);
let detached_arc = DetachedArc::new(20);

if let Some(read_arc) = detached_arc.attach_read(&rw_arc) {
    println!("Attached ReadArc value: {}", *read_arc);
}

HyperWriteArc

一个写锁保护器,确保在销毁时将写入的数据正确存储回主数据结构。这被称为写销毁(WOD),旨在进行高效的延迟写操作。

示例
use gearbox::sync::rw_arc::RwArc;

let lock: RwArc<i32> = RwArc::new(5);
{
    let mut hyper_write_guard = lock.hyper_write();
    *hyper_write_guard = 10;
}
{
    let read_guard = lock.read();
    assert_eq!(*read_guard, 10);
}

UpgradableArc

一个可升级的读锁保护器,可以升级为写锁,从而实现更灵活和高效的锁管理。

示例
use gearbox::sync::rw_arc::RwArc;

let lock: RwArc<i32> = RwArc::new(5);
{
    let upgradable_guard = lock.upgradeable_read();
    let write_guard = upgradable_guard.upgrade();
    assert_eq!(*write_guard, 5);
}
{
    let read_guard = lock.read();
    assert_eq!(*read_guard, 5);
}

WriteArc

一个写锁保护器,允许修改数据,同时确保修改安全提交。

示例
use gearbox::sync::rw_arc::RwArc;

let lock: RwArc<i32> = RwArc::new(0);
{
    let mut write_guard = lock.write();
    *write_guard += 1;
    println!("Write: {}", *write_guard);
}

RwArc (gearbox::template)

描述

template模块提供了一个强大且灵活的机制,用于在Rust中渲染模板,允许通过管道进行动态内容插入和转换。此模块旨在在模板渲染和数据转换中提供高性能和安全。它包括各种结构,如TemplateEngineTemplateContextPipelineManagerDatePipelinePrefixPipeline,每个都针对特定的模板模式进行了定制。它结合了模板解析器和管道管理器的功能,在模板渲染中提供灵活性和简单性。

功能

  • TemplateEngine:负责使用上下文数据渲染模板,并应用管道进行数据转换。
  • TemplateContext:管理模板的上下文数据,允许动态插入和检索值。
  • PipelineManager:管理用于数据转换的可用管道,支持默认和自定义管道。
  • DatePipeline:一个用于格式化日期的管道。
  • PrefixPipeline:一个用于添加前缀的管道。

优势和风险

  • 通用性:该模块的灵活性通过允许动态模板渲染和通过自定义管道轻松扩展来增强开发。
  • 危险:潜在风险包括管道使用不当和多线程环境中的锁定机制的性能开销。

线程安全

TemplateEngine及其相关组件使用原子操作和锁定机制进行线程安全。用于PIPELINESMutex确保安全的并发访问,尽管可能会引入性能开销。

使用弱引用打破循环

该模块不直接使用弱引用,而是使用Mutex来安全地并发访问共享资源。

克隆引用

从现有的模板引擎或上下文中创建新引用是通过为TemplateEngineTemplateContext实现的Clone特质来完成的。

use gearbox::template::{TemplateEngine, TemplateContext};

let engine = TemplateEngine::new();
let engine_clone = engine.clone();
let context = TemplateContext::new();
let context_clone = context.clone();

Deref行为

TemplateContext提供了对其内部HashMap的直接访问,用于管理上下文变量,允许轻松插入和检索值。

使用示例

在线程之间共享一些不可变数据

use gearbox::template::{TemplateEngine, TemplateContext};
use std::thread;

let engine = TemplateEngine::new();
let mut context = TemplateContext::new();
context.insert("name", Box::new("World".to_string()));

for _ in 0..10 {
    let engine = engine.clone();
    let context = context.clone();

    thread::spawn(move || {
        let result = engine.render("Hello, {{ name }}!", &context).unwrap();
        println!("{}", result);
    });
}

共享一个可变原子值

use gearbox::template::{TemplateEngine, TemplateContext};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

let engine = TemplateEngine::new();
let val = Arc::new(AtomicUsize::new(5));

for _ in 0..10 {
    let val = Arc::clone(&val);

    thread::spawn(move || {
        let v = val.fetch_add(1, Ordering::Relaxed);
        println!("{}", v);
    });
}

详细描述

TemplateEngine

TemplateEngine 结构是 template 模块的核心。它负责通过应用上下文数据和利用管道进行数据转换来渲染模板。TemplateEngine 维护一个 PipelineManager 实例,该实例包含所有可用的管道。

  • 字段:

    • pipelines:一个管理所有已注册管道的 PipelineManager 实例。
  • 方法:

    • new() -> Self:创建一个具有默认管道的新的 TemplateEngine 实例。
    • get_pipelines_default() -> PipelineManager:返回默认的管道集合。
    • update_pipeline<P: Pipeline + Send + Sync + 'static>(name: &str, pipeline: P):更新或添加一个指定名称的管道。
    • get_pipeline(name: &str) -> Option<Box<dyn Pipeline + Send + Sync>>:通过名称检索一个特定的管道。
    • get_pipelines() -> PipelineManager:检索所有可用的管道。
    • render(&self, template: &str, context: &TemplateContext) -> Result<String, DynTracerError>:使用提供的上下文渲染模板。
use gearbox::template::{TemplateEngine, TemplateContext};

let engine = TemplateEngine::new();
let mut context = TemplateContext::new();
context.insert("name", Box::new("World".to_string()));

let result = engine.render("Hello, {{ name }}!", &context).unwrap();
assert_eq!(result, "Hello, World!");

TemplateContext

TemplateContext 结构管理模板中使用的上下文数据。它允许动态插入和检索值。

  • 字段:

    • variables:一个存储上下文变量的 HashMap
  • 方法:

    • new() -> Self:创建一个新的 TemplateContext 实例。
    • insert(&mut self, key: &str, value: Box<dyn PipelineValue + Send + Sync>: 插入一个新的上下文变量。
    • get(&self, key: &str) -> Option<&Box<dyn PipelineValue + Send + Sync>>: 通过键检索上下文变量。
use gearbox::template::TemplateContext;

let mut context = TemplateContext::new();
context.insert("key", Box::new("value".to_string()));
println!("TemplateContext value: {}", context.get("key").unwrap());

PipelineManager

PipelineManager 结构管理可用的数据转换管道。

  • 字段:

    • 0: 存储管道的 HashMap
  • 方法:

    • 实现了 DerefDerefMut 特性,以便访问内部 HashMap
    • 实现了 Clone 特性,允许克隆 PipelineManager 及其管道。
use gearbox::template::{PipelineManager, pipelines::DatePipeline, Pipeline};

let mut manager = PipelineManager::default();
manager.insert("date".to_string(), DatePipeline::new().boxed_clone());
println!("PipelineManager contains date pipeline: {}", manager.contains_key("date"));

DatePipeline

DatePipeline 结构是一个用于格式化日期的管道,它实现了 Pipeline 特性。

  • 字段:

    • format: 存储日期格式的 String
  • 方法:

    • new() -> Self: 创建一个带有默认格式的 DatePipeline
    • format(&self, pipe_object: &Box<dyn PipelineValue + Send + Sync>) -> Box<dyn PipelineValue + Send + Sync>: 使用管道的转换格式化输入值。
    • options(&self, options: &str) -> Box<dyn Pipeline + Send + Sync>: 创建一个具有指定选项的新管道实例。
    • boxed_clone(&self) -> Box<dyn Pipeline + Send + Sync>:将管道克隆到封装实例中。
use gearbox::template::{Pipeline, pipelines::DatePipeline, PipelineValue};
use gearbox::time::DateTime;

let date_pipeline = DatePipeline::new();
let date = DateTime::from_date(2024, 7, 1);
let value: Box<(dyn PipelineValue + Send + Sync + 'static)> = Box::new(date);
let formatted = date_pipeline.format(&value);
println!("Formatted date: {}", formatted);

PrefixPipeline

PrefixPipeline 结构是一个用于前缀字符串的管道。它实现了 Pipeline 特性。

  • 字段:

    • prefix:存储前缀的 String
  • 方法:

    • new() -> Self:创建一个新的具有默认前缀的 PrefixPipeline
    • format(&self, pipe_object: &Box<dyn PipelineValue + Send + Sync>) -> Box<dyn PipelineValue + Send + Sync>: 使用管道的转换格式化输入值。
    • options(&self, options: &str) -> Box<dyn Pipeline + Send + Sync>: 创建一个具有指定选项的新管道实例。
    • boxed_clone(&self) -> Box<dyn Pipeline + Send + Sync>:将管道克隆到封装实例中。
use gearbox::template::{Pipeline, pipelines::PrefixPipeline, PipelineValue};

let prefix_pipeline = PrefixPipeline::new();
let value: Box<(dyn PipelineValue + Send + Sync + 'static)> = Box::new("value".to_string());
let prefixed = prefix_pipeline.format(&value);
println!("Prefixed value: {}", prefixed);

架构图

graph TD;
    TemplateEngine -->|Uses| PipelineManager;
    PipelineManager -->|Contains| DatePipeline;
    PipelineManager -->|Contains| PrefixPipeline;
    TemplateEngine -->|Uses| TemplateContext;
    TemplateContext -->|Contains| Variables;
    TemplateEngine -->|Uses| Pipelines;

待办事项

  • ( gearbox::log::* ) 清理 Log fmt/syslog,一些代码可以合并和更好地整理,此外,格式化程序支持 syslog 和 bunyan,这应该进一步清理并更好地分离。
  • ( gearbox::path::* ) 当前此系统主要只是暴露 dirs::* 库,应该将其移除。
  • ( gearbox::* ) 移除 Vec 的使用或将 std::vec::Vec 的使用移至另一个非 std 库

当前版本:3.0.0

许可证:MIT

依赖关系

~14–41MB
~663K SLoC