אינטראפעסיות פונקציות זרות (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 הופך לסוג robust 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.rustimpl Clone for Type1 { fn clone(&self) -> Self; } impl Clone for Type2 { fn clone(&self) -> Self; }