Skip to content

უცხოური ფუნქციების ინტერფეისები (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-ს, თქვენ საერთოდ არ უნდა გამოიყენოთ ნედლეული მაჩვენებლები.

მაგალითი

აქ მოცემულია ერთგვარი მაგალითი ბინდის წარმოქმნის შესახებ:

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 ტიპს იყენებენ წარმოქმნილი 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.

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