Արտաքին գործառույթների ինտերֆեյսներ (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>, կլոնված են:
Անունը Mangling
Նշենք, որ FFI օբյեկտների ստեղծված անվանումներում օգտագործվում են կրկնակի ենթակետեր.
StructNameկառուցվածքի վրա սահմանվածinherent_fnմեթոդի համար FFI անվանումը կլինիStructName__inherent_fn:StructNameկառուցվածքում գտնվողTraitNameհատկանիշիցMethodNameմեթոդի համար FFI անվանումը կլինիStructNameTraitNameMethodName:StructNameկառուցվածքի մեջfield_nameդաշտը սահմանելու համար FFI գործառույթի անվանումը կլինիStructName__set_field_name:Որպեսզի ստանալ
field_nameդաշտումStructNameԿազմակերպություն 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.rustimpl Clone for Type1 { fn clone(&self) -> Self; } impl Clone for Type2 { fn clone(&self) -> Self; }