#slice #null #cstr

无 std sentinel

哨兵终止的切片库

20 个版本

0.5.4 2023年10月7日
0.5.0 2023年3月17日
0.3.4 2022年12月17日
0.3.3 2022年10月16日
0.1.2 2015年7月24日

#61FFI

Download history 8/week @ 2024-05-28 4/week @ 2024-07-02

每月 56 次下载

MIT/Apache

72KB
1.5K SLoC

Sentinel

sentinel 是一个哨兵终止的切片库。

工作原理

Rust 切片

在 Rust 中,切片类型 &[T] 的定义基本上是这样的:(*const T, usize)。这里的 usize 指示了在 *const T 中引用的 T 的数量。预先知道数组的尺寸具有许多优势,这里不再赘述。

然而,&[T] 类型存在两个主要问题

  1. 它不是(至少还不是)FFI 安全的。无法创建一个 extern "C" fn(s: &[u32]) 函数,并期望从 C 代码中调用它时能够工作。

  2. &[T] 的大小是两个 usize 的大小。

哨兵是什么?

哨兵是一个特殊值,用于确定数组的结束。例如,在 C 中,char * 类型可以是“以 null 结尾”的字符串的指针。这是一个哨兵终止的切片的例子。

CString:
char *ptr
 |
'H' 'e' 'l' 'l' 'o' '\0'
                      ^ sentinel, anything after this point may be invalid.
str:
*const u8, 5
 |
'H' 'e' 'l' 'l' 'o'
                    ^ no sentinel, we know the slice contains 5 elements.

这个 crate 在哨兵的定义上保持泛型。它使用 Sentinel trait,它大致定义如下

trait Sentinel<T> {
    fn is_sentinel(val: &T) -> bool;
}

它用于确定特定的 T 实例是否应被视为“哨兵”值。

SSlice

最后,与Sentinel特质结合,这个包定义了SSlice<T>类型。它是泛型类型T的,存储元素的类型,具有很高的灵活性。

struct SSlice<T> {
    _marker: PhantomData<T>,
}

请注意,这个类型实际上不包含任何数据。只能创建对这个类型的引用(即&SSlice<T>&mut SSlice<T>),并且这些引用的大小是一个usize

FFI

SSlice<T>类型是FFI安全的,这意味着你现在可以写出这个

// type CStr = sentinel::SSlice<u8>;

extern "C" {
    /// # Safety
    ///
    /// This will be `unsafe` because of `extern "C"`. But calling libc's `puts` with this
    /// signature is always sound!
    fn puts(s: &sentinel::CStr);
}

或者这个!

extern crate libc;

use sentinel::{cstr, CStr, SSlice};

fn print(s: &CStr) {
    // SAFETY:
    //  `CStr` ensures that the string is null-terminated.
    unsafe { libc::puts(s.as_ptr() as _) };
}

#[no_mangle]
extern "C" fn main(_ac: libc::c_int, argv: &SSlice<Option<&CStr>>) -> libc::c_int {
    print(cstr!("Arguments:"));
    for arg in argv.iter().unwrap_sentinels() {
        print(arg);
    }

    0
}

功能

  • alloc - 添加了对alloc包的支持。这添加了SBox<T>类型。

  • nightly - 利用不稳定的extern_type功能,确保不能在堆栈上创建SSlice<T>的实例,使其成为!Sized。此功能还启用了对新allocator_api不稳定功能的支持。

  • libc - 使用libc的strlenmemchr在哨兵终止的切片中查找空字符。

  • memchr - 使用memchr包在哨兵终止的切片中查找空字符。

allocmemchr默认启用。

旧的sentinel

“sentinel”这个名字是由这个项目的先前维护者友好地赐予我的。

所有0.2版本之前的版本(在crates.io上)都包含该包的源代码。

依赖项

~110-260KB