Skip to content

Внешние интерфейсы функций (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, вы не должны вообще использовать сырые указатели.

Пример

Вот пример создания связывания:

rust
#[derive(FfiType)]
struct DaysSinceEquinox(u32);

#[ffi_export]
impl DaysSinceEquinox {
    pub fn update_value(&mut self, a: &u8) {
        self.0 = *a as u32;
    }
}

В приведенном выше примере будет создана следующая связь с DaysSinceEquinox, представленная как непрозрачный показатель:

rust
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.

    rust
    impl Clone for Type1 {
        fn clone(&self) -> Self;
    }
    impl Clone for Type2 {
        fn clone(&self) -> Self;
    }