Как опубликовать постоянную строку в Rust RFI?

Я хочу, чтобы библиотека Rust отображала старую строку const char * на C, чтобы быть совместимой с существующим интерфейсом (в частности librsync). То есть, заголовочный файл C имеет

extern char const *my_string;

В C библиотека просто имела бы

char const *my_string = "hi";

В Rust я пробовал что-то вроде

pub static my_string: *const libc::c_char = unsafe { "hi\0" as *const libc::c_char };

но это жалуется

error: casting `&'static str` as `*const i8` is invalid

Похоже, я не могу использовать CString и т.д., потому что они не будут постоянным выражением времени компиляции.

2 ответа

Это немного странно, так что медведь со мной...

#[repr(C)]
pub struct StaticCString(*const u8);
unsafe impl Sync for StaticCString {}
#[no_mangle]
pub static CONST_C_STR: StaticCString =
 StaticCString(b"a constant c string\0" as *const u8);

В идеале, мы могли бы просто иметь открытый, статический, нечётный, постоянный указатель на некоторые байты, правильно? Однако вы не можете этого сделать, поскольку получите эту ошибку:

error: the trait `core::marker::Sync` is not implemented for the type `*const u8` [E0277]
 pub static CONST_C_STR: *const u8 = b"a constant c string\0" as *const u8;
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Я не потратил много времени на то, чтобы понять, почему это так. Кажется, что неизменный указатель не должен вызывать слишком много проблем...

Однако мы можем сказать компилятору, что наш тип безопасен для использования в многопоточной среде. Вот почему существует тип оболочки - он позволяет нам реализовать Sync для типа, который у нас есть. Одноэлементная структура всегда должна иметь ту же реализацию, что и обернутое значение, но мы продолжаем и отмечаем ее как repr(C), чтобы быть в безопасности.

Это работало с простой программой C:

#include <stdio.h>
extern char * CONST_C_STR;
int main(int argc, char *argv[]) {
 printf("%s\n", CONST_C_STR);
}
</stdio.h>


Ящик c_str_macro предоставляет удобный макрос c_str!, который добавляет 0 байт в строковый литерал Rust и представляет его как a CStr.

Отказ от ответственности: я являюсь автором ящика.

licensed under cc by-sa 3.0 with attribution.