#key #bindings #configuration #access-key #hierarchical #key-set #global

elektra

Elektra是一个通用的、安全的框架,用于访问全局、分层键数据库中的配置参数

5个不稳定版本

0.11.1 2023年8月21日
0.10.0 2023年7月31日
0.9.10 2022年7月14日
0.9.1 2019年11月29日
0.9.0 2019年9月18日

#458 in 数据库接口

39 每月下载次数

BSD-3-Clause

100KB
1.5K SLoC

  • infos =
  • infos/author = Philipp Gackstatter [email protected]
  • infos/status = experimental maintained
  • infos/provides =
  • infos/description =

Rust对Elektra的绑定

Elektra作为一个通用的、安全的框架,用于访问全局、分层键数据库中的配置参数。

有关Elektra的更多信息,请访问网站

构建

根据您如何安装libelektra,您应该使用不同的方式来获取绑定。如果您使用包管理器安装,您应该使用crates.io上的crates。如果您本地构建了libelektra,您应该使用在build目录中构建的绑定。

包管理器

如果您通过包管理器安装了elektra,您应该使用elektra crate或者如果您需要原始绑定,则使用elektra-sys crate。在这种情况下,您将需要libelektra本身以及用于绑定生成的开发头文件(通常称为libelektra-dev)。在这种情况下,elektra-sys以及elektra crate都有一个名为pkg-config的功能,您可以通过将其添加到依赖部分来启用以查找elektra的安装及其头文件。默认情况下,它没有被启用,但推荐启用,并且您可以通过添加以下内容来实现这一点:features = ["pkg-config"],如以下所示。然后需要安装pkg-config实用工具。您的Cargo.toml依赖项可能如下所示:

[dependencies]
elektra = { version = "0.9.10", features = ["pkg-config"] }
# Directly depending on elektra-sys is only needed if you need to use the raw bindings
elektra-sys = { version = "0.9.10", features = ["pkg-config"] }

如果您不使用pkg-config功能,构建脚本将在/usr/local/include/elektra/usr/include/elektra中查找Elektra的安装。

设置好之后,当您运行cargo build时,应该会构建绑定。

本地构建

要将绑定显式地作为Elektra构建过程的一部分构建,我们将选项rust添加到-DBINDINGS。现在构建libelektra,绑定将在构建过程中构建。

您的Cargo.toml依赖项可能如下所示

[dependencies]
elektra = { path = "../libelektra/build/src/bindings/rust/elektra/"}

示例

请注意,您的动态链接器必须能够找到libelektra-{core,meta,kdb}。如果您刚刚编译了它,您可以从build目录运行source ../scripts/dev/run_env来适当地修改您的PATH

请参阅example目录以获取完整设置的项目。要运行它,请将工作目录更改为build/src/bindings/rust/example/,然后运行cargo run --bin key

要从头开始一个新的项目,使用cargo new elektra_rust。现在将elektra crate添加到依赖项。该crate位于您的build目录的src/bindings/rust子目录中,因此确切路径取决于您的系统。适当地更改路径(并可能更改版本),并将以下依赖项添加到您的Cargo.toml中。

[dependencies]
elektra = { version = "0.9.10", path = "~/git/libelektra/build/src/bindings/rust/elektra" }
# Directly depending on elektra-sys is only needed if you need to use the raw bindings
elektra-sys = { version = "0.9.10", path = "~/git/libelektra/build/src/bindings/rust/elektra-sys" }

如果您运行cargo run并且一切构建正确并打印出Hello, world!,您可以将main.rs的内容替换为下一节中显示的示例。

用法

使用 StringKey 的示例。在 example 目录下运行,使用以下命令:cargo run --bin key。更多示例请参阅完整示例

extern crate elektra;
use elektra::{ReadableKey, StringKey, WriteableKey};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // To create a simple key with a name and value
    let mut key = StringKey::new("user:/test/language")?;
    key.set_value("rust");

    println!("Key with name {} has value {}", key.name(), key.value());

    Ok(())
}

与 C-API 相比,存在两种不同的键类型,StringKeyBinaryKey。使用它们,在 BinaryKey 上调用 keyString 等类型不匹配的情况是不可能的。它们之间的唯一区别是你可以从它们设置和获取的值的类型。它们只是 C-API 中的 Key 的包装。

使用 BinaryKey 设置任意字节数值。

extern crate elektra;
use elektra::{BinaryKey, ReadableKey, WriteableKey};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let binary_content: [u8; 7] = [25, 34, 0, 254, 1, 0, 7];
    let mut key = BinaryKey::new("user:/test/rust")?;
    key.set_value(&binary_content);
    let read_content = key.value();

    println!(
        "Key with name {} holds bytes {:?}",
        key.name(),
        read_content
    );

    Ok(())
}

键的功能分为两个特质,ReadableKeyWritableKey,分别定义了只从键中读取信息的方法和修改键的方法。例如,检索元键的方法只返回实现 ReadableKey 的键,它是 ReadOnly 包装中的一个键。

KeySet

