უცხოური ფუნქციების ინტერფეისები (FFI)
სააგენტო iroha_ffi კოლოფი უზრუნველყოფს მაკროებს და C-ის წარმოქმნის თვისებებს ABI ვალდებულებები Rust APIs. გამოიყენება: Iroha ტიპები უნდა გადაკვეთოს a FFI საზღვარი, მაგალითად: SDK დამაკავშირებელი ან მასპინძელი ინტეგრაციები.
რატომ FFI
ფუნქცია არის საკმაოდ აბსტრაქტული ერთეული და მიუხედავად იმისა, რომ უმეტეს ენები თანხმდებიან იმაზე, თუ რა უნდა გააკეთოს ფუნქციამ, ფუნქციების წარმოდგენა ძალიან განსხვავებულია. გარდა ამისა, ზოგიერთ ენაზე, როგორიცაა Rust, ფუნქციის დარეკვის შედეგები და ის რაღაცეები, რაც მისთვის დასაშვებია, ასევე განსხვავებულია. როდესაც Rust APIs უნდა იყოს გამოძახებული სხვა ენაზე ან სხვა მასპინძელი გარემოში, Iroha იყენებს უცხო ფუნქციის ინტერფეისს (FFI) სათამაშო მოედნის გასათანაბრებლად
დღეს გამოყენებული ძირითადი სტანდარტი არის C აპლიკაციის ბინარული ინტერფეისი. ეს მარტივია, ფართოდ ხელმისაწვდომია და სტაბილურია. პრინციპში ყველაფერი შეგიძლიათ გააკეთოთ ხელით, მაგრამ Iroha უზრუნველყოფს iroha_ffi ყუთს, რომ შექმნას FFI-თან შესაბამის ფუნქციებს არსებული Rust API.
რა თქმა უნდა, შეგიძლიათ გააკეთოთ ეს თქვენი გზით. iroha_ffi კარადა უბრალოდ გენერირებს იმ კოდს, რომელიც თქვენ მაინც მოგიწევთ გენერაციისთვის. საჭირო ბოილერის პლატის დაწერას საკმაოდ დიდი სიფრთხილია და დისციპლინა მოითხოვს. ყველა ფუნქციის მოწოდება FFI საზღვართან არის unsafe რომელსაც შეუძლია გამოიწვიოს განუსაზღვრელი ქცევა. მეთოდი, რომლის მეშვეობითაც ჩვენ შევძელით მისი გადაწყვეტა, ბრუნდება robust repr(C) ტიპების გამოყენებით.
INFO
ერთადერთი გამონაკლისი არის მანიშნებლები. ნულოვანი შემოწმება და ძალისხმევას ვერ ახორციელებს გლობალურად, ამიტომ ნედლეული მანიშნებელი (როგორც ყოველთვის) გამოიყენება მხოლოდ განსაკუთრებულ შემთხვევებში. იმის გათვალისწინებით, რომ Iroha მონაცემთა მოდელის ობიექტის თითქმის ყველა ინსტენციის გარშემო ვამზადებთ wrappers-ს, თქვენ საერთოდ არ უნდა გამოიყენოთ ნედლეული მაჩვენებლები.
მაგალითი
აქ მოცემულია ერთგვარი მაგალითი ბინდის წარმოქმნის შესახებ:
#[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 ტიპს იყენებენ წარმოქმნილი FFI ფუნქციის API ფუნქციაში Rust ტიპის ნაცვლად. |
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.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.rustimpl Clone for Type1 { fn clone(&self) -> Self; } impl Clone for Type2 { fn clone(&self) -> Self; }