Внешние интерфейсы функций (FFI)
В настоящее время iroha_ffi ящик обеспечивает макросы и черты для создания C ABI обязательства от Rust APIs. Используется, когда Iroha типы должны пересечь FFI границы, например: SDK объединения или интеграции хоста.
Почему FFI
Функция является довольно абстрактным субъектом, и в то время как большинство языков соглашаются на том, что должна делать функция, Кроме того, на некоторых языках, таких как: Rust, последствия вызова функции и вещи, которые она может сделать, также различаются. Rust APIs нуждаются в вызове с другого языка или другой среды приема, Iroha использует внешний функциональный интерфейс (FFI) для уравнения условий.
Основным стандартом, используемым сегодня, является бинарный интерфейс приложений C. Он прост, широко доступен и стабилен. В принципе вы можете все делать вручную, но Iroha обеспечивает коробку iroha_ffi для генерации функций, соответствующих требованиям FFI из существующей Rust API.
Вы можете, конечно, сделать это по-своему. iroha_ffi ящик просто генерирует код, который вам нужно будет генерировать в любом случае. Каждый вызов функции над границей FFI является unsafe с потенциалом вызвать неопределенное поведение. Метод, которым нам удалось его решить, вращается вокруг использования надежных типов repr(C).
INFO
Единственным исключением являются указатели. Проверка нулевой действительности не может быть осуществлена в глобальном масштабе, поэтому сырые указатели (как всегда) используются только в исключительных случаях. Учитывая, что мы предоставляем упаковки вокруг почти каждого экземпляра объекта в модели данных Iroha, вы не должны вообще использовать сырые указатели.
Пример
Вот пример создания связывания:
#[derive(FfiType)]
struct DaysSinceEquinox(u32);
#[ffi_export]
impl DaysSinceEquinox {
pub fn update_value(&mut self, a: &u8) {
self.0 = *a as u32;
}
}В приведенном выше примере будет создана следующая связь с DaysSinceEquinox, представленная как непрозрачный показатель:
pub extern fn DaysSinceEquinox__update_value(handle: *mut DaysSinceEquinox, a: *const u8) -> FfiReturn {
// function implementation
}FFI Обязательное поколение
Ящик iroha_ffi используется для генерации функций, которые могут быть вызваны через FFI. Учитывая строки и методы Rust, они генерируют код unsafe, который вам нужен для пересечения границы соединения.
Тип Rust преобразуется в прочный тип repr(C), который может пересечь границу FFI с FfiType::into_ffi. Это происходит и наоборот: тип FFI ReprC превращается в тип Rust через FfiType::try_from_ffi.
WARNING
Обратите внимание, что обратное преобразование является ошибочным и может вызвать неопределенное поведение. Хотя мы можем сделать все возможное, чтобы избежать наиболее очевидных ошибок, вы должны убедиться в правильности программы на вашем конце.
Основные характеристики, позволяющие генерировать связывания, являются ReprC, FfiType и FfiConvert.
| Особенность . | Описание |
|---|---|
ReprC | Эта черта представляет собой надежный тип, который соответствует C ABI. Тип может быть безопасно распределен между FFI границы. |
FfiType | Эта черта определяет соответствующую ReprC тип для данного Rust тип. ReprC тип используется вместо Rust Тип в API из генерируемых FFI Функция. |
FfiConvert | Эта характеристика определяет два метода into_ffi и try_from_ffi, которые используются для выполнения преобразования типа Rust в или из типа ReprC. |
Обратите внимание, что не существует передачи собственности на FFI за исключением непрозрачных типов указателей. Vec<T>, Клонируются.
Название Манглинг
Обратите внимание на использование двойных подчеркновений в генерируемых названиях объектов FFI:
Для метода
inherent_fn, определенного на структуреStructName, название FFI будетStructName__inherent_fn.Для метода
MethodNameиз чертыTraitNameв структуреStructNameназвание FFI будетStructNameTraitNameMethodName.Для определения поля
field_nameв структуреStructNameназвание функции FFI будетStructName__set_field_name.Чтобы получить поле
field_nameв структуреStructName, название функции FFI будетStructName__field_name.Чтобы получить изменяемое поле
field_nameв структуреStructName, название функции FFI будетStrucuName__field_name_mut.Для независимого
module_name::fn_nameнаименование FFI было быmodule_name::__fn_name.Для характеристик, которые не являются общими и позволяют делиться их реализацией в FFI (см.
Cloneниже), наименование FFI будетmodule_name::__clone.rustimpl Clone for Type1 { fn clone(&self) -> Self; } impl Clone for Type2 { fn clone(&self) -> Self; }