KeySet 是一组 StringKey。

  • 你可以使用 new 创建一个空键集,或者使用 with_capacity 预分配一定数量的键的空间。
  • 它有两个 Iterator 特质的实现,因此你可以以不可变或可变的方式迭代。

更多示例请参阅完整示例。在 example 目录下运行,使用以下命令:cargo run --bin keyset

extern crate elektra;
use elektra::{KeyBuilder, KeySet, ReadableKey, StringKey, keyset};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // keyset! works just like vec!
    let keyset = keyset![
        KeyBuilder::<StringKey>::new("user:/sw/app/#1/host")?
            .value("localhost")
            .build(),
        KeyBuilder::<StringKey>::new("user:/sw/app/#1/port")?
            .value("8080")
            .build(),
    ];

    // Iterate the keyset
    for key in keyset.iter() {
        println!("Key ({}, {})", key.name(), key.value());
    }

    Ok(())
}

KeySet 只包含 StringKey,因为它们比 BinaryKey 更常见。然而,由于底层 KeySet 持有泛型 KeyBinaryKey 也可能发生。您可以使用 From 特质在这两种键之间进行转换。这在内存方面是安全的,但如果将包含任意字节的 BinaryKey 转换为 StringKey,则可能是非安全的。您可以使用 is_stringis_binary 来确定转换是否安全。

let mut key = StringKey::new("user:/test/language")?;

// Cast the StringKey to BinaryKey
let binary_key = BinaryKey::from(key);

// And cast it back
let string_key = StringKey::from(binary_key);

KDB

使用 KDB 结构可以访问键数据库。更多示例请参阅完整示例。在 example 目录下运行,使用以下命令:cargo run --bin kdb

KDB 错误类型是嵌套的,因此您可以在高级别或特定级别上进行匹配。您可能希望使用 kdb_error.is_validation() 匹配所有验证错误,这将包括语法和语义验证错误。有关错误类型的深入解释,请参阅错误指南

extern crate elektra;

use elektra::{KeySet, StringKey, WriteableKey, KDB};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let contract = KeySet::with_capacity(0);

    // Open a KDB session
    let mut kdb = KDB::open(contract)?;

    // Create a keyset that will hold the keys we get from the get call
    let mut ks = KeySet::with_capacity(10);

    // Get the current state of the key database
    let mut parent_key = StringKey::new("user:/test")?;
    let get_res = kdb.get(&mut ks, &mut parent_key);

    if let Err(kdb_error) = get_res {
        if kdb_error.is_validation() {
            // Handle the validation error, which could be syntactic or semantic
            // You could use is_semantic() or is_syntactic() to match further.
            Ok(())
        } else {
            // Otherwise propagate the error up
            Err(Box::new(kdb_error))
        }
    } else {
        Ok(())
    }
}

原始绑定

elektra 包中提供了安全包装,但您也可以直接使用来自 elektra_sys 的原始绑定。例如,Rust 不允许定义可变参数函数,但允许调用它们。因此,您可以像在 C 中一样调用 keyNew

extern crate elektra_sys;
use elektra_sys::{keyDel, keyName, keyNew, keyString, KEY_END, KEY_VALUE};
use std::ffi::{CStr, CString};

fn main() {
    let key_name = CString::new("user:/test/key").unwrap();
    let key_val = CString::new("rust-bindings").unwrap();
    let key = unsafe { keyNew(key_name.as_ptr(), KEY_VALUE, key_val.as_ptr(), KEY_END) };
    let name_str = unsafe { CStr::from_ptr(keyName(key)) };
    let val_str = unsafe { CStr::from_ptr(keyString(key)) };
    println!("Key with name {:?} has value {:?}", name_str, val_str);
    assert_eq!(unsafe { keyDel(key) }, 0);
}

文档

对于 elektraelektra-sys,文档会在 docs.rs 上自动构建。请注意,由于 elektra-sys 是 C API 的一对一翻译,它没有文档,您应该直接使用 C 文档

您还可以在 build 目录的 src/bindings/rust/ 子目录中构建文档,通过运行 cargo doc 并打开 target/doc/elektra/index.html

生成

在构建 elektra-sys 包时,使用 rust-bindgen 生成绑定。在 elektra-sys 包中的 build.rs 脚本会调用并配置 bindgen。它还会为 rustc 发出额外的配置,以告诉它链接哪个库以及在哪里找到它。Bindgen 预期一个 wrapper.h 文件,该文件包含所有应为其生成绑定的头文件。最后,bindgen 将绑定输出到一个文件中,然后将其包含在 elektra-sys/lib.rs 文件中,以便其他包可以使用。

故障排除

Rust-bindgen 需要 clang 生成绑定,因此如果您遇到以下错误,请确保已安装 clang(3.9 或更高版本)。

/usr/include/limits.h:123:16: fatal error: 'limits.h' file not found
/usr/include/limits.h:123:16: fatal error: 'limits.h' file not found, err: true
thread 'main' panicked at 'Unable to generate bindings: ()', src/libcore/result.rs:999:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

依赖关系

~0–2MB
~38K SLoC