У меня есть библиотека C, которая ожидает строковый тип, который явно определяет длину строки:
#[repr(C)]
pub struct FFIStr {
len: usize,
data: *const u8,
}
Поскольку этот тип используется как статический, я хотел бы получить способ безопасно объявить его, используя constфункция или макрос (вместо ручной настройки len
).
Моей первой попыткой было использование макроса и len()
, однако в версиях до 1.39.0 это невозможночтобы получить длину среза как константу fn :
macro_rules! ffi_string {
($x:expr) => {
FFIStr { len: $x.len(), data: $x as *const u8 }
};
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string!(b"Hello, world!");
error: core::slice::<impl [T]>::len` is not yet stable as a const function
Моя вторая попытка была использовать std::mem::size_of<T>
, но, похоже, нет способа получить тип статического массива за исключением использования обобщений:
const fn ffi_string<T>(s: &'static T) -> FFIStr {
FFIStr { len: ::std::mem::size_of::<T>(), data: s as *const _ as *const _ }
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string(b"Hello, world!");
Хотя это работает (удивительно), оно ужасно склонно к неправильному использованию, так как оно дико преобразуетсячто бы вы ни передавали в *const u8
.
Кажется, что const_generics было бы хорошим решением для этого, но в настоящее время они нестабильны:
const fn ffi_string<const SIZE: usize>(s: &'static [u8; SIZE]) -> FFIStr {
FFIStr { len: SIZE, data: s as *const u8 }
}
#[no_mangle]
pub static mut X: FFIStr = ffi_string(b"Hello, world!");
error[E0658]: const generics are unstable
Есть ли лучший способ определить размер статического массива во время компиляции?