Skip to content

Шетелдік функция интерфейстері (FFI)

Қауымдастық iroha_ffi коробка C өндірісі үшін макролар мен қасиеттерді ұсынады ABI байланыстар Rust APIs. Бұл жерде қолданылады: Iroha түрлер арқылы өту керек FFI шекарасы, мысалы SDK байланыстар немесе қоректендіру интеграциялары.

Неге FFI

Функция - бұл абстрактты бірлік. Көптеген тілдер функцияның не істеу керектігі туралы келісе отырып, Сонымен қатар, кейбір тілдерде, мысалы: Rust, Функцияны шақырудың салдары және оған рұқсат етілген нәрселер де әртүрлі. Rust APIs басқа тілден немесе басқа қонақ ортадан шақыру қажет, Iroha сыртқы функция интерфейсін пайдаланады (FFI) ойын шарттарын теңестіру.

Бүгінгі таңда қолданылатын негізгі стандарт - C қолданбалы бинарлық интерфейс. Ол қарапайым, кеңінен қол жетімді және тұрақты. Негізінде сіз бәрін қолмен жасай аласыз, бірақ Iroha қолданыстағы Rust API функцияларынан FFI-қа сәйкес функцияларды тудыру үшін iroha_ffi қорын ұсынады.

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) түріне айналады, ол FfiType::into_ffi арқылы FFI шекарасын аша алады. Бұл керісінше де болады: FFI ReprC түрі Rust түріне FfiType::try_from_ffi арқылы айналады.

WARNING

Кері айналымның қате екенін және анықталмаған мінез-құлықтарға әкелуі мүмкін екенін ескеріңіз. Біз ең анық қателерді болдырмау үшін барынша күш сала аламыз, бірақ сіз бағдарламаның дұрыстығын қамтамасыз етуіңіз керек.

Байланыс туындысын құруға мүмкіндік беретін негізгі белгілер - ReprC, FfiType және FfiConvert.

қасиеттерБейнелеу
ReprCБұл қасиет C ABI сәйкес келетін берік типті білдіреді. Тип FFI шекараларында қауіпсіз бөлінеді.
FfiTypeБұл белгі белгілі бір Rust тип үшін тиісті ReprC түрін анықтайды. Белгіленген ReprC түрі Rust түрінің орнына пайда болған FFI функциясының API құрамында қолданылады.
FfiConvertБұл сипаттама into_ffi және try_from_ffi түрін Rust түріне немесе ReprC түрінен қайтару үшін қолданылатын екі әдісті анықтайды.

Байқаңыз, оған иелік етудің берілуі жоқ FFI Өткінші индикатор түрлерін қоспағанда, басқа да меншік иелері бар типтер: Vec<T>, клондалған.

Атын Манглинг

FFI нысандарының генериленген атауларында қос қосалқы белгілер қолданылуын ескеріңіз:

  • StructName құрылымында айқындалған inherent_fn әдісі үшін FFI атауы StructName__inherent_fn болып табылады.

  • StructName конструкциясындағы TraitName белгісінен алынған MethodName әдісі үшін FFI атауы StructNameTraitNameMethodName болады.

  • StructName құрылымында field_name өрісін орнату үшін FFI функциясының атауы StructName__set_field_name болып табылады.

  • StructName құрылымындағы field_name өрісін алу үшін FFI функциясының атауы StructName__field_name болады.

  • StructName құрылымындағы өзгеріске қабілетті field_name өрісін алу үшін 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;
    }