[{"data":1,"prerenderedAt":2820},["ShallowReactive",2],{"page-\u002Frust\u002F26-ffi":3},{"id":4,"title":5,"body":6,"description":16,"extension":2814,"meta":2815,"navigation":93,"path":2816,"seo":2817,"stem":2818,"__hash__":2819},"content\u002Frust\u002F26-ffi.md","26 — FFI (Foreign Function Interface)",{"type":7,"value":8,"toc":2776},"minimark",[9,13,17,22,160,180,185,195,231,237,290,297,303,327,570,610,614,617,743,752,756,819,837,840,857,893,897,903,939,948,1093,1114,1124,1127,1190,1207,1211,1364,1372,1376,1387,1391,1406,1410,1556,1581,1585,1592,1693,1699,1703,1840,1851,1855,1858,1876,1977,1981,1985,2134,2141,2148,2192,2197,2201,2237,2243,2306,2313,2319,2396,2401,2407,2410,2446,2452,2456,2534,2544,2560,2564,2656,2660,2737,2741,2769,2772],[10,11,5],"h1",{"id":12},"_26-ffi-foreign-function-interface",[14,15,16],"p",{},"Rust talks to C — and through C, to almost every other language. This chapter covers calling C from Rust, Rust from C, and the supporting ecosystem.",[18,19,21],"h2",{"id":20},"calling-c-from-rust","Calling C from Rust",[23,24,26],"code-wrapper",{"language":25},"rust",[27,28,32],"pre",{"className":29,"code":30,"language":25,"meta":31,"style":31},"language-rust shiki shiki-themes github-light github-dark","extern \"C\" {\n    fn abs(x: i32) -> i32;\n}\n\nfn main() {\n    let x = unsafe { abs(-5) };\n    println!(\"{x}\");\n}\n","",[33,34,35,52,82,88,95,107,141,155],"code",{"__ignoreMap":31},[36,37,40,44,48],"span",{"class":38,"line":39},"line",1,[36,41,43],{"class":42},"svdQ7","extern",[36,45,47],{"class":46},"sJ6F3"," \"C\"",[36,49,51],{"class":50},"ssxIu"," {\n",[36,53,55,58,62,65,68,71,74,77,79],{"class":38,"line":54},2,[36,56,57],{"class":42},"    fn",[36,59,61],{"class":60},"sIsaT"," abs",[36,63,64],{"class":50},"(x",[36,66,67],{"class":42},":",[36,69,70],{"class":60}," i32",[36,72,73],{"class":50},") ",[36,75,76],{"class":42},"->",[36,78,70],{"class":60},[36,80,81],{"class":50},";\n",[36,83,85],{"class":38,"line":84},3,[36,86,87],{"class":50},"}\n",[36,89,91],{"class":38,"line":90},4,[36,92,94],{"emptyLinePlaceholder":93},true,"\n",[36,96,98,101,104],{"class":38,"line":97},5,[36,99,100],{"class":42},"fn",[36,102,103],{"class":60}," main",[36,105,106],{"class":50},"() {\n",[36,108,110,113,116,119,122,125,128,131,134,138],{"class":38,"line":109},6,[36,111,112],{"class":42},"    let",[36,114,115],{"class":50}," x ",[36,117,118],{"class":42},"=",[36,120,121],{"class":42}," unsafe",[36,123,124],{"class":50}," { ",[36,126,127],{"class":60},"abs",[36,129,130],{"class":50},"(",[36,132,133],{"class":42},"-",[36,135,137],{"class":136},"snvgF","5",[36,139,140],{"class":50},") };\n",[36,142,144,147,149,152],{"class":38,"line":143},7,[36,145,146],{"class":60},"    println!",[36,148,130],{"class":50},[36,150,151],{"class":46},"\"{x}\"",[36,153,154],{"class":50},");\n",[36,156,158],{"class":38,"line":157},8,[36,159,87],{"class":50},[161,162,163,170,177],"ul",{},[164,165,166,169],"li",{},[33,167,168],{},"extern \"C\""," declares a foreign function with the C ABI.",[164,171,172,173,176],{},"Calling requires ",[33,174,175],{},"unsafe"," (the compiler can't verify the signature or memory safety).",[164,178,179],{},"The linker resolves the symbol at link time.",[181,182,184],"h3",{"id":183},"linking","Linking",[14,186,187,188,191,192,67],{},"Add the C library to ",[33,189,190],{},"Cargo.toml"," via ",[33,193,194],{},"build.rs",[23,196,197],{"language":25},[27,198,200],{"className":29,"code":199,"language":25,"meta":31,"style":31},"\u002F\u002F build.rs\nfn main() {\n    println!(\"cargo:rustc-link-lib=c\");\n}\n",[33,201,202,208,216,227],{"__ignoreMap":31},[36,203,204],{"class":38,"line":39},[36,205,207],{"class":206},"sdCPZ","\u002F\u002F build.rs\n",[36,209,210,212,214],{"class":38,"line":54},[36,211,100],{"class":42},[36,213,103],{"class":60},[36,215,106],{"class":50},[36,217,218,220,222,225],{"class":38,"line":84},[36,219,146],{"class":60},[36,221,130],{"class":50},[36,223,224],{"class":46},"\"cargo:rustc-link-lib=c\"",[36,226,154],{"class":50},[36,228,229],{"class":38,"line":90},[36,230,87],{"class":50},[14,232,233,234,67],{},"Or use ",[33,235,236],{},"#[link(name = \"mylib\")]",[23,238,239],{"language":25},[27,240,242],{"className":29,"code":241,"language":25,"meta":31,"style":31},"#[link(name = \"mylib\")]\nextern \"C\" {\n    fn my_func(x: i32) -> i32;\n}\n",[33,243,244,257,265,286],{"__ignoreMap":31},[36,245,246,249,251,254],{"class":38,"line":39},[36,247,248],{"class":50},"#[link(name ",[36,250,118],{"class":42},[36,252,253],{"class":46}," \"mylib\"",[36,255,256],{"class":50},")]\n",[36,258,259,261,263],{"class":38,"line":54},[36,260,43],{"class":42},[36,262,47],{"class":46},[36,264,51],{"class":50},[36,266,267,269,272,274,276,278,280,282,284],{"class":38,"line":84},[36,268,57],{"class":42},[36,270,271],{"class":60}," my_func",[36,273,64],{"class":50},[36,275,67],{"class":42},[36,277,70],{"class":60},[36,279,73],{"class":50},[36,281,76],{"class":42},[36,283,70],{"class":60},[36,285,81],{"class":50},[36,287,288],{"class":38,"line":90},[36,289,87],{"class":50},[181,291,293,296],{"id":292},"bindgen-for-auto-binding",[33,294,295],{},"bindgen"," for Auto-Binding",[14,298,299,300,302],{},"Hand-writing extern blocks is error-prone. ",[33,301,295],{}," generates Rust bindings from C headers:",[23,304,306],{"language":305},"toml",[27,307,310],{"className":308,"code":309,"language":305,"meta":31,"style":31},"language-toml shiki shiki-themes github-light github-dark","# Cargo.toml\n[build-dependencies]\nbindgen = \"0.69\"\n",[33,311,312,317,322],{"__ignoreMap":31},[36,313,314],{"class":38,"line":39},[36,315,316],{},"# Cargo.toml\n",[36,318,319],{"class":38,"line":54},[36,320,321],{},"[build-dependencies]\n",[36,323,324],{"class":38,"line":84},[36,325,326],{},"bindgen = \"0.69\"\n",[23,328,329],{"language":25},[27,330,332],{"className":29,"code":331,"language":25,"meta":31,"style":31},"\u002F\u002F build.rs\nuse std::env;\nuse std::path::PathBuf;\n\nfn main() {\n    let bindings = bindgen::Builder::default()\n        .header(\"wrapper.h\")\n        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))\n        .generate()\n        .expect(\"Unable to generate bindings\");\n\n    let out_path = PathBuf::from(env::var(\"OUT_DIR\").unwrap());\n    bindings.write_to_file(out_path.join(\"bindings.rs\")).unwrap();\n}\n",[33,333,334,338,352,370,374,382,407,423,456,466,481,486,531,565],{"__ignoreMap":31},[36,335,336],{"class":38,"line":39},[36,337,207],{"class":206},[36,339,340,343,346,349],{"class":38,"line":54},[36,341,342],{"class":42},"use",[36,344,345],{"class":60}," std",[36,347,348],{"class":42},"::",[36,350,351],{"class":50},"env;\n",[36,353,354,356,358,360,363,365,368],{"class":38,"line":84},[36,355,342],{"class":42},[36,357,345],{"class":60},[36,359,348],{"class":42},[36,361,362],{"class":60},"path",[36,364,348],{"class":42},[36,366,367],{"class":60},"PathBuf",[36,369,81],{"class":50},[36,371,372],{"class":38,"line":90},[36,373,94],{"emptyLinePlaceholder":93},[36,375,376,378,380],{"class":38,"line":97},[36,377,100],{"class":42},[36,379,103],{"class":60},[36,381,106],{"class":50},[36,383,384,386,389,391,394,396,399,401,404],{"class":38,"line":109},[36,385,112],{"class":42},[36,387,388],{"class":50}," bindings ",[36,390,118],{"class":42},[36,392,393],{"class":60}," bindgen",[36,395,348],{"class":42},[36,397,398],{"class":60},"Builder",[36,400,348],{"class":42},[36,402,403],{"class":60},"default",[36,405,406],{"class":50},"()\n",[36,408,409,412,415,417,420],{"class":38,"line":143},[36,410,411],{"class":42},"        .",[36,413,414],{"class":60},"header",[36,416,130],{"class":50},[36,418,419],{"class":46},"\"wrapper.h\"",[36,421,422],{"class":50},")\n",[36,424,425,427,430,432,435,437,440,442,444,446,449,451,453],{"class":38,"line":157},[36,426,411],{"class":42},[36,428,429],{"class":60},"parse_callbacks",[36,431,130],{"class":50},[36,433,434],{"class":60},"Box",[36,436,348],{"class":42},[36,438,439],{"class":60},"new",[36,441,130],{"class":50},[36,443,295],{"class":60},[36,445,348],{"class":42},[36,447,448],{"class":60},"CargoCallbacks",[36,450,348],{"class":42},[36,452,439],{"class":60},[36,454,455],{"class":50},"()))\n",[36,457,459,461,464],{"class":38,"line":458},9,[36,460,411],{"class":42},[36,462,463],{"class":60},"generate",[36,465,406],{"class":50},[36,467,469,471,474,476,479],{"class":38,"line":468},10,[36,470,411],{"class":42},[36,472,473],{"class":60},"expect",[36,475,130],{"class":50},[36,477,478],{"class":46},"\"Unable to generate bindings\"",[36,480,154],{"class":50},[36,482,484],{"class":38,"line":483},11,[36,485,94],{"emptyLinePlaceholder":93},[36,487,489,491,494,496,499,501,504,506,509,511,514,516,519,522,525,528],{"class":38,"line":488},12,[36,490,112],{"class":42},[36,492,493],{"class":50}," out_path ",[36,495,118],{"class":42},[36,497,498],{"class":60}," PathBuf",[36,500,348],{"class":42},[36,502,503],{"class":60},"from",[36,505,130],{"class":50},[36,507,508],{"class":60},"env",[36,510,348],{"class":42},[36,512,513],{"class":60},"var",[36,515,130],{"class":50},[36,517,518],{"class":46},"\"OUT_DIR\"",[36,520,521],{"class":50},")",[36,523,524],{"class":42},".",[36,526,527],{"class":60},"unwrap",[36,529,530],{"class":50},"());\n",[36,532,534,537,539,542,545,547,550,552,555,558,560,562],{"class":38,"line":533},13,[36,535,536],{"class":50},"    bindings",[36,538,524],{"class":42},[36,540,541],{"class":60},"write_to_file",[36,543,544],{"class":50},"(out_path",[36,546,524],{"class":42},[36,548,549],{"class":60},"join",[36,551,130],{"class":50},[36,553,554],{"class":46},"\"bindings.rs\"",[36,556,557],{"class":50},"))",[36,559,524],{"class":42},[36,561,527],{"class":60},[36,563,564],{"class":50},"();\n",[36,566,568],{"class":38,"line":567},14,[36,569,87],{"class":50},[23,571,572],{"language":25},[27,573,575],{"className":29,"code":574,"language":25,"meta":31,"style":31},"\u002F\u002F src\u002Flib.rs\ninclude!(concat!(env!(\"OUT_DIR\"), \"\u002Fbindings.rs\"));\n",[33,576,577,582],{"__ignoreMap":31},[36,578,579],{"class":38,"line":39},[36,580,581],{"class":206},"\u002F\u002F src\u002Flib.rs\n",[36,583,584,587,589,592,594,597,599,601,604,607],{"class":38,"line":54},[36,585,586],{"class":60},"include!",[36,588,130],{"class":50},[36,590,591],{"class":60},"concat!",[36,593,130],{"class":50},[36,595,596],{"class":60},"env!",[36,598,130],{"class":50},[36,600,518],{"class":46},[36,602,603],{"class":50},"), ",[36,605,606],{"class":46},"\"\u002Fbindings.rs\"",[36,608,609],{"class":50},"));\n",[181,611,613],{"id":612},"wrapping-in-safe-apis","Wrapping in Safe APIs",[14,615,616],{},"Raw FFI bindings are unsafe. Wrap them:",[23,618,619],{"language":25},[27,620,622],{"className":29,"code":621,"language":25,"meta":31,"style":31},"mod sys {\n    extern \"C\" {\n        pub fn strlen(s: *const u8) -> usize;\n    }\n}\n\npub fn strlen(s: &CStr) -> usize {\n    unsafe { sys::strlen(s.as_ptr()) }\n}\n",[33,623,624,634,643,674,679,683,687,714,739],{"__ignoreMap":31},[36,625,626,629,632],{"class":38,"line":39},[36,627,628],{"class":42},"mod",[36,630,631],{"class":60}," sys",[36,633,51],{"class":50},[36,635,636,639,641],{"class":38,"line":54},[36,637,638],{"class":42},"    extern",[36,640,47],{"class":46},[36,642,51],{"class":50},[36,644,645,648,651,654,657,659,662,665,667,669,672],{"class":38,"line":84},[36,646,647],{"class":42},"        pub",[36,649,650],{"class":42}," fn",[36,652,653],{"class":60}," strlen",[36,655,656],{"class":50},"(s",[36,658,67],{"class":42},[36,660,661],{"class":42}," *const",[36,663,664],{"class":60}," u8",[36,666,73],{"class":50},[36,668,76],{"class":42},[36,670,671],{"class":60}," usize",[36,673,81],{"class":50},[36,675,676],{"class":38,"line":90},[36,677,678],{"class":50},"    }\n",[36,680,681],{"class":38,"line":97},[36,682,87],{"class":50},[36,684,685],{"class":38,"line":109},[36,686,94],{"emptyLinePlaceholder":93},[36,688,689,692,694,696,698,700,703,706,708,710,712],{"class":38,"line":143},[36,690,691],{"class":42},"pub",[36,693,650],{"class":42},[36,695,653],{"class":60},[36,697,656],{"class":50},[36,699,67],{"class":42},[36,701,702],{"class":42}," &",[36,704,705],{"class":60},"CStr",[36,707,73],{"class":50},[36,709,76],{"class":42},[36,711,671],{"class":60},[36,713,51],{"class":50},[36,715,716,719,721,724,726,729,731,733,736],{"class":38,"line":157},[36,717,718],{"class":42},"    unsafe",[36,720,124],{"class":50},[36,722,723],{"class":60},"sys",[36,725,348],{"class":42},[36,727,728],{"class":60},"strlen",[36,730,656],{"class":50},[36,732,524],{"class":42},[36,734,735],{"class":60},"as_ptr",[36,737,738],{"class":50},"()) }\n",[36,740,741],{"class":38,"line":458},[36,742,87],{"class":50},[14,744,745,747,748,751],{},[33,746,705],{},"\u002F",[33,749,750],{},"CString"," are the safe wrappers around C's null-terminated strings.",[18,753,755],{"id":754},"calling-rust-from-c","Calling Rust from C",[23,757,758],{"language":25},[27,759,761],{"className":29,"code":760,"language":25,"meta":31,"style":31},"#[no_mangle]\npub extern \"C\" fn add(a: i32, b: i32) -> i32 {\n    a + b\n}\n",[33,762,763,768,804,815],{"__ignoreMap":31},[36,764,765],{"class":38,"line":39},[36,766,767],{"class":50},"#[no_mangle]\n",[36,769,770,772,775,777,779,782,785,787,789,792,794,796,798,800,802],{"class":38,"line":54},[36,771,691],{"class":42},[36,773,774],{"class":42}," extern",[36,776,47],{"class":46},[36,778,650],{"class":42},[36,780,781],{"class":60}," add",[36,783,784],{"class":50},"(a",[36,786,67],{"class":42},[36,788,70],{"class":60},[36,790,791],{"class":50},", b",[36,793,67],{"class":42},[36,795,70],{"class":60},[36,797,73],{"class":50},[36,799,76],{"class":42},[36,801,70],{"class":60},[36,803,51],{"class":50},[36,805,806,809,812],{"class":38,"line":84},[36,807,808],{"class":50},"    a ",[36,810,811],{"class":42},"+",[36,813,814],{"class":50}," b\n",[36,816,817],{"class":38,"line":90},[36,818,87],{"class":50},[161,820,821,831],{},[164,822,823,826,827,830],{},[33,824,825],{},"#[no_mangle]",": keep the symbol name exactly ",[33,828,829],{},"add"," (don't mangle).",[164,832,833,836],{},[33,834,835],{},"pub extern \"C\"",": export with C ABI.",[14,838,839],{},"Build as a static or dynamic library:",[23,841,842],{"language":305},[27,843,845],{"className":308,"code":844,"language":305,"meta":31,"style":31},"[lib]\ncrate-type = [\"staticlib\", \"cdylib\", \"rlib\"]\n",[33,846,847,852],{"__ignoreMap":31},[36,848,849],{"class":38,"line":39},[36,850,851],{},"[lib]\n",[36,853,854],{"class":38,"line":54},[36,855,856],{},"crate-type = [\"staticlib\", \"cdylib\", \"rlib\"]\n",[161,858,859,872,887],{},[164,860,861,864,865,747,868,871],{},[33,862,863],{},"staticlib",": ",[33,866,867],{},".a",[33,869,870],{},".lib"," static archive.",[164,873,874,864,877,747,880,747,883,886],{},[33,875,876],{},"cdylib",[33,878,879],{},".so",[33,881,882],{},".dylib",[33,884,885],{},".dll"," dynamic library.",[164,888,889,892],{},[33,890,891],{},"rlib",": Rust-specific (for other Rust crates).",[181,894,896],{"id":895},"c-header","C Header",[14,898,899,900,67],{},"Generate a header for C consumers with ",[33,901,902],{},"cbindgen",[23,904,906],{"language":905},"bash",[27,907,910],{"className":908,"code":909,"language":905,"meta":31,"style":31},"language-bash shiki shiki-themes github-light github-dark","cargo install cbindgen\ncbindgen --crate my_lib --output my_lib.h\n",[33,911,912,923],{"__ignoreMap":31},[36,913,914,917,920],{"class":38,"line":39},[36,915,916],{"class":60},"cargo",[36,918,919],{"class":46}," install",[36,921,922],{"class":46}," cbindgen\n",[36,924,925,927,930,933,936],{"class":38,"line":54},[36,926,902],{"class":60},[36,928,929],{"class":136}," --crate",[36,931,932],{"class":46}," my_lib",[36,934,935],{"class":136}," --output",[36,937,938],{"class":46}," my_lib.h\n",[18,940,942,943,945,946],{"id":941},"c-strings-cstring-and-cstr","C Strings: ",[33,944,750],{}," and ",[33,947,705],{},[23,949,950],{"language":25},[27,951,953],{"className":29,"code":952,"language":25,"meta":31,"style":31},"use std::ffi::{CString, CStr};\n\nlet c_string = CString::new(\"hello\").unwrap();\nlet ptr: *const u8 = c_string.as_ptr();    \u002F\u002F null-terminated\nlet cstr = unsafe { CStr::from_ptr(ptr) };\nlet rust_str = cstr.to_str().unwrap();\n",[33,954,955,981,985,1015,1044,1067],{"__ignoreMap":31},[36,956,957,959,961,963,966,968,971,973,976,978],{"class":38,"line":39},[36,958,342],{"class":42},[36,960,345],{"class":60},[36,962,348],{"class":42},[36,964,965],{"class":60},"ffi",[36,967,348],{"class":42},[36,969,970],{"class":50},"{",[36,972,750],{"class":60},[36,974,975],{"class":50},", ",[36,977,705],{"class":60},[36,979,980],{"class":50},"};\n",[36,982,983],{"class":38,"line":54},[36,984,94],{"emptyLinePlaceholder":93},[36,986,987,990,993,995,998,1000,1002,1004,1007,1009,1011,1013],{"class":38,"line":84},[36,988,989],{"class":42},"let",[36,991,992],{"class":50}," c_string ",[36,994,118],{"class":42},[36,996,997],{"class":60}," CString",[36,999,348],{"class":42},[36,1001,439],{"class":60},[36,1003,130],{"class":50},[36,1005,1006],{"class":46},"\"hello\"",[36,1008,521],{"class":50},[36,1010,524],{"class":42},[36,1012,527],{"class":60},[36,1014,564],{"class":50},[36,1016,1017,1019,1022,1024,1026,1028,1031,1034,1036,1038,1041],{"class":38,"line":90},[36,1018,989],{"class":42},[36,1020,1021],{"class":50}," ptr",[36,1023,67],{"class":42},[36,1025,661],{"class":42},[36,1027,664],{"class":60},[36,1029,1030],{"class":42}," =",[36,1032,1033],{"class":50}," c_string",[36,1035,524],{"class":42},[36,1037,735],{"class":60},[36,1039,1040],{"class":50},"();    ",[36,1042,1043],{"class":206},"\u002F\u002F null-terminated\n",[36,1045,1046,1048,1051,1053,1055,1057,1059,1061,1064],{"class":38,"line":97},[36,1047,989],{"class":42},[36,1049,1050],{"class":50}," cstr ",[36,1052,118],{"class":42},[36,1054,121],{"class":42},[36,1056,124],{"class":50},[36,1058,705],{"class":60},[36,1060,348],{"class":42},[36,1062,1063],{"class":60},"from_ptr",[36,1065,1066],{"class":50},"(ptr) };\n",[36,1068,1069,1071,1074,1076,1079,1081,1084,1087,1089,1091],{"class":38,"line":109},[36,1070,989],{"class":42},[36,1072,1073],{"class":50}," rust_str ",[36,1075,118],{"class":42},[36,1077,1078],{"class":50}," cstr",[36,1080,524],{"class":42},[36,1082,1083],{"class":60},"to_str",[36,1085,1086],{"class":50},"()",[36,1088,524],{"class":42},[36,1090,527],{"class":60},[36,1092,564],{"class":50},[161,1094,1095,1104],{},[164,1096,1097,1099,1100,1103],{},[33,1098,750],{},": owned, null-terminated; can't contain interior NUL bytes (constructor returns ",[33,1101,1102],{},"Result",").",[164,1105,1106,1108,1109,1111,1112,524],{},[33,1107,705],{},": borrowed, null-terminated; from ",[33,1110,1063],{}," (unsafe) or by deref of ",[33,1113,750],{},[18,1115,1117,1118,945,1121],{"id":1116},"os-strings-osstring-and-osstr","OS Strings: ",[33,1119,1120],{},"OsString",[33,1122,1123],{},"OsStr",[14,1125,1126],{},"For platform-native strings (file paths, env):",[23,1128,1129],{"language":25},[27,1130,1132],{"className":29,"code":1131,"language":25,"meta":31,"style":31},"use std::ffi::OsString;\nlet s: OsString = std::env::args_os().next().unwrap();\n",[33,1133,1134,1150],{"__ignoreMap":31},[36,1135,1136,1138,1140,1142,1144,1146,1148],{"class":38,"line":39},[36,1137,342],{"class":42},[36,1139,345],{"class":60},[36,1141,348],{"class":42},[36,1143,965],{"class":60},[36,1145,348],{"class":42},[36,1147,1120],{"class":60},[36,1149,81],{"class":50},[36,1151,1152,1154,1157,1159,1162,1164,1166,1168,1170,1172,1175,1177,1179,1182,1184,1186,1188],{"class":38,"line":54},[36,1153,989],{"class":42},[36,1155,1156],{"class":50}," s",[36,1158,67],{"class":42},[36,1160,1161],{"class":60}," OsString",[36,1163,1030],{"class":42},[36,1165,345],{"class":60},[36,1167,348],{"class":42},[36,1169,508],{"class":60},[36,1171,348],{"class":42},[36,1173,1174],{"class":60},"args_os",[36,1176,1086],{"class":50},[36,1178,524],{"class":42},[36,1180,1181],{"class":60},"next",[36,1183,1086],{"class":50},[36,1185,524],{"class":42},[36,1187,527],{"class":60},[36,1189,564],{"class":50},[161,1191,1192,1199],{},[164,1193,1194,747,1196,1198],{},[33,1195,1120],{},[33,1197,1123],{}," are the OS-native string equivalents.",[164,1200,1201,747,1203,1206],{},[33,1202,367],{},[33,1204,1205],{},"Path"," are wrappers for path semantics (cross-platform).",[18,1208,1210],{"id":1209},"memory-ownership-across-ffi","Memory Ownership Across FFI",[23,1212,1213],{"language":25},[27,1214,1216],{"className":29,"code":1215,"language":25,"meta":31,"style":31},"\u002F\u002F Rust allocates, C frees\n#[no_mangle]\npub extern \"C\" fn make_string() -> *mut u8 {\n    let s = CString::new(\"hello\").unwrap();\n    s.into_raw()      \u002F\u002F leaks ownership to C\n}\n\n\u002F\u002F C frees via this\n#[no_mangle]\npub extern \"C\" fn free_string(ptr: *mut u8) {\n    unsafe { let _ = CString::from_raw(ptr); }\n}\n",[33,1217,1218,1223,1227,1252,1279,1295,1299,1303,1308,1312,1337,1360],{"__ignoreMap":31},[36,1219,1220],{"class":38,"line":39},[36,1221,1222],{"class":206},"\u002F\u002F Rust allocates, C frees\n",[36,1224,1225],{"class":38,"line":54},[36,1226,767],{"class":50},[36,1228,1229,1231,1233,1235,1237,1240,1243,1245,1248,1250],{"class":38,"line":84},[36,1230,691],{"class":42},[36,1232,774],{"class":42},[36,1234,47],{"class":46},[36,1236,650],{"class":42},[36,1238,1239],{"class":60}," make_string",[36,1241,1242],{"class":50},"() ",[36,1244,76],{"class":42},[36,1246,1247],{"class":42}," *mut",[36,1249,664],{"class":60},[36,1251,51],{"class":50},[36,1253,1254,1256,1259,1261,1263,1265,1267,1269,1271,1273,1275,1277],{"class":38,"line":90},[36,1255,112],{"class":42},[36,1257,1258],{"class":50}," s ",[36,1260,118],{"class":42},[36,1262,997],{"class":60},[36,1264,348],{"class":42},[36,1266,439],{"class":60},[36,1268,130],{"class":50},[36,1270,1006],{"class":46},[36,1272,521],{"class":50},[36,1274,524],{"class":42},[36,1276,527],{"class":60},[36,1278,564],{"class":50},[36,1280,1281,1284,1286,1289,1292],{"class":38,"line":97},[36,1282,1283],{"class":50},"    s",[36,1285,524],{"class":42},[36,1287,1288],{"class":60},"into_raw",[36,1290,1291],{"class":50},"()      ",[36,1293,1294],{"class":206},"\u002F\u002F leaks ownership to C\n",[36,1296,1297],{"class":38,"line":109},[36,1298,87],{"class":50},[36,1300,1301],{"class":38,"line":143},[36,1302,94],{"emptyLinePlaceholder":93},[36,1304,1305],{"class":38,"line":157},[36,1306,1307],{"class":206},"\u002F\u002F C frees via this\n",[36,1309,1310],{"class":38,"line":458},[36,1311,767],{"class":50},[36,1313,1314,1316,1318,1320,1322,1325,1328,1330,1332,1334],{"class":38,"line":468},[36,1315,691],{"class":42},[36,1317,774],{"class":42},[36,1319,47],{"class":46},[36,1321,650],{"class":42},[36,1323,1324],{"class":60}," free_string",[36,1326,1327],{"class":50},"(ptr",[36,1329,67],{"class":42},[36,1331,1247],{"class":42},[36,1333,664],{"class":60},[36,1335,1336],{"class":50},") {\n",[36,1338,1339,1341,1343,1345,1348,1350,1352,1354,1357],{"class":38,"line":483},[36,1340,718],{"class":42},[36,1342,124],{"class":50},[36,1344,989],{"class":42},[36,1346,1347],{"class":50}," _ ",[36,1349,118],{"class":42},[36,1351,997],{"class":60},[36,1353,348],{"class":42},[36,1355,1356],{"class":60},"from_raw",[36,1358,1359],{"class":50},"(ptr); }\n",[36,1361,1362],{"class":38,"line":488},[36,1363,87],{"class":50},[14,1365,1366,747,1369,1371],{},[33,1367,1368],{},"CString::into_raw",[33,1370,1356],{}," are the standard pattern for handing Rust strings to C and getting them back.",[181,1373,1375],{"id":1374},"c-allocates-rust-frees","C allocates, Rust frees",[14,1377,1378,1379,1382,1383,1386],{},"If C allocates with ",[33,1380,1381],{},"malloc",", Rust must call ",[33,1384,1385],{},"free"," (or the equivalent), not Rust's allocator. Provide a destructor function on the C side.",[181,1388,1390],{"id":1389},"common-pitfall-mismatched-allocators","Common Pitfall: Mismatched Allocators",[14,1392,1393,1394,747,1397,1400,1401,747,1403,1405],{},"Rust's ",[33,1395,1396],{},"Vec::push",[33,1398,1399],{},"String::push"," use Rust's allocator. C's ",[33,1402,1381],{},[33,1404,1385],{}," use the C library. Mixing them is UB. Always free with the allocator that allocated.",[18,1407,1409],{"id":1408},"structs-across-ffi","Structs Across FFI",[23,1411,1412],{"language":25},[27,1413,1415],{"className":29,"code":1414,"language":25,"meta":31,"style":31},"#[repr(C)]\nstruct Point {\n    x: f64,\n    y: f64,\n}\n\n#[no_mangle]\npub extern \"C\" fn translate(p: Point, dx: f64, dy: f64) -> Point {\n    Point { x: p.x + dx, y: p.y + dy }\n}\n",[33,1416,1417,1427,1437,1450,1461,1465,1469,1473,1515,1552],{"__ignoreMap":31},[36,1418,1419,1422,1425],{"class":38,"line":39},[36,1420,1421],{"class":50},"#[repr(",[36,1423,1424],{"class":60},"C",[36,1426,256],{"class":50},[36,1428,1429,1432,1435],{"class":38,"line":54},[36,1430,1431],{"class":42},"struct",[36,1433,1434],{"class":60}," Point",[36,1436,51],{"class":50},[36,1438,1439,1442,1444,1447],{"class":38,"line":84},[36,1440,1441],{"class":50},"    x",[36,1443,67],{"class":42},[36,1445,1446],{"class":60}," f64",[36,1448,1449],{"class":50},",\n",[36,1451,1452,1455,1457,1459],{"class":38,"line":90},[36,1453,1454],{"class":50},"    y",[36,1456,67],{"class":42},[36,1458,1446],{"class":60},[36,1460,1449],{"class":50},[36,1462,1463],{"class":38,"line":97},[36,1464,87],{"class":50},[36,1466,1467],{"class":38,"line":109},[36,1468,94],{"emptyLinePlaceholder":93},[36,1470,1471],{"class":38,"line":143},[36,1472,767],{"class":50},[36,1474,1475,1477,1479,1481,1483,1486,1489,1491,1493,1496,1498,1500,1503,1505,1507,1509,1511,1513],{"class":38,"line":157},[36,1476,691],{"class":42},[36,1478,774],{"class":42},[36,1480,47],{"class":46},[36,1482,650],{"class":42},[36,1484,1485],{"class":60}," translate",[36,1487,1488],{"class":50},"(p",[36,1490,67],{"class":42},[36,1492,1434],{"class":60},[36,1494,1495],{"class":50},", dx",[36,1497,67],{"class":42},[36,1499,1446],{"class":60},[36,1501,1502],{"class":50},", dy",[36,1504,67],{"class":42},[36,1506,1446],{"class":60},[36,1508,73],{"class":50},[36,1510,76],{"class":42},[36,1512,1434],{"class":60},[36,1514,51],{"class":50},[36,1516,1517,1520,1523,1525,1528,1530,1533,1535,1538,1540,1542,1544,1547,1549],{"class":38,"line":458},[36,1518,1519],{"class":60},"    Point",[36,1521,1522],{"class":50}," { x",[36,1524,67],{"class":42},[36,1526,1527],{"class":50}," p",[36,1529,524],{"class":42},[36,1531,1532],{"class":50},"x ",[36,1534,811],{"class":42},[36,1536,1537],{"class":50}," dx, y",[36,1539,67],{"class":42},[36,1541,1527],{"class":50},[36,1543,524],{"class":42},[36,1545,1546],{"class":50},"y ",[36,1548,811],{"class":42},[36,1550,1551],{"class":50}," dy }\n",[36,1553,1554],{"class":38,"line":468},[36,1555,87],{"class":50},[161,1557,1558,1564,1567],{},[164,1559,1560,1563],{},[33,1561,1562],{},"#[repr(C)]"," forces C-compatible layout (no Rust-specific reordering).",[164,1565,1566],{},"Field order matters and matches C's.",[164,1568,1569,1570,747,1573,1576,1577,1580],{},"Avoid ",[33,1571,1572],{},"Box\u003CT>",[33,1574,1575],{},"Vec\u003CT>"," in ",[33,1578,1579],{},"repr(C)"," structs (Rust-specific layout).",[181,1582,1584],{"id":1583},"opaque-types","Opaque Types",[14,1586,1587,1588,1591],{},"When C uses an opaque pointer (",[33,1589,1590],{},"typedef struct Foo Foo;","), use a zero-sized ZST:",[23,1593,1594],{"language":25},[27,1595,1597],{"className":29,"code":1596,"language":25,"meta":31,"style":31},"#[repr(C)]\npub struct Foo { _private: [u8; 0] }\n\nextern \"C\" {\n    pub fn foo_new() -> *mut Foo;\n    pub fn foo_free(f: *mut Foo);\n}\n",[33,1598,1599,1607,1637,1641,1649,1669,1689],{"__ignoreMap":31},[36,1600,1601,1603,1605],{"class":38,"line":39},[36,1602,1421],{"class":50},[36,1604,1424],{"class":60},[36,1606,256],{"class":50},[36,1608,1609,1611,1614,1617,1620,1622,1625,1628,1631,1634],{"class":38,"line":54},[36,1610,691],{"class":42},[36,1612,1613],{"class":42}," struct",[36,1615,1616],{"class":60}," Foo",[36,1618,1619],{"class":50}," { _private",[36,1621,67],{"class":42},[36,1623,1624],{"class":50}," [",[36,1626,1627],{"class":60},"u8",[36,1629,1630],{"class":50},"; ",[36,1632,1633],{"class":136},"0",[36,1635,1636],{"class":50},"] }\n",[36,1638,1639],{"class":38,"line":84},[36,1640,94],{"emptyLinePlaceholder":93},[36,1642,1643,1645,1647],{"class":38,"line":90},[36,1644,43],{"class":42},[36,1646,47],{"class":46},[36,1648,51],{"class":50},[36,1650,1651,1654,1656,1659,1661,1663,1665,1667],{"class":38,"line":97},[36,1652,1653],{"class":42},"    pub",[36,1655,650],{"class":42},[36,1657,1658],{"class":60}," foo_new",[36,1660,1242],{"class":50},[36,1662,76],{"class":42},[36,1664,1247],{"class":42},[36,1666,1616],{"class":60},[36,1668,81],{"class":50},[36,1670,1671,1673,1675,1678,1681,1683,1685,1687],{"class":38,"line":109},[36,1672,1653],{"class":42},[36,1674,650],{"class":42},[36,1676,1677],{"class":60}," foo_free",[36,1679,1680],{"class":50},"(f",[36,1682,67],{"class":42},[36,1684,1247],{"class":42},[36,1686,1616],{"class":60},[36,1688,154],{"class":50},[36,1690,1691],{"class":38,"line":143},[36,1692,87],{"class":50},[14,1694,1695,1698],{},[33,1696,1697],{},"[u8; 0]"," is the convention for opaque types.",[18,1700,1702],{"id":1701},"function-pointers","Function Pointers",[23,1704,1705],{"language":25},[27,1706,1708],{"className":29,"code":1707,"language":25,"meta":31,"style":31},"#[repr(C)]\nstruct Callbacks {\n    on_event: Option\u003Cextern \"C\" fn(data: *mut u8)>,\n}\n\nextern \"C\" fn my_callback(data: *mut u8) {\n    let s = unsafe { CStr::from_ptr(data as *const i8) };\n    println!(\"event: {:?}\", s);\n}\n",[33,1709,1710,1718,1727,1764,1768,1772,1793,1824,1836],{"__ignoreMap":31},[36,1711,1712,1714,1716],{"class":38,"line":39},[36,1713,1421],{"class":50},[36,1715,1424],{"class":60},[36,1717,256],{"class":50},[36,1719,1720,1722,1725],{"class":38,"line":54},[36,1721,1431],{"class":42},[36,1723,1724],{"class":60}," Callbacks",[36,1726,51],{"class":50},[36,1728,1729,1732,1734,1737,1740,1742,1745,1747,1750,1752,1755,1757,1759,1761],{"class":38,"line":84},[36,1730,1731],{"class":50},"    on_event",[36,1733,67],{"class":42},[36,1735,1736],{"class":60}," Option",[36,1738,1739],{"class":50},"\u003C",[36,1741,43],{"class":42},[36,1743,1744],{"class":50}," \"",[36,1746,1424],{"class":60},[36,1748,1749],{"class":50},"\" ",[36,1751,100],{"class":42},[36,1753,1754],{"class":50},"(data",[36,1756,67],{"class":42},[36,1758,1247],{"class":42},[36,1760,664],{"class":60},[36,1762,1763],{"class":50},")>,\n",[36,1765,1766],{"class":38,"line":90},[36,1767,87],{"class":50},[36,1769,1770],{"class":38,"line":97},[36,1771,94],{"emptyLinePlaceholder":93},[36,1773,1774,1776,1778,1780,1783,1785,1787,1789,1791],{"class":38,"line":109},[36,1775,43],{"class":42},[36,1777,47],{"class":46},[36,1779,650],{"class":42},[36,1781,1782],{"class":60}," my_callback",[36,1784,1754],{"class":50},[36,1786,67],{"class":42},[36,1788,1247],{"class":42},[36,1790,664],{"class":60},[36,1792,1336],{"class":50},[36,1794,1795,1797,1799,1801,1803,1805,1807,1809,1811,1814,1817,1819,1822],{"class":38,"line":143},[36,1796,112],{"class":42},[36,1798,1258],{"class":50},[36,1800,118],{"class":42},[36,1802,121],{"class":42},[36,1804,124],{"class":50},[36,1806,705],{"class":60},[36,1808,348],{"class":42},[36,1810,1063],{"class":60},[36,1812,1813],{"class":50},"(data ",[36,1815,1816],{"class":42},"as",[36,1818,661],{"class":42},[36,1820,1821],{"class":60}," i8",[36,1823,140],{"class":50},[36,1825,1826,1828,1830,1833],{"class":38,"line":157},[36,1827,146],{"class":60},[36,1829,130],{"class":50},[36,1831,1832],{"class":46},"\"event: {:?}\"",[36,1834,1835],{"class":50},", s);\n",[36,1837,1838],{"class":38,"line":458},[36,1839,87],{"class":50},[14,1841,1842,1843,1846,1847,1850],{},"C callbacks into Rust: store as ",[33,1844,1845],{},"Option\u003Cextern \"C\" fn(...)>",", pass ",[33,1848,1849],{},"my_callback as extern \"C\" fn(...)",", handle the user-data void pointer.",[18,1852,1854],{"id":1853},"panic-across-ffi-ub","Panic Across FFI — UB",[14,1856,1857],{},"Unwinding across an FFI boundary is UB. Solutions:",[161,1859,1860,1869],{},[164,1861,1862,1863,1576,1866,1868],{},"Set ",[33,1864,1865],{},"panic = \"abort\"",[33,1867,190],{}," (kills the process on panic).",[164,1870,1871,1872,1875],{},"Use ",[33,1873,1874],{},"std::panic::catch_unwind"," at the boundary and convert to a C error code.",[23,1877,1878],{"language":25},[27,1879,1881],{"className":29,"code":1880,"language":25,"meta":31,"style":31},"#[no_mangle]\npub extern \"C\" fn safe_call() -> i32 {\n    match std::panic::catch_unwind(|| risky_fn()) {\n        Ok(_) => 0,\n        Err(_) => -1,\n    }\n}\n",[33,1882,1883,1887,1908,1936,1952,1969,1973],{"__ignoreMap":31},[36,1884,1885],{"class":38,"line":39},[36,1886,767],{"class":50},[36,1888,1889,1891,1893,1895,1897,1900,1902,1904,1906],{"class":38,"line":54},[36,1890,691],{"class":42},[36,1892,774],{"class":42},[36,1894,47],{"class":46},[36,1896,650],{"class":42},[36,1898,1899],{"class":60}," safe_call",[36,1901,1242],{"class":50},[36,1903,76],{"class":42},[36,1905,70],{"class":60},[36,1907,51],{"class":50},[36,1909,1910,1913,1915,1917,1920,1922,1925,1927,1930,1933],{"class":38,"line":84},[36,1911,1912],{"class":42},"    match",[36,1914,345],{"class":60},[36,1916,348],{"class":42},[36,1918,1919],{"class":60},"panic",[36,1921,348],{"class":42},[36,1923,1924],{"class":60},"catch_unwind",[36,1926,130],{"class":50},[36,1928,1929],{"class":42},"||",[36,1931,1932],{"class":60}," risky_fn",[36,1934,1935],{"class":50},"()) {\n",[36,1937,1938,1941,1944,1947,1950],{"class":38,"line":90},[36,1939,1940],{"class":60},"        Ok",[36,1942,1943],{"class":50},"(_) ",[36,1945,1946],{"class":42},"=>",[36,1948,1949],{"class":136}," 0",[36,1951,1449],{"class":50},[36,1953,1954,1957,1959,1961,1964,1967],{"class":38,"line":97},[36,1955,1956],{"class":60},"        Err",[36,1958,1943],{"class":50},[36,1960,1946],{"class":42},[36,1962,1963],{"class":42}," -",[36,1965,1966],{"class":136},"1",[36,1968,1449],{"class":50},[36,1970,1971],{"class":38,"line":109},[36,1972,678],{"class":50},[36,1974,1975],{"class":38,"line":143},[36,1976,87],{"class":50},[18,1978,1980],{"id":1979},"calling-other-languages","Calling Other Languages",[181,1982,1984],{"id":1983},"python-pyo3","Python (PyO3)",[23,1986,1987],{"language":25},[27,1988,1990],{"className":29,"code":1989,"language":25,"meta":31,"style":31},"use pyo3::prelude::*;\n\n#[pyfunction]\nfn add(a: i64, b: i64) -> i64 { a + b }\n\n#[pymodule]\nfn my_module(_py: Python, m: &PyModule) -> PyResult\u003C()> {\n    m.add_function(wrap_pyfunction!(add, m)?)?;\n    Ok(())\n}\n",[33,1991,1992,2009,2013,2018,2051,2055,2060,2095,2122,2130],{"__ignoreMap":31},[36,1993,1994,1996,1999,2001,2004,2007],{"class":38,"line":39},[36,1995,342],{"class":42},[36,1997,1998],{"class":60}," pyo3",[36,2000,348],{"class":42},[36,2002,2003],{"class":60},"prelude",[36,2005,2006],{"class":42},"::*",[36,2008,81],{"class":50},[36,2010,2011],{"class":38,"line":54},[36,2012,94],{"emptyLinePlaceholder":93},[36,2014,2015],{"class":38,"line":84},[36,2016,2017],{"class":50},"#[pyfunction]\n",[36,2019,2020,2022,2024,2026,2028,2031,2033,2035,2037,2039,2041,2043,2046,2048],{"class":38,"line":90},[36,2021,100],{"class":42},[36,2023,781],{"class":60},[36,2025,784],{"class":50},[36,2027,67],{"class":42},[36,2029,2030],{"class":60}," i64",[36,2032,791],{"class":50},[36,2034,67],{"class":42},[36,2036,2030],{"class":60},[36,2038,73],{"class":50},[36,2040,76],{"class":42},[36,2042,2030],{"class":60},[36,2044,2045],{"class":50}," { a ",[36,2047,811],{"class":42},[36,2049,2050],{"class":50}," b }\n",[36,2052,2053],{"class":38,"line":97},[36,2054,94],{"emptyLinePlaceholder":93},[36,2056,2057],{"class":38,"line":109},[36,2058,2059],{"class":50},"#[pymodule]\n",[36,2061,2062,2064,2067,2070,2072,2075,2078,2080,2082,2085,2087,2089,2092],{"class":38,"line":143},[36,2063,100],{"class":42},[36,2065,2066],{"class":60}," my_module",[36,2068,2069],{"class":50},"(_py",[36,2071,67],{"class":42},[36,2073,2074],{"class":60}," Python",[36,2076,2077],{"class":50},", m",[36,2079,67],{"class":42},[36,2081,702],{"class":42},[36,2083,2084],{"class":60},"PyModule",[36,2086,73],{"class":50},[36,2088,76],{"class":42},[36,2090,2091],{"class":60}," PyResult",[36,2093,2094],{"class":50},"\u003C()> {\n",[36,2096,2097,2100,2102,2105,2107,2110,2113,2116,2118,2120],{"class":38,"line":157},[36,2098,2099],{"class":50},"    m",[36,2101,524],{"class":42},[36,2103,2104],{"class":60},"add_function",[36,2106,130],{"class":50},[36,2108,2109],{"class":60},"wrap_pyfunction!",[36,2111,2112],{"class":50},"(add, m)",[36,2114,2115],{"class":42},"?",[36,2117,521],{"class":50},[36,2119,2115],{"class":42},[36,2121,81],{"class":50},[36,2123,2124,2127],{"class":38,"line":458},[36,2125,2126],{"class":60},"    Ok",[36,2128,2129],{"class":50},"(())\n",[36,2131,2132],{"class":38,"line":468},[36,2133,87],{"class":50},[14,2135,2136,2137,2140],{},"Build with ",[33,2138,2139],{},"maturin develop",". PyO3 handles Python ABI.",[181,2142,2144,2145,521],{"id":2143},"nodejs-napi-rs","Node.js (",[33,2146,2147],{},"napi-rs",[23,2149,2150],{"language":25},[27,2151,2153],{"className":29,"code":2152,"language":25,"meta":31,"style":31},"#[napi]\npub fn add(a: i32, b: i32) -> i32 { a + b }\n",[33,2154,2155,2160],{"__ignoreMap":31},[36,2156,2157],{"class":38,"line":39},[36,2158,2159],{"class":50},"#[napi]\n",[36,2161,2162,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190],{"class":38,"line":54},[36,2163,691],{"class":42},[36,2165,650],{"class":42},[36,2167,781],{"class":60},[36,2169,784],{"class":50},[36,2171,67],{"class":42},[36,2173,70],{"class":60},[36,2175,791],{"class":50},[36,2177,67],{"class":42},[36,2179,70],{"class":60},[36,2181,73],{"class":50},[36,2183,76],{"class":42},[36,2185,70],{"class":60},[36,2187,2045],{"class":50},[36,2189,811],{"class":42},[36,2191,2050],{"class":50},[14,2193,2136,2194,524],{},[33,2195,2196],{},"napi build",[181,2198,2200],{"id":2199},"webassembly","WebAssembly",[23,2202,2203],{"language":905},[27,2204,2206],{"className":908,"code":2205,"language":905,"meta":31,"style":31},"rustup target add wasm32-unknown-unknown\ncargo build --target wasm32-unknown-unknown --release\n",[33,2207,2208,2221],{"__ignoreMap":31},[36,2209,2210,2213,2216,2218],{"class":38,"line":39},[36,2211,2212],{"class":60},"rustup",[36,2214,2215],{"class":46}," target",[36,2217,781],{"class":46},[36,2219,2220],{"class":46}," wasm32-unknown-unknown\n",[36,2222,2223,2225,2228,2231,2234],{"class":38,"line":54},[36,2224,916],{"class":60},[36,2226,2227],{"class":46}," build",[36,2229,2230],{"class":136}," --target",[36,2232,2233],{"class":46}," wasm32-unknown-unknown",[36,2235,2236],{"class":136}," --release\n",[14,2238,2239,2240,67],{},"For JS interop, use ",[33,2241,2242],{},"wasm-bindgen",[23,2244,2245],{"language":25},[27,2246,2248],{"className":29,"code":2247,"language":25,"meta":31,"style":31},"use wasm_bindgen::prelude::*;\n\n#[wasm_bindgen]\npub fn add(a: i32, b: i32) -> i32 { a + b }\n",[33,2249,2250,2265,2269,2274],{"__ignoreMap":31},[36,2251,2252,2254,2257,2259,2261,2263],{"class":38,"line":39},[36,2253,342],{"class":42},[36,2255,2256],{"class":60}," wasm_bindgen",[36,2258,348],{"class":42},[36,2260,2003],{"class":60},[36,2262,2006],{"class":42},[36,2264,81],{"class":50},[36,2266,2267],{"class":38,"line":54},[36,2268,94],{"emptyLinePlaceholder":93},[36,2270,2271],{"class":38,"line":84},[36,2272,2273],{"class":50},"#[wasm_bindgen]\n",[36,2275,2276,2278,2280,2282,2284,2286,2288,2290,2292,2294,2296,2298,2300,2302,2304],{"class":38,"line":90},[36,2277,691],{"class":42},[36,2279,650],{"class":42},[36,2281,781],{"class":60},[36,2283,784],{"class":50},[36,2285,67],{"class":42},[36,2287,70],{"class":60},[36,2289,791],{"class":50},[36,2291,67],{"class":42},[36,2293,70],{"class":60},[36,2295,73],{"class":50},[36,2297,76],{"class":42},[36,2299,70],{"class":60},[36,2301,2045],{"class":50},[36,2303,811],{"class":42},[36,2305,2050],{"class":50},[181,2307,2309,2310,521],{"id":2308},"c-cxx","C++ (",[33,2311,2312],{},"cxx",[14,2314,2315,2316,2318],{},"The ",[33,2317,2312],{}," crate provides safe bidirectional FFI:",[23,2320,2321],{"language":25},[27,2322,2324],{"className":29,"code":2323,"language":25,"meta":31,"style":31},"#[cxx::bridge]\nmod ffi {\n    extern \"C++\" {\n        include!(\"mylib.h\");\n        fn cpp_func(x: i32) -> i32;\n    }\n}\n",[33,2325,2326,2336,2345,2354,2366,2388,2392],{"__ignoreMap":31},[36,2327,2328,2331,2333],{"class":38,"line":39},[36,2329,2330],{"class":50},"#[cxx",[36,2332,348],{"class":42},[36,2334,2335],{"class":50},"bridge]\n",[36,2337,2338,2340,2343],{"class":38,"line":54},[36,2339,628],{"class":42},[36,2341,2342],{"class":60}," ffi",[36,2344,51],{"class":50},[36,2346,2347,2349,2352],{"class":38,"line":84},[36,2348,638],{"class":42},[36,2350,2351],{"class":46}," \"C++\"",[36,2353,51],{"class":50},[36,2355,2356,2359,2361,2364],{"class":38,"line":90},[36,2357,2358],{"class":60},"        include!",[36,2360,130],{"class":50},[36,2362,2363],{"class":46},"\"mylib.h\"",[36,2365,154],{"class":50},[36,2367,2368,2371,2374,2376,2378,2380,2382,2384,2386],{"class":38,"line":97},[36,2369,2370],{"class":42},"        fn",[36,2372,2373],{"class":60}," cpp_func",[36,2375,64],{"class":50},[36,2377,67],{"class":42},[36,2379,70],{"class":60},[36,2381,73],{"class":50},[36,2383,76],{"class":42},[36,2385,70],{"class":60},[36,2387,81],{"class":50},[36,2389,2390],{"class":38,"line":109},[36,2391,678],{"class":50},[36,2393,2394],{"class":38,"line":143},[36,2395,87],{"class":50},[14,2397,2398,2400],{},[33,2399,2312],{}," generates both sides; types are restricted to a safe subset.",[18,2402,2404,2406],{"id":2403},"extern-c-and-abis",[33,2405,168],{}," and ABIs",[14,2408,2409],{},"Common ABIs:",[161,2411,2412,2418,2424,2437],{},[164,2413,2414,2417],{},[33,2415,2416],{},"\"C\""," — System V \u002F cdecl depending on platform.",[164,2419,2420,2423],{},[33,2421,2422],{},"\"stdcall\""," — Windows x32.",[164,2425,2426,2429,2430,2433,2434,2436],{},[33,2427,2428],{},"\"system\""," — ",[33,2431,2432],{},"stdcall"," on Win32, ",[33,2435,2416],{}," on Win64.",[164,2438,2439,975,2442,2445],{},[33,2440,2441],{},"\"win64\"",[33,2443,2444],{},"\"sysv64\""," — explicit x64\u002FSysV.",[14,2447,2448,2449,2451],{},"Mismatched ABIs cause subtle corruption. Use ",[33,2450,295],{}," to get them right.",[18,2453,2455],{"id":2454},"build-scripts-for-ffi","Build Scripts for FFI",[23,2457,2458],{"language":25},[27,2459,2461],{"className":29,"code":2460,"language":25,"meta":31,"style":31},"\u002F\u002F build.rs\nfn main() {\n    cc::Build::new()\n        .file(\"src\u002Fc_code.c\")\n        .compile(\"my_c_code\");\n    println!(\"cargo:rerun-if-changed=src\u002Fc_code.c\");\n}\n",[33,2462,2463,2467,2475,2491,2505,2519,2530],{"__ignoreMap":31},[36,2464,2465],{"class":38,"line":39},[36,2466,207],{"class":206},[36,2468,2469,2471,2473],{"class":38,"line":54},[36,2470,100],{"class":42},[36,2472,103],{"class":60},[36,2474,106],{"class":50},[36,2476,2477,2480,2482,2485,2487,2489],{"class":38,"line":84},[36,2478,2479],{"class":60},"    cc",[36,2481,348],{"class":42},[36,2483,2484],{"class":60},"Build",[36,2486,348],{"class":42},[36,2488,439],{"class":60},[36,2490,406],{"class":50},[36,2492,2493,2495,2498,2500,2503],{"class":38,"line":90},[36,2494,411],{"class":42},[36,2496,2497],{"class":60},"file",[36,2499,130],{"class":50},[36,2501,2502],{"class":46},"\"src\u002Fc_code.c\"",[36,2504,422],{"class":50},[36,2506,2507,2509,2512,2514,2517],{"class":38,"line":97},[36,2508,411],{"class":42},[36,2510,2511],{"class":60},"compile",[36,2513,130],{"class":50},[36,2515,2516],{"class":46},"\"my_c_code\"",[36,2518,154],{"class":50},[36,2520,2521,2523,2525,2528],{"class":38,"line":109},[36,2522,146],{"class":60},[36,2524,130],{"class":50},[36,2526,2527],{"class":46},"\"cargo:rerun-if-changed=src\u002Fc_code.c\"",[36,2529,154],{"class":50},[36,2531,2532],{"class":38,"line":143},[36,2533,87],{"class":50},[14,2535,2536,2539,2540,2543],{},[33,2537,2538],{},"cc"," crate compiles C\u002FC++ as part of ",[33,2541,2542],{},"cargo build",". Add it as a build dependency:",[23,2545,2546],{"language":305},[27,2547,2549],{"className":308,"code":2548,"language":305,"meta":31,"style":31},"[build-dependencies]\ncc = \"1.0\"\n",[33,2550,2551,2555],{"__ignoreMap":31},[36,2552,2553],{"class":38,"line":39},[36,2554,321],{},[36,2556,2557],{"class":38,"line":54},[36,2558,2559],{},"cc = \"1.0\"\n",[18,2561,2563],{"id":2562},"common-pitfalls","Common Pitfalls",[161,2565,2566,2573,2581,2592,2598,2606,2619,2628,2634,2643],{},[164,2567,2568,2572],{},[2569,2570,2571],"strong",{},"Mismatched allocators",": UB; always free with the originating allocator.",[164,2574,2575,2578,2579,524],{},[2569,2576,2577],{},"Wrong ABI",": silent corruption; use ",[33,2580,295],{},[164,2582,2583,2586,2587,2589,2590,524],{},[2569,2584,2585],{},"Unwinding across FFI",": UB; use ",[33,2588,1924],{}," or ",[33,2591,1865],{},[164,2593,2594,2597],{},[2569,2595,2596],{},"Returning references to stack data",": classic UB; return owned or pass buffers in.",[164,2599,2600,2605],{},[2569,2601,2602,2604],{},[33,2603,1562],{}," missing",": Rust may reorder fields; mismatch with C struct.",[164,2607,2608,2611,2612,2614,2615,2618],{},[2569,2609,2610],{},"Nullable function pointers",": use ",[33,2613,1845],{}," so the ",[33,2616,2617],{},"None"," variant is a null pointer.",[164,2620,2621,2624,2625,2627],{},[2569,2622,2623],{},"Variadic FFI",": only ",[33,2626,168],{}," functions can be variadic.",[164,2629,2630,2633],{},[2569,2631,2632],{},"Thread-local state",": FFI calls into Rust from C threads don't have Rust's thread-local set up.",[164,2635,2636,2639,2640,2642],{},[2569,2637,2638],{},"String encoding",": C strings are NUL-terminated byte arrays; Rust strings are UTF-8. ",[33,2641,1123],{}," for paths.",[164,2644,2645,2650,2651,747,2654,524],{},[2569,2646,2647,2649],{},[33,2648,1572],{}," across FFI",": not stable layout; use raw pointers explicitly with ",[33,2652,2653],{},"Box::into_raw",[33,2655,1356],{},[18,2657,2659],{"id":2658},"useful-crates","Useful Crates",[161,2661,2662,2667,2672,2679,2684,2690,2695,2700,2706,2722],{},[164,2663,2664,2666],{},[33,2665,295],{},": auto-generate Rust bindings from C.",[164,2668,2669,2671],{},[33,2670,902],{},": generate C headers from Rust.",[164,2673,2674,2676,2677,524],{},[33,2675,2538],{},": compile C\u002FC++ in ",[33,2678,194],{},[164,2680,2681,2683],{},[33,2682,2312],{},": safe C++ interop.",[164,2685,2686,2689],{},[33,2687,2688],{},"pyo3",": Python bindings.",[164,2691,2692,2694],{},[33,2693,2147],{},": Node.js bindings.",[164,2696,2697,2699],{},[33,2698,2242],{},": JS\u002FWebAssembly bindings.",[164,2701,2702,2705],{},[33,2703,2704],{},"jni",": Java\u002FJVM bindings.",[164,2707,2708,2711,2712,975,2715,975,2718,2721],{},[33,2709,2710],{},"libc",": raw C types and constants (",[33,2713,2714],{},"c_int",[33,2716,2717],{},"c_char",[33,2719,2720],{},"size_t",", etc.).",[164,2723,2724,975,2727,975,2730,747,2733,2736],{},[33,2725,2726],{},"raw-cpuid",[33,2728,2729],{},"nix",[33,2731,2732],{},"winapi",[33,2734,2735],{},"windows-sys",": OS bindings.",[18,2738,2740],{"id":2739},"summary","Summary",[14,2742,2743,2745,2746,2749,2750,2752,2753,747,2755,747,2757,2759,2760,747,2762,747,2764,747,2766,2768],{},[33,2744,168],{}," declares FFI. ",[33,2747,2748],{},"#[no_mangle] pub extern \"C\" fn"," exports Rust to C. ",[33,2751,1562],{}," controls struct layout. Use ",[33,2754,295],{},[33,2756,902],{},[33,2758,2312],{}," for safe interop. Memory ownership must match allocators. Panics must not cross FFI. ",[33,2761,750],{},[33,2763,705],{},[33,2765,1120],{},[33,2767,1123],{}," for string interop. Wrap unsafe bindings in safe abstractions.",[14,2770,2771],{},"Next: Attributes and conditional compilation.",[2773,2774,2775],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}",{"title":31,"searchDepth":54,"depth":54,"links":2777},[2778,2784,2787,2789,2791,2795,2798,2799,2800,2808,2810,2811,2812,2813],{"id":20,"depth":54,"text":21,"children":2779},[2780,2781,2783],{"id":183,"depth":84,"text":184},{"id":292,"depth":84,"text":2782},"bindgen for Auto-Binding",{"id":612,"depth":84,"text":613},{"id":754,"depth":54,"text":755,"children":2785},[2786],{"id":895,"depth":84,"text":896},{"id":941,"depth":54,"text":2788},"C Strings: CString and CStr",{"id":1116,"depth":54,"text":2790},"OS Strings: OsString and OsStr",{"id":1209,"depth":54,"text":1210,"children":2792},[2793,2794],{"id":1374,"depth":84,"text":1375},{"id":1389,"depth":84,"text":1390},{"id":1408,"depth":54,"text":1409,"children":2796},[2797],{"id":1583,"depth":84,"text":1584},{"id":1701,"depth":54,"text":1702},{"id":1853,"depth":54,"text":1854},{"id":1979,"depth":54,"text":1980,"children":2801},[2802,2803,2805,2806],{"id":1983,"depth":84,"text":1984},{"id":2143,"depth":84,"text":2804},"Node.js (napi-rs)",{"id":2199,"depth":84,"text":2200},{"id":2308,"depth":84,"text":2807},"C++ (cxx)",{"id":2403,"depth":54,"text":2809},"extern \"C\" and ABIs",{"id":2454,"depth":54,"text":2455},{"id":2562,"depth":54,"text":2563},{"id":2658,"depth":54,"text":2659},{"id":2739,"depth":54,"text":2740},"md",{},"\u002Frust\u002F26-ffi",{"title":5,"description":16},"rust\u002F26-ffi","E_OZR_y0Z8TSlnqdfhI-PD9P0XezZDNNtQ6lvUA1MuQ",1785944093270]