├── flutter_package ├── example │ ├── linux │ │ ├── .gitignore │ │ ├── runner │ │ │ ├── main.cc │ │ │ ├── my_application.h │ │ │ └── CMakeLists.txt │ │ └── flutter │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ ├── ios │ │ ├── Runner │ │ │ ├── Runner-Bridging-Header.h │ │ │ ├── Assets.xcassets │ │ │ │ ├── LaunchImage.imageset │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ ├── README.md │ │ │ │ │ └── Contents.json │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj │ │ │ │ ├── Main.storyboard │ │ │ │ └── LaunchScreen.storyboard │ │ │ └── Info.plist │ │ ├── Flutter │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ └── AppFrameworkInfo.plist │ │ ├── Runner.xcodeproj │ │ │ └── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── RunnerTests │ │ │ └── RunnerTests.swift │ │ ├── .gitignore │ │ └── Podfile │ ├── web │ │ ├── favicon.png │ │ ├── icons │ │ │ ├── Icon-192.png │ │ │ ├── Icon-512.png │ │ │ ├── Icon-maskable-192.png │ │ │ └── Icon-maskable-512.png │ │ ├── manifest.json │ │ └── index.html │ ├── macos │ │ ├── Runner │ │ │ ├── Configs │ │ │ │ ├── Debug.xcconfig │ │ │ │ ├── Release.xcconfig │ │ │ │ ├── Warnings.xcconfig │ │ │ │ └── AppInfo.xcconfig │ │ │ ├── Assets.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── app_icon_16.png │ │ │ │ │ ├── app_icon_32.png │ │ │ │ │ ├── app_icon_64.png │ │ │ │ │ ├── app_icon_1024.png │ │ │ │ │ ├── app_icon_128.png │ │ │ │ │ ├── app_icon_256.png │ │ │ │ │ ├── app_icon_512.png │ │ │ │ │ └── Contents.json │ │ │ ├── Release.entitlements │ │ │ ├── AppDelegate.swift │ │ │ ├── DebugProfile.entitlements │ │ │ ├── MainFlutterWindow.swift │ │ │ └── Info.plist │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── Flutter-Debug.xcconfig │ │ │ ├── Flutter-Release.xcconfig │ │ │ └── GeneratedPluginRegistrant.swift │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── Runner.xcodeproj │ │ │ └── project.xcworkspace │ │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── RunnerTests │ │ │ └── RunnerTests.swift │ │ └── Podfile │ ├── windows │ │ ├── runner │ │ │ ├── resources │ │ │ │ └── app_icon.ico │ │ │ ├── resource.h │ │ │ ├── runner.exe.manifest │ │ │ ├── utils.h │ │ │ ├── flutter_window.h │ │ │ ├── main.cpp │ │ │ ├── CMakeLists.txt │ │ │ ├── utils.cpp │ │ │ └── flutter_window.cpp │ │ ├── flutter │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ │ └── .gitignore │ ├── android │ │ ├── app │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── drawable │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ ├── values │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ │ └── values-night │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── kotlin │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── example │ │ │ │ │ │ │ └── example_app │ │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── debug │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── profile │ │ │ │ │ └── AndroidManifest.xml │ │ │ └── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ └── settings.gradle.kts │ ├── native │ │ ├── hub │ │ │ ├── src │ │ │ │ ├── signals │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── fractal_art.rs │ │ │ │ │ ├── app_control.rs │ │ │ │ │ └── counter_number.rs │ │ │ │ ├── lib.rs │ │ │ │ └── actors │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── counting.rs │ │ │ └── Cargo.toml │ │ ├── sample_crate │ │ │ ├── src │ │ │ │ ├── lib.rs │ │ │ │ ├── error.rs │ │ │ │ └── extras.rs │ │ │ └── Cargo.toml │ │ └── README.md │ ├── pubspec.yaml │ ├── .gitignore │ ├── README.md │ ├── test │ │ └── complex_signal_test.dart │ └── .metadata ├── android │ ├── settings.gradle │ ├── src │ │ └── main │ │ │ └── AndroidManifest.xml │ ├── .gitignore │ └── build.gradle ├── lib │ ├── src │ │ ├── interface.dart │ │ ├── structure.dart │ │ ├── interface_web.dart │ │ ├── interface_os.dart │ │ └── load_web.dart │ └── rinf.dart ├── analysis_options.yaml ├── cargokit │ ├── build_tool │ │ ├── README.md │ │ ├── bin │ │ │ └── build_tool.dart │ │ ├── lib │ │ │ ├── build_tool.dart │ │ │ └── src │ │ │ │ ├── build_cmake.dart │ │ │ │ ├── logging.dart │ │ │ │ ├── cargo.dart │ │ │ │ ├── build_gradle.dart │ │ │ │ ├── environment.dart │ │ │ │ └── verify_binaries.dart │ │ ├── test │ │ │ ├── cargo_test.dart │ │ │ ├── builder_test.dart │ │ │ ├── rustup_test.dart │ │ │ └── options_test.dart │ │ ├── pubspec.yaml │ │ └── analysis_options.yaml │ ├── README │ ├── cmake │ │ └── resolve_symlinks.ps1 │ ├── .github │ │ └── workflows │ │ │ └── check_and_lint.yml │ ├── LICENSE │ ├── build_pod.sh │ └── run_build_tool.cmd ├── ios │ ├── Classes │ │ └── rinf.c │ └── rinf.podspec ├── macos │ ├── Classes │ │ └── rinf.c │ └── rinf.podspec ├── windows │ ├── .gitignore │ ├── rust.cmake │ └── CMakeLists.txt ├── elinux │ ├── rust.cmake │ └── CMakeLists.txt ├── linux │ ├── rust.cmake │ └── CMakeLists.txt ├── src │ ├── CMakeLists.txt │ ├── rinf.c │ └── rinf.h ├── LICENSE └── pubspec.yaml ├── .dockerignore ├── demo ├── __init__.py ├── server.py └── Dockerfile ├── documentation ├── __init__.py ├── source │ ├── __init__.py │ ├── _static │ │ ├── logo.png │ │ ├── preview.webp │ │ ├── rust_icon.png │ │ ├── rinf_design.png │ │ └── flutter_icon.svg │ ├── _templates │ │ ├── icon_pair.html │ │ └── landing.html │ ├── index.md │ ├── printing-for-debugging.md │ ├── field-types.md │ ├── contribution.md │ ├── installing-components.md │ ├── conf.py │ ├── field-attributes.md │ ├── introduction.md │ ├── configuration.md │ ├── unit-testing.md │ ├── applying-template.md │ ├── graceful-shutdown.md │ └── running-and-building.md ├── pyproject.toml ├── README.md ├── server.py └── Dockerfile ├── automate ├── __init__.py └── pyproject.toml ├── .rustfmt.toml ├── rust_crate_cli ├── src │ ├── lib.rs │ ├── bin │ │ └── main.rs │ └── tool │ │ ├── mod.rs │ │ ├── server.rs │ │ ├── common.rs │ │ └── config.rs ├── template │ ├── Cargo.toml.template │ └── native │ │ ├── README.md │ │ └── hub │ │ ├── src │ │ ├── signals │ │ │ └── mod.rs │ │ ├── lib.rs │ │ └── actors │ │ │ ├── second.rs │ │ │ ├── mod.rs │ │ │ └── first.rs │ │ └── Cargo.toml.template └── Cargo.toml ├── .vscode └── settings.json ├── compose.yaml ├── .github ├── pull_request_template.md ├── dependabot.yaml ├── ISSUE_TEMPLATE │ ├── task.md │ └── bug-report.md └── workflows │ ├── registry_push.yaml │ └── publication.yaml ├── Cargo.toml ├── pyproject.toml ├── rust_crate_proc └── Cargo.toml ├── .gitignore ├── rust_crate ├── src │ ├── traits.rs │ ├── lib.rs │ ├── error.rs │ ├── interface_web.rs │ ├── macros.rs │ └── interface.rs └── Cargo.toml └── LICENSE /flutter_package/example/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | **/target/ 3 | **/dist/ 4 | **/build/ 5 | -------------------------------------------------------------------------------- /demo/__init__.py: -------------------------------------------------------------------------------- 1 | """A demo web application made with Rinf.""" 2 | -------------------------------------------------------------------------------- /documentation/__init__.py: -------------------------------------------------------------------------------- 1 | """Documentation package for Rinf.""" 2 | -------------------------------------------------------------------------------- /automate/__init__.py: -------------------------------------------------------------------------------- 1 | """Automation package for Rinf project tasks.""" 2 | -------------------------------------------------------------------------------- /flutter_package/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rinf' 2 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | style_edition = "2024" 2 | max_width = 80 3 | tab_spaces = 2 4 | -------------------------------------------------------------------------------- /documentation/source/__init__.py: -------------------------------------------------------------------------------- 1 | """Documentation source files for Rinf.""" 2 | -------------------------------------------------------------------------------- /rust_crate_cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod tool; 2 | 3 | pub use tool::{SetupError, run_command}; 4 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /automate/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "automate" 3 | version = "0.1.0" 4 | requires-python = ">=3.13" 5 | -------------------------------------------------------------------------------- /documentation/source/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/documentation/source/_static/logo.png -------------------------------------------------------------------------------- /flutter_package/lib/src/interface.dart: -------------------------------------------------------------------------------- 1 | export 'interface_os.dart' if (dart.library.js_interop) 'interface_web.dart'; 2 | -------------------------------------------------------------------------------- /flutter_package/example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/web/favicon.png -------------------------------------------------------------------------------- /documentation/source/_static/preview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/documentation/source/_static/preview.webp -------------------------------------------------------------------------------- /documentation/source/_static/rust_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/documentation/source/_static/rust_icon.png -------------------------------------------------------------------------------- /documentation/source/_static/rinf_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/documentation/source/_static/rinf_design.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.linkedProjects": [ 3 | "./Cargo.toml", 4 | "./rust_crate_cli/Cargo.toml" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /flutter_package/example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /flutter_package/example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /flutter_package/example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /flutter_package/example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /flutter_package/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | linter: 4 | rules: 5 | prefer_single_quotes: true 6 | avoid_print: false 7 | -------------------------------------------------------------------------------- /flutter_package/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/README.md: -------------------------------------------------------------------------------- 1 | A sample command-line application with an entrypoint in `bin/`, library code 2 | in `lib/`, and example unit test in `test/`. 3 | -------------------------------------------------------------------------------- /flutter_package/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /flutter_package/ios/Classes/rinf.c: -------------------------------------------------------------------------------- 1 | // Relative import to be able to reuse the C sources. 2 | // See the comment in ../{projectName}}.podspec for more information. 3 | #include "../../src/rinf.c" 4 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_package/macos/Classes/rinf.c: -------------------------------------------------------------------------------- 1 | // Relative import to be able to reuse the C sources. 2 | // See the comment in ../{projectName}}.podspec for more information. 3 | #include "../../src/rinf.c" 4 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/bin/build_tool.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_tool/build_tool.dart' as build_tool; 2 | 3 | void main(List arguments) { 4 | build_tool.runMain(arguments); 5 | } 6 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/build_tool.dart: -------------------------------------------------------------------------------- 1 | import 'src/build_tool.dart' as build_tool; 2 | 3 | Future runMain(List args) async { 4 | return build_tool.runMain(args); 5 | } 6 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /flutter_package/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/kotlin/com/example/example_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example_app 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() 6 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cunarist/rinf/HEAD/flutter_package/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /flutter_package/example/linux/runner/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | 9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 10 | } 11 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/signals/mod.rs: -------------------------------------------------------------------------------- 1 | mod app_control; 2 | mod complex_types; 3 | mod counter_number; 4 | mod fractal_art; 5 | 6 | pub use app_control::*; 7 | pub use complex_types::*; 8 | pub use counter_number::*; 9 | pub use fractal_art::*; 10 | -------------------------------------------------------------------------------- /documentation/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "documentation" 3 | version = "0.1.0" 4 | requires-python = ">=3.13" 5 | dependencies = [ 6 | "Sphinx~=8.2.0", 7 | "furo~=2024.8.6", 8 | "myst-parser~=4.0.1", 9 | "sphinx-autobuild~=2024.10.3", 10 | ] 11 | -------------------------------------------------------------------------------- /flutter_package/example/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /rust_crate_cli/template/Cargo.toml.template: -------------------------------------------------------------------------------- 1 | # This file is used for telling Rust-related tools 2 | # where various Rust crates are. 3 | # This also unifies `target` output folder and 4 | # various Rust configurations. 5 | 6 | [workspace] 7 | resolver = "3" 8 | members = ["native/*"] 9 | -------------------------------------------------------------------------------- /flutter_package/example/windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void RegisterPlugins(flutter::PluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /flutter_package/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 6 | -------------------------------------------------------------------------------- /flutter_package/example/native/sample_crate/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate is written for Rinf demonstrations. 2 | 3 | mod error; 4 | mod extras; 5 | mod fractal; 6 | 7 | pub use extras::{fetch_from_web_api, get_current_time, get_hardward_id}; 8 | pub use fractal::{ImageInfo, draw_fractal_image}; 9 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | docs: 3 | image: registry.cunarist.org/rinf-docs:latest 4 | ports: 5 | - "${PORT}:80" 6 | restart: unless-stopped 7 | 8 | demo: 9 | image: registry.cunarist.org/rinf-demo:latest 10 | ports: 11 | - "${PORT_DEMO}:80" 12 | restart: unless-stopped 13 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /rust_crate_cli/src/bin/main.rs: -------------------------------------------------------------------------------- 1 | use std::process::ExitCode; 2 | 3 | fn main() -> ExitCode { 4 | use owo_colors::OwoColorize; 5 | let result = rinf_cli::run_command(); 6 | if let Err(err) = result { 7 | eprintln!("{}", format!("Error: {err}").red()); 8 | return ExitCode::FAILURE; 9 | }; 10 | ExitCode::SUCCESS 11 | } 12 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | .cxx/ 9 | 10 | # Remember to never publicly share your keystore. 11 | # See https://flutter.dev/to/reference-keystore 12 | key.properties 13 | **/*.keystore 14 | **/*.jks 15 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /flutter_package/cargokit/README: -------------------------------------------------------------------------------- 1 | Experimental repository to provide glue for seamlessly integrating cargo build 2 | with flutter plugins and packages. 3 | 4 | See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/ 5 | for a tutorial on how to use Cargokit. 6 | 7 | Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin. 8 | 9 | -------------------------------------------------------------------------------- /rust_crate_cli/src/tool/mod.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | mod config; 3 | mod entry; 4 | mod error; 5 | mod generate; 6 | mod server; 7 | mod template; 8 | mod webassembly; 9 | 10 | pub use common::*; 11 | pub use config::*; 12 | pub use entry::*; 13 | pub use error::*; 14 | pub use generate::*; 15 | pub use server::*; 16 | pub use template::*; 17 | pub use webassembly::*; 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Changes 2 | 3 | _Please mention issues fixed by this PR here, using format "Fixes #(Issue number)"._ 4 | 5 | ## Before Committing 6 | 7 | _Please make sure that you've analyzed and formatted the files._ 8 | 9 | ``` 10 | dart analyze flutter_package --fatal-infos 11 | dart format . 12 | cargo fmt 13 | cargo clippy --fix --allow-dirty 14 | ``` 15 | -------------------------------------------------------------------------------- /flutter_package/example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /flutter_package/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /flutter_package/example/macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /documentation/source/_templates/icon_pair.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | Flutter Icon 12 | Rust Icon 13 | -------------------------------------------------------------------------------- /flutter_package/example/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @main 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | 10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 11 | return true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. 6 | -------------------------------------------------------------------------------- /flutter_package/example/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/signals/fractal_art.rs: -------------------------------------------------------------------------------- 1 | use crate::signals::SampleSchema; 2 | use rinf::RustSignalBinary; 3 | use serde::Serialize; 4 | 5 | /// You can add your custom comments like this. 6 | /// The generated Dart classes will have the same comments on them. 7 | #[derive(Serialize, RustSignalBinary)] 8 | pub struct SampleFractal { 9 | pub current_scale: f64, 10 | pub dummy: Option, 11 | } 12 | -------------------------------------------------------------------------------- /flutter_package/example/windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /flutter_package/example/native/README.md: -------------------------------------------------------------------------------- 1 | # Rust Crates 2 | 3 | This folder contains Rust crates. Entry point of the Rust logic is the `hub` library crate. These crates are integrated and compiled into the Flutter app by the [Rinf](https://rinf.cunarist.org) framework. 4 | 5 | - Do NOT change the name of the `hub` crate. Compilation presets expect the entry library crate to be located at `native/hub`. 6 | - You CAN name crates other than `hub` as you want. 7 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/signals/app_control.rs: -------------------------------------------------------------------------------- 1 | use rinf::{DartSignal, RustSignal}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, DartSignal)] 5 | pub struct UnitTestStart; 6 | 7 | #[derive(Serialize, RustSignal)] 8 | pub struct UnitTestEnd; 9 | 10 | #[derive(Serialize, RustSignal)] 11 | pub struct ComplexSignalTestResult(pub bool); 12 | 13 | #[derive(Deserialize, DartSignal)] 14 | pub struct CreateActors; 15 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/README.md: -------------------------------------------------------------------------------- 1 | # Rust Crates 2 | 3 | This folder contains Rust crates. Entry point of the Rust logic is the `hub` library crate. These crates are integrated and compiled into the Flutter app by the [Rinf](https://rinf.cunarist.org) framework. 4 | 5 | - Do NOT change the name of the `hub` crate. Compilation presets expect the entry library crate to be located at `native/hub`. 6 | - You CAN name crates other than `hub` as you want. 7 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "3" 3 | # These can depend on each other. 4 | # We need to override `crates.io` to use local paths. 5 | members = ["flutter_package/example/native/*", "rust_crate", "rust_crate_proc"] 6 | # The binary crate doesn't have dependency relationship with others. 7 | # Also, it should have its own `Cargo.lock`. 8 | exclude = ["rust_crate_cli"] 9 | 10 | [patch.crates-io] 11 | rinf = { path = "rust_crate" } 12 | rinf_proc = { path = "rust_crate_proc" } 13 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pub 4 | directory: "flutter_package/" 5 | schedule: 6 | interval: daily 7 | - package-ecosystem: pub 8 | directory: "flutter_package/example/" 9 | schedule: 10 | interval: daily 11 | - package-ecosystem: cargo 12 | directory: "/" 13 | schedule: 14 | interval: daily 15 | - package-ecosystem: github-actions 16 | directory: "/" 17 | schedule: 18 | interval: daily 19 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @main 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /flutter_package/example/native/sample_crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sample_crate" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [lints.clippy] 7 | unwrap_used = "deny" 8 | expect_used = "deny" 9 | wildcard_imports = "deny" 10 | 11 | [target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies] 12 | machineid-rs = "1.2.4" 13 | 14 | [dependencies] 15 | chrono = "0.4.31" 16 | reqwest = { version = "0.12.1", default-features = false } 17 | image = "0.25.0" 18 | -------------------------------------------------------------------------------- /flutter_package/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example_app 2 | description: Demonstrates how to use the Rinf plugin 3 | publish_to: "none" 4 | 5 | version: 0.1.0 6 | 7 | environment: 8 | sdk: ">=3.8.0 <4.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | rinf: 14 | path: ../ 15 | cupertino_icons: ^1.0.8 16 | meta: ^1.15.0 17 | tuple: ^2.0.2 18 | 19 | dev_dependencies: 20 | flutter_lints: ^6.0.0 21 | test: ^1.25.15 22 | 23 | flutter: 24 | uses-material-design: true 25 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /flutter_package/example/linux/runner/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Write something to do for this project 4 | title: "" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | ## Current Status 10 | 11 | Provide a clear and concise description of what is currently missing. 12 | If this is a completely new idea, please leave a discussion instead of an issue. 13 | 14 | ## Describe the Task 15 | 16 | A clear and concise description of the improvements. 17 | 18 | ## Additional Context 19 | 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # Python scripts manage code and automate tests. 2 | # We avoid shell scripts because they are platform-dependent. 3 | # You can run the automation scripts with 4 | # `uv run automate [command_type]`. 5 | 6 | [dependency-groups] 7 | dev = ["ruff", "pyright"] 8 | 9 | [tool.uv.workspace] 10 | members = ["automate", "documentation"] 11 | 12 | [tool.ruff.lint] 13 | select = ["ALL"] 14 | ignore = ["TC", "BLE", "S602"] 15 | 16 | [tool.pyright] 17 | typeCheckingMode = "strict" 18 | 19 | [tool.ruff.lint.per-file-ignores] 20 | "documentation/**/*.py" = ["A001"] 21 | -------------------------------------------------------------------------------- /rust_crate_proc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rinf_proc" 3 | version = "8.8.1" 4 | edition = "2024" 5 | license = "MIT" 6 | description = "Rust for native business logic, Flutter for flexible and beautiful GUI" 7 | repository = "https://github.com/cunarist/rinf" 8 | documentation = "https://rinf.cunarist.org" 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [lints.clippy] 14 | unwrap_used = "deny" 15 | expect_used = "deny" 16 | wildcard_imports = "deny" 17 | 18 | [dependencies] 19 | syn = "2.0.98" 20 | quote = "1.0.38" 21 | heck = "0.5.0" 22 | proc-macro2 = "1.0.94" 23 | -------------------------------------------------------------------------------- /documentation/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | In order to preview and build this documentation, you need to have [uv](https://docs.astral.sh/uv/getting-started/installation/) installed on your system. 4 | 5 | Generate the static documentation files for publication on the web. 6 | 7 | ```shell 8 | uv run sphinx-build -M dirhtml source dist 9 | ``` 10 | 11 | Serve the built files locally. 12 | 13 | ```shell 14 | uv run python server.py 15 | ``` 16 | 17 | Automatically apply changes while writing. 18 | 19 | ```shell 20 | uv run sphinx-autobuild source dist --builder dirhtml 21 | ``` 22 | -------------------------------------------------------------------------------- /rust_crate_cli/src/tool/server.rs: -------------------------------------------------------------------------------- 1 | use crate::SetupError; 2 | use arboard::Clipboard; 3 | 4 | pub fn provide_server_command(release: bool) -> Result<(), SetupError> { 5 | let mut clipboard = Clipboard::new()?; 6 | let release_arg = if release { " --release" } else { "" }; 7 | let base_command = concat!( 8 | "flutter run", 9 | " --web-header=cross-origin-opener-policy=same-origin", 10 | " --web-header=cross-origin-embedder-policy=require-corp", 11 | ); 12 | let full_command = format!("{base_command}{release_arg}"); 13 | clipboard.set_text(full_command)?; 14 | Ok(()) 15 | } 16 | -------------------------------------------------------------------------------- /flutter_package/elinux/rust.cmake: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0079 NEW) 2 | apply_standard_settings(${BINARY_NAME}) 3 | 4 | set_target_properties( 5 | ${BINARY_NAME} PROPERTIES 6 | CXX_VISIBILITY_PRESET hidden 7 | BUILD_RPATH_USE_ORIGIN ON 8 | ) 9 | 10 | target_compile_definitions(${BINARY_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 11 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 12 | 13 | include("../cargokit/cmake/cargokit.cmake") 14 | apply_cargokit(${BINARY_NAME} ${CMAKE_SOURCE_DIR}/../native/hub hub "") 15 | 16 | set( 17 | rinf_bundled_libraries 18 | "${${BINARY_NAME}_cargokit_lib}" 19 | PARENT_SCOPE 20 | ) -------------------------------------------------------------------------------- /flutter_package/linux/rust.cmake: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0079 NEW) 2 | apply_standard_settings(${BINARY_NAME}) 3 | 4 | set_target_properties( 5 | ${BINARY_NAME} PROPERTIES 6 | CXX_VISIBILITY_PRESET hidden 7 | BUILD_RPATH_USE_ORIGIN ON 8 | ) 9 | 10 | target_compile_definitions(${BINARY_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 11 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 12 | 13 | include("../cargokit/cmake/cargokit.cmake") 14 | apply_cargokit(${BINARY_NAME} ${CMAKE_SOURCE_DIR}/../native/hub hub "") 15 | 16 | set( 17 | rinf_bundled_libraries 18 | "${${BINARY_NAME}_cargokit_lib}" 19 | PARENT_SCOPE 20 | ) -------------------------------------------------------------------------------- /flutter_package/windows/rust.cmake: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0079 NEW) 2 | apply_standard_settings(${BINARY_NAME}) 3 | 4 | set_target_properties( 5 | ${BINARY_NAME} PROPERTIES 6 | CXX_VISIBILITY_PRESET hidden 7 | BUILD_RPATH_USE_ORIGIN ON 8 | ) 9 | 10 | target_compile_definitions(${BINARY_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 11 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 12 | 13 | include("../cargokit/cmake/cargokit.cmake") 14 | apply_cargokit(${BINARY_NAME} ${CMAKE_SOURCE_DIR}/../native/hub hub "") 15 | 16 | set( 17 | rinf_bundled_libraries 18 | "${${BINARY_NAME}_cargokit_lib}" 19 | PARENT_SCOPE 20 | ) -------------------------------------------------------------------------------- /documentation/source/index.md: -------------------------------------------------------------------------------- 1 | ```{eval-rst} 2 | .. raw:: html 3 | :file: _templates/landing.html 4 | ``` 5 | 6 | ```{eval-rst} 7 | .. toctree:: 8 | :maxdepth: 1 9 | :hidden: 10 | 11 | introduction.md 12 | installing-components.md 13 | applying-template.md 14 | running-and-building.md 15 | messaging.md 16 | field-types.md 17 | field-attributes.md 18 | tutorial.md 19 | state-management.md 20 | error-handling.md 21 | printing-for-debugging.md 22 | graceful-shutdown.md 23 | configuration.md 24 | unit-testing.md 25 | upgrading.md 26 | frequently-asked-questions.md 27 | contribution.md 28 | ``` 29 | -------------------------------------------------------------------------------- /flutter_package/example/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() 9 | rootProject.layout.buildDirectory.value(newBuildDir) 10 | 11 | subprojects { 12 | val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) 13 | project.layout.buildDirectory.value(newSubprojectBuildDir) 14 | } 15 | subprojects { 16 | project.evaluationDependsOn(":app") 17 | } 18 | 19 | tasks.register("clean") { 20 | delete(rootProject.layout.buildDirectory) 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Flutter/Dart/Pub related 20 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 21 | /pubspec.lock 22 | **/doc/api/ 23 | .dart_tool/ 24 | .packages 25 | build/ 26 | 27 | # Rust related 28 | /.cargo/ 29 | target/ 30 | 31 | # Others 32 | *.lock 33 | !/rust_crate_cli/Cargo.lock 34 | .python-version 35 | /documentation/dist/ 36 | /documentation/*.egg-info/ 37 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/test/cargo_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_tool/src/cargo.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | final _cargoToml = """ 5 | [workspace] 6 | 7 | [profile.release] 8 | lto = true 9 | panic = "abort" 10 | opt-level = "z" 11 | # strip = "symbols" 12 | 13 | [package] 14 | name = "super_native_extensions" 15 | version = "0.1.0" 16 | edition = "2021" 17 | resolver = "2" 18 | 19 | [lib] 20 | crate-type = ["cdylib", "staticlib"] 21 | """; 22 | 23 | void main() { 24 | test('parseCargoToml', () { 25 | final info = CrateInfo.parseManifest(_cargoToml); 26 | expect(info.packageName, 'super_native_extensions'); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /rust_crate/src/traits.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{MutexGuard, PoisonError}; 2 | 3 | /// There is no panicking code in the Rinf crate. 4 | /// We assume that any mutex used here will never be poisoned. 5 | /// This trait handles the recovery from a logically poisoned situation, 6 | /// which is unlikely to occur. 7 | pub trait GuardRecovery<'a, T> { 8 | fn recover(self) -> MutexGuard<'a, T>; 9 | } 10 | 11 | impl<'a, T> GuardRecovery<'a, T> 12 | for Result, PoisonError>> 13 | { 14 | fn recover(self) -> MutexGuard<'a, T> { 15 | match self { 16 | Ok(inner) => inner, 17 | Err(poisoned) => poisoned.into_inner(), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flutter_package/example/native/sample_crate/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt::{Display, Formatter}; 3 | 4 | #[derive(Debug)] 5 | pub enum ExampleError { 6 | Fractal, 7 | HardwareId, 8 | WebApi, 9 | } 10 | 11 | impl Error for ExampleError {} 12 | 13 | impl Display for ExampleError { 14 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 15 | match self { 16 | Self::Fractal => { 17 | write!(f, "Failed to generate fractal") 18 | } 19 | Self::HardwareId => { 20 | write!(f, "Unable to retrieve hardware ID") 21 | } 22 | Self::WebApi => { 23 | write!(f, "Web API call failed") 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example_app 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.exampleApp 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /flutter_package/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have CMake 3.10 or later 2 | # installed. You should not increase this version, as doing so will cause 3 | # the plugin to fail to compile for some customers of the plugin. 4 | cmake_minimum_required(VERSION 3.10) 5 | 6 | project(rinf_library VERSION 0.0.1 LANGUAGES C) 7 | 8 | add_library(rinf SHARED 9 | "rinf.c" 10 | ) 11 | 12 | set_target_properties(rinf PROPERTIES 13 | PUBLIC_HEADER rinf.h 14 | OUTPUT_NAME "rinf" 15 | ) 16 | 17 | target_compile_definitions(rinf PUBLIC DART_SHARED_LIB) 18 | 19 | if (ANDROID) 20 | # Support Android 15 16k page size. 21 | target_link_options(rinf PRIVATE "-Wl,-z,max-page-size=16384") 22 | endif() 23 | -------------------------------------------------------------------------------- /documentation/source/printing-for-debugging.md: -------------------------------------------------------------------------------- 1 | # Printing for Debugging 2 | 3 | You might be used to `println!` macro in Rust. However, using that macro isn't a very good idea in our apps made with Flutter and Rust because `stdout` stream cannot be seen on the web and mobile emulators. 4 | 5 | When writing Rust code in the `hub` crate, you can simply print your debug message with the `debug_print!` macro provided by this framework like below. Once you use this macro, Flutter will take care of the rest. 6 | 7 | ```{code-block} rust 8 | :caption: Rust 9 | use rinf::debug_print; 10 | debug_print!("My object is {:?}", my_object); 11 | ``` 12 | 13 | `debug_print!` only writes the code in debug mode, resulting in a smaller and cleaner release binary. 14 | -------------------------------------------------------------------------------- /flutter_package/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/signals/counter_number.rs: -------------------------------------------------------------------------------- 1 | use rinf::{DartSignal, RustSignal, SignalPiece}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Deserialize, DartSignal)] 5 | pub struct SampleNumberInput { 6 | pub letter: String, 7 | pub _dummy_one: u32, 8 | pub _dummy_two: Option, 9 | pub _dummy_three: Vec, 10 | } 11 | 12 | #[derive(Serialize, RustSignal)] 13 | pub struct SampleNumberOutput { 14 | pub current_number: i32, 15 | pub dummy_one: u32, 16 | pub dummy_two: Option, 17 | pub dummy_three: Vec, 18 | } 19 | 20 | #[derive(Serialize, Deserialize, SignalPiece)] 21 | pub struct SampleSchema { 22 | pub sample_field_one: bool, 23 | pub sample_field_two: bool, 24 | } 25 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /rust_crate/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod channel; 2 | mod error; 3 | mod macros; 4 | mod shutdown; 5 | mod signal_trait; 6 | mod traits; 7 | 8 | mod interface; 9 | #[cfg(not(target_family = "wasm"))] 10 | mod interface_os; 11 | #[cfg(target_family = "wasm")] 12 | mod interface_web; 13 | 14 | pub use channel::{SignalReceiver, SignalSender, signal_channel}; 15 | pub use error::AppError; 16 | pub use interface::{DartSignalPack, send_rust_signal, start_rust_logic}; 17 | pub use shutdown::dart_shutdown; 18 | pub use signal_trait::{ 19 | DartSignal, DartSignalBinary, RustSignal, RustSignalBinary, SignalPiece, 20 | }; 21 | 22 | pub use rinf_proc::{ 23 | DartSignal, DartSignalBinary, RustSignal, RustSignalBinary, SignalPiece, 24 | }; 25 | 26 | #[doc(hidden)] 27 | pub use bincode::{deserialize, serialize}; 28 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/src/signals/mod.rs: -------------------------------------------------------------------------------- 1 | use rinf::{DartSignal, RustSignal, SignalPiece}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | /// To send data from Dart to Rust, use `DartSignal`. 5 | #[derive(Deserialize, DartSignal)] 6 | pub struct SmallText { 7 | pub text: String, 8 | } 9 | 10 | /// To send data from Rust to Dart, use `RustSignal`. 11 | #[derive(Serialize, RustSignal)] 12 | pub struct SmallNumber { 13 | pub number: i32, 14 | } 15 | 16 | /// A signal can be nested inside another signal. 17 | #[derive(Serialize, RustSignal)] 18 | pub struct BigBool { 19 | pub member: bool, 20 | pub nested: SmallBool, 21 | } 22 | 23 | /// To nest a signal inside other signal, use `SignalPiece`. 24 | #[derive(Serialize, SignalPiece)] 25 | pub struct SmallBool(pub bool); 26 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: build_tool 2 | description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build. 3 | publish_to: none 4 | version: 1.0.0 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | # Add regular dependencies here. 10 | dependencies: 11 | # these are pinned on purpose because the bundle_tool_runner doesn't have 12 | # pubspec.lock. See run_build_tool.sh 13 | logging: 1.2.0 14 | path: 1.8.0 15 | version: 3.0.0 16 | collection: 1.18.0 17 | ed25519_edwards: 0.3.1 18 | hex: 0.2.0 19 | yaml: 3.1.2 20 | source_span: 1.10.0 21 | github: 9.17.0 22 | args: 2.4.2 23 | crypto: 3.0.3 24 | convert: 3.1.1 25 | http: 1.1.0 26 | toml: 0.14.0 27 | 28 | dev_dependencies: 29 | lints: ^2.1.0 30 | test: ^1.24.0 31 | -------------------------------------------------------------------------------- /flutter_package/cargokit/cmake/resolve_symlinks.ps1: -------------------------------------------------------------------------------- 1 | function Resolve-Symlinks { 2 | [CmdletBinding()] 3 | [OutputType([string])] 4 | param( 5 | [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 6 | [string] $Path 7 | ) 8 | 9 | [string] $separator = '/' 10 | [string[]] $parts = $Path.Split($separator) 11 | 12 | [string] $realPath = '' 13 | foreach ($part in $parts) { 14 | if ($realPath -and !$realPath.EndsWith($separator)) { 15 | $realPath += $separator 16 | } 17 | $realPath += $part 18 | $item = Get-Item $realPath 19 | if ($item.Target) { 20 | $realPath = $item.Target.Replace('\', '/') 21 | } 22 | } 23 | $realPath 24 | } 25 | 26 | $path=Resolve-Symlinks -Path $args[0] 27 | Write-Host $path 28 | -------------------------------------------------------------------------------- /rust_crate/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt::{Display, Formatter}; 3 | 4 | #[derive(Debug)] 5 | pub enum AppError { 6 | NoDartIsolate, 7 | CannotEncodeMessage, 8 | CannotDecodeMessage, 9 | NoBindings, 10 | } 11 | 12 | impl Error for AppError {} 13 | 14 | impl Display for AppError { 15 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 16 | match self { 17 | Self::NoDartIsolate => { 18 | write!(f, "Dart isolate for Rust signals was not created") 19 | } 20 | Self::CannotDecodeMessage => { 21 | write!(f, "Could not decode the message") 22 | } 23 | Self::CannotEncodeMessage => { 24 | write!(f, "Could not encode the message") 25 | } 26 | Self::NoBindings => { 27 | write!(f, "Rinf bindings are not ready") 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | ## Describe the Bug 10 | 11 | A clear and concise description of what the bug is. 12 | If it's not a bug, please leave a discussion instead of an issue. 13 | 14 | ## To Reproduce 15 | 16 | Steps to reproduce the behavior: 17 | 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | ## Expected Behavior 24 | 25 | A clear and concise description of what you expected to happen. 26 | 27 | ## Screenshots 28 | 29 | If applicable, add screenshots to help explain your problem. 30 | 31 | ## Additional Context 32 | 33 | Output from the command below, shown in a Markdown code block. 34 | 35 | ```shell 36 | rustc --version 37 | flutter doctor 38 | ``` 39 | -------------------------------------------------------------------------------- /flutter_package/cargokit/.github/workflows/check_and_lint.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | branches: 5 | - main 6 | 7 | name: Check and Lint 8 | 9 | jobs: 10 | Flutter: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # 4.1.0 14 | - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # 2.16.0 15 | - name: Pub Get 16 | run: dart pub get --no-precompile 17 | working-directory: build_tool 18 | - name: Dart Format 19 | run: dart format . --output=none --set-exit-if-changed 20 | working-directory: build_tool 21 | - name: Analyze 22 | run: dart analyze 23 | working-directory: build_tool 24 | - name: Test 25 | run: flutter test 26 | working-directory: build_tool 27 | -------------------------------------------------------------------------------- /demo/server.py: -------------------------------------------------------------------------------- 1 | """Simple HTTP server with CORS headers for demo Rinf web app.""" 2 | 3 | from http.server import HTTPServer, SimpleHTTPRequestHandler 4 | from typing import override 5 | 6 | 7 | class RequestHandler(SimpleHTTPRequestHandler): 8 | """Request handler with CORS headers for SharedArrayBuffer support.""" 9 | 10 | @override 11 | def end_headers(self) -> None: 12 | """Add required headers for cross-origin isolation.""" 13 | self.send_header("cross-origin-opener-policy", "same-origin") 14 | self.send_header("cross-origin-embedder-policy", "require-corp") 15 | super().end_headers() 16 | 17 | 18 | def main() -> None: 19 | """Start the HTTP server for serving documentation files.""" 20 | address = ("", 80) 21 | HTTPServer(address, RequestHandler).serve_forever() 22 | 23 | 24 | if __name__ == "__main__": 25 | main() 26 | -------------------------------------------------------------------------------- /flutter_package/example/android/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | val flutterSdkPath = run { 3 | val properties = java.util.Properties() 4 | file("local.properties").inputStream().use { properties.load(it) } 5 | val flutterSdkPath = properties.getProperty("flutter.sdk") 6 | require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } 7 | flutterSdkPath 8 | } 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id("dev.flutter.flutter-plugin-loader") version "1.0.0" 21 | id("com.android.application") version "8.7.0" apply false 22 | id("org.jetbrains.kotlin.android") version "1.8.22" apply false 23 | } 24 | 25 | include(":app") 26 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This `hub` crate is the 2 | //! entry point of the Rust logic. 3 | 4 | mod actors; 5 | mod signals; 6 | 7 | use actors::create_actors; 8 | use rinf::{dart_shutdown, write_interface}; 9 | use tokio::spawn; 10 | 11 | // Uncomment below to target the web. 12 | // use tokio_with_wasm::alias as tokio; 13 | 14 | write_interface!(); 15 | 16 | // You can go with any async library, not just `tokio`. 17 | #[tokio::main(flavor = "current_thread")] 18 | async fn main() { 19 | // Spawn concurrent tasks. 20 | // Always use non-blocking async functions like `tokio::fs::File::open`. 21 | // If you must use blocking code, use `tokio::task::spawn_blocking` 22 | // or the equivalent provided by your async library. 23 | spawn(create_actors()); 24 | 25 | // Keep the main function running until Dart shutdown. 26 | dart_shutdown().await; 27 | } 28 | -------------------------------------------------------------------------------- /documentation/server.py: -------------------------------------------------------------------------------- 1 | """Simple HTTP server for serving documentation with CORS headers.""" 2 | 3 | import os 4 | from http.server import HTTPServer, SimpleHTTPRequestHandler 5 | from typing import override 6 | 7 | 8 | class RequestHandler(SimpleHTTPRequestHandler): 9 | """HTTP request handler with additional CORS headers for cross-origin isolation.""" 10 | 11 | @override 12 | def end_headers(self) -> None: 13 | self.send_header("cross-origin-opener-policy", "same-origin") 14 | self.send_header("cross-origin-embedder-policy", "require-corp") 15 | super().end_headers() 16 | 17 | 18 | def main() -> None: 19 | """Start the HTTP server for serving documentation files.""" 20 | os.chdir("dist/dirhtml") 21 | address = ("", 80) 22 | HTTPServer(address, RequestHandler).serve_forever() 23 | 24 | 25 | if __name__ == "__main__": 26 | main() 27 | -------------------------------------------------------------------------------- /flutter_package/example/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | rinf 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/Cargo.toml.template: -------------------------------------------------------------------------------- 1 | [package] 2 | # Do not change the name of this crate. 3 | name = "hub" 4 | version = "0.1.0" 5 | edition = "2024" 6 | 7 | [lib] 8 | # `lib` is required for non-library targets, 9 | # such as tests and benchmarks. 10 | # `cdylib` is for Linux, Android, Windows, and web. 11 | # `staticlib` is for iOS and macOS. 12 | crate-type = ["lib", "cdylib", "staticlib"] 13 | 14 | [lints.clippy] 15 | unwrap_used = "deny" 16 | expect_used = "deny" 17 | wildcard_imports = "deny" 18 | 19 | [dependencies] 20 | rinf = "8.8.1" 21 | serde = { version = "1.0.219", features = ["derive"] } 22 | tokio = { version = "1.45.0", features = ["rt", "macros", "time"] } 23 | async-trait = "0.1.87" 24 | messages = "0.3.1" 25 | 26 | # Uncomment below to target the web. 27 | # tokio_with_wasm = { version = "0.8.5", features = ["rt", "macros", "time"] } 28 | # wasm-bindgen = "0.2.100" 29 | -------------------------------------------------------------------------------- /flutter_package/example/windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | rinf 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This `hub` crate is the 2 | //! entry point of the Rust logic. 3 | 4 | mod actors; 5 | mod signals; 6 | mod testing; 7 | 8 | use actors::create_actors; 9 | 10 | use rinf::{dart_shutdown, write_interface}; 11 | use testing::run_unit_tests; 12 | use tokio::spawn; 13 | use tokio_with_wasm::alias as tokio; 14 | 15 | write_interface!(); 16 | 17 | // You can go with any async library, not just `tokio`. 18 | #[tokio::main(flavor = "current_thread")] 19 | async fn main() { 20 | // Spawn concurrent tasks. 21 | // Always use non-blocking async functions like `tokio::fs::File::open`. 22 | // If you must use blocking code, use `tokio::task::spawn_blocking` 23 | // or the equivalent provided by your async library. 24 | spawn(create_actors()); 25 | spawn(run_unit_tests()); 26 | 27 | // Keep the main function running until Dart shutdown. 28 | dart_shutdown().await; 29 | } 30 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_package/lib/src/structure.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | /// This type represents a function 4 | /// that can accept raw signal data from Rust 5 | /// and handle it accordingly. 6 | typedef AssignRustSignal = Map; 7 | 8 | /// This contains a message from Rust. 9 | /// Optionally, a custom binary called `binary` can also be included. 10 | class RustSignalPack { 11 | /// The message instance. 12 | final T message; 13 | 14 | /// Binary data included in the signal. 15 | /// This field is useful for sending custom bytes 16 | /// without the overhead of serialization/deserialization. 17 | final Uint8List binary; 18 | 19 | /// Constructs a packed data transfer object that includes 20 | /// the message and the binary data from Rust. 21 | /// This constructor is not intended for external use outside the library. 22 | RustSignalPack(this.message, this.binary); 23 | } 24 | -------------------------------------------------------------------------------- /flutter_package/src/rinf.c: -------------------------------------------------------------------------------- 1 | #include "rinf.h" 2 | 3 | // A very short-lived native function. 4 | // 5 | // For very short-lived functions, it is fine to call them on the main isolate. 6 | // They will block the Dart execution while running the native function, so 7 | // only do this for native functions which are guaranteed to be short-lived. 8 | FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b) { return a + b; } 9 | 10 | // A longer-lived native function, which occupies the thread calling it. 11 | // 12 | // Do not call these kind of native functions in the main isolate. They will 13 | // block Dart execution. This will cause dropped frames in Flutter applications. 14 | // Instead, call these native functions on a separate isolate. 15 | FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b) { 16 | // Simulate work. 17 | #if _WIN32 18 | Sleep(5000); 19 | #else 20 | usleep(5000 * 1000); 21 | #endif 22 | return a + b; 23 | } 24 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | # Do not change the name of this crate. 3 | name = "hub" 4 | version = "0.1.0" 5 | edition = "2024" 6 | 7 | [lib] 8 | # `lib` is required for non-library targets, 9 | # such as tests and benchmarks. 10 | # `cdylib` is for Linux, Android, Windows, and web. 11 | # `staticlib` is for iOS and macOS. 12 | crate-type = ["lib", "cdylib", "staticlib"] 13 | 14 | [lints.clippy] 15 | unwrap_used = "deny" 16 | expect_used = "deny" 17 | wildcard_imports = "deny" 18 | 19 | [dependencies] 20 | rinf = "8.8.1" 21 | serde = { version = "1.0.219", features = ["derive"] } 22 | tokio = { version = "1.45.0", features = ["rt", "sync", "time", "macros"] } 23 | tokio_with_wasm = { version = "0.8.5", features = [ 24 | "rt", 25 | "sync", 26 | "time", 27 | "macros", 28 | ] } 29 | wasm-bindgen = "0.2.100" 30 | async-trait = "0.1.87" 31 | messages = "0.3.1" 32 | anyhow = "1.0.89" 33 | sample_crate = { path = "../sample_crate" } 34 | -------------------------------------------------------------------------------- /rust_crate_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rinf_cli" 3 | version = "8.8.1" 4 | edition = "2024" 5 | license = "MIT" 6 | description = "Rust for native business logic, Flutter for flexible and beautiful GUI" 7 | repository = "https://github.com/cunarist/rinf" 8 | documentation = "https://rinf.cunarist.org" 9 | include = ["/src/", "/template/"] 10 | 11 | [[bin]] 12 | name = "rinf" 13 | path = "src/bin/main.rs" 14 | 15 | [lints.clippy] 16 | unwrap_used = "deny" 17 | expect_used = "deny" 18 | wildcard_imports = "deny" 19 | 20 | [target.'cfg(not(target_family = "wasm"))'.dependencies] 21 | serde = { version = "1.0.219", features = ["derive"] } 22 | clap = { version = "4.5.32", features = ["derive"] } 23 | owo-colors = "4.2.0" 24 | syn = { version = "2.0.98", features = ["full"] } 25 | quote = "1.0.38" 26 | serde_yml = "0.0.12" 27 | serde-reflection = "0.5.0" 28 | serde-generate = "0.32.0" 29 | include_dir = "0.7.4" 30 | heck = "0.5.0" 31 | arboard = "3.4.1" 32 | notify = "8.0.0" 33 | -------------------------------------------------------------------------------- /rust_crate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rinf" 3 | version = "8.8.1" 4 | edition = "2024" 5 | license = "MIT" 6 | description = "Rust for native business logic, Flutter for flexible and beautiful GUI" 7 | repository = "https://github.com/cunarist/rinf" 8 | documentation = "https://rinf.cunarist.org" 9 | rust-version = "1.85" 10 | 11 | [features] 12 | show-backtrace = ["backtrace"] 13 | bevy = ["bevy_ecs"] 14 | 15 | [lints.clippy] 16 | unwrap_used = "deny" 17 | expect_used = "deny" 18 | wildcard_imports = "deny" 19 | 20 | [dependencies] 21 | rinf_proc = { version = "8.8.1" } 22 | serde = "1.0.219" 23 | bincode = "1.3.3" 24 | bevy_ecs = { version = "0.17", optional = true } 25 | 26 | [target.'cfg(not(target_family = "wasm"))'.dependencies] 27 | allo-isolate = "0.1.26" 28 | os-thread-local = "0.1.3" 29 | backtrace = { version = "0.3.69", optional = true } 30 | 31 | [target.'cfg(target_family = "wasm")'.dependencies] 32 | js-sys = "0.3.77" 33 | wasm-bindgen = "0.2.100" 34 | wasm-bindgen-futures = "0.4.50" 35 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/src/actors/second.rs: -------------------------------------------------------------------------------- 1 | use crate::actors::FirstActor; 2 | use crate::signals::{BigBool, SmallBool}; 3 | use messages::prelude::{Actor, Address}; 4 | use rinf::debug_print; 5 | use std::time::Duration; 6 | use tokio::spawn; 7 | use tokio::time::sleep; 8 | 9 | // Uncomment below to target the web. 10 | // use tokio_with_wasm::alias as tokio; 11 | 12 | pub struct SecondActor {} 13 | 14 | impl Actor for SecondActor {} 15 | 16 | impl SecondActor { 17 | pub fn new(first_addr: Address) -> Self { 18 | spawn(Self::ask_first_actor(first_addr)); 19 | SecondActor {} 20 | } 21 | } 22 | 23 | impl SecondActor { 24 | async fn ask_first_actor(mut first_addr: Address) { 25 | sleep(Duration::from_secs(10)).await; 26 | let big_bool = BigBool { 27 | member: true, 28 | nested: SmallBool(true), 29 | }; 30 | if let Ok(response) = first_addr.send(big_bool).await { 31 | debug_print!("{}", response); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /documentation/source/field-types.md: -------------------------------------------------------------------------------- 1 | # Field Types 2 | 3 | Rinf uses Bincode serialization under the hood. It currently supports most of the standard types that Bincode does: 4 | 5 | - Signed Integers: `i8`, `i16`, `i32`, `i64`, `i128` 6 | - Unsigned Integers: `u8`, `u16`, `u32`, `u64`, `u128` 7 | - Floating-Point Numbers: `f32`, `f64` 8 | - Text: `char`, `String`, `&str` 9 | - Boolean: `bool` 10 | - Sequences: `[T; N]`, `Vec`, `HashSet`, `BTreeSet` 11 | - Maps: `HashMap`, `BTreeMap` 12 | - Standard Library Types: `Option`, `Box` 13 | - Tuple Types: `()` to `(T1, T2, T3, T4)` 14 | - C-style enums 15 | - Enums with inner data 16 | 17 | You can nest anything that implements `SignalPiece` inside a `RustSignal` or `DartSignal`. `Serialize` and `Deserialize` also have their own nesting rules. If there are no compile-time errors and the app builds successfully, you're good to go. 18 | 19 | To represent abstract data such as time, it’s recommended to use integer-based timestamps or simple primitives. 20 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/actors/mod.rs: -------------------------------------------------------------------------------- 1 | mod counting; 2 | mod performing; 3 | 4 | use crate::signals::CreateActors; 5 | use messages::prelude::Context; 6 | use performing::PerformingActor; 7 | use rinf::DartSignal; 8 | use tokio::spawn; 9 | use tokio_with_wasm::alias as tokio; 10 | 11 | pub use counting::*; 12 | 13 | /// Spawns the actors. 14 | pub async fn create_actors() { 15 | // Wait until the start signal arrives. 16 | let start_receiver = CreateActors::get_dart_signal_receiver(); 17 | start_receiver.recv().await; 18 | 19 | // Create actor contexts. 20 | let counting_context = Context::new(); 21 | let counting_addr = counting_context.address(); 22 | let performing_context = Context::new(); 23 | let performing_addr = performing_context.address(); 24 | 25 | // Spawn the actors. 26 | let counting_actor = CountingActor::new(counting_addr); 27 | spawn(counting_context.run(counting_actor)); 28 | let performing_actor = PerformingActor::new(performing_addr); 29 | spawn(performing_context.run(performing_actor)); 30 | } 31 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/test/builder_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_tool/src/builder.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | test('parseBuildConfiguration', () { 6 | var b = BuildEnvironment.parseBuildConfiguration('debug'); 7 | expect(b, BuildConfiguration.debug); 8 | 9 | b = BuildEnvironment.parseBuildConfiguration('profile'); 10 | expect(b, BuildConfiguration.profile); 11 | 12 | b = BuildEnvironment.parseBuildConfiguration('release'); 13 | expect(b, BuildConfiguration.release); 14 | 15 | b = BuildEnvironment.parseBuildConfiguration('debug-dev'); 16 | expect(b, BuildConfiguration.debug); 17 | 18 | b = BuildEnvironment.parseBuildConfiguration('profile'); 19 | expect(b, BuildConfiguration.profile); 20 | 21 | b = BuildEnvironment.parseBuildConfiguration('profile-prod'); 22 | expect(b, BuildConfiguration.profile); 23 | 24 | // fallback to release 25 | b = BuildEnvironment.parseBuildConfiguration('unknown'); 26 | expect(b, BuildConfiguration.release); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /flutter_package/src/rinf.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if _WIN32 6 | #include 7 | #else 8 | #include 9 | #include 10 | #endif 11 | 12 | #if _WIN32 13 | #define FFI_PLUGIN_EXPORT __declspec(dllexport) 14 | #else 15 | #define FFI_PLUGIN_EXPORT 16 | #endif 17 | 18 | // A very short-lived native function. 19 | // 20 | // For very short-lived functions, it is fine to call them on the main isolate. 21 | // They will block the Dart execution while running the native function, so 22 | // only do this for native functions which are guaranteed to be short-lived. 23 | FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b); 24 | 25 | // A longer lived native function, which occupies the thread calling it. 26 | // 27 | // Do not call these kind of native functions in the main isolate. They will 28 | // block Dart execution. This will cause dropped frames in Flutter applications. 29 | // Instead, call these native functions on a separate isolate. 30 | FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b); 31 | -------------------------------------------------------------------------------- /flutter_package/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .build/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | .swiftpm/ 13 | migrate_working_dir/ 14 | 15 | # IntelliJ related 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .idea/ 20 | 21 | # The .vscode folder contains launch configuration and tasks you configure in 22 | # VS Code which you may wish to be included in version control, so this line 23 | # is commented out by default. 24 | #.vscode/ 25 | 26 | # Flutter/Dart/Pub related 27 | **/doc/api/ 28 | **/ios/Flutter/.last_build_id 29 | .dart_tool/ 30 | .flutter-plugins 31 | .flutter-plugins-dependencies 32 | .packages 33 | .pub-cache/ 34 | .pub/ 35 | /build/ 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | 48 | # Rust related 49 | /.cargo/ 50 | /target/ 51 | 52 | # Generated signals 53 | /lib/src/bincode 54 | /lib/src/serde 55 | /lib/src/bindings 56 | -------------------------------------------------------------------------------- /flutter_package/example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example_app", 3 | "short_name": "example_app", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /flutter_package/example/linux/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} 10 | "main.cc" 11 | "my_application.cc" 12 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 13 | ) 14 | 15 | # Apply the standard set of build settings. This can be removed for applications 16 | # that need different build settings. 17 | apply_standard_settings(${BINARY_NAME}) 18 | 19 | # Add preprocessor definitions for the application ID. 20 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 21 | 22 | # Add dependency libraries. Add any application-specific dependencies here. 23 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 24 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 25 | 26 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 27 | -------------------------------------------------------------------------------- /flutter_package/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have CMake 3.10 or later 2 | # installed. You should not increase this version, as doing so will cause 3 | # the plugin to fail to compile for some customers of the plugin. 4 | cmake_minimum_required(VERSION 3.10) 5 | 6 | # Project-level configuration. 7 | set(PROJECT_NAME "rinf") 8 | project(${PROJECT_NAME} LANGUAGES CXX) 9 | 10 | # Invoke the build for native code shared with the other target platforms. 11 | # This can be changed to accommodate different builds. 12 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") 13 | 14 | # List of absolute paths to libraries that should be bundled with the plugin. 15 | # This list could contain prebuilt libraries, or libraries created by an 16 | # external build triggered from this build file. 17 | set(rinf_bundled_libraries 18 | # Defined in ../src/CMakeLists.txt. 19 | # This can be changed to accommodate different builds. 20 | $ 21 | PARENT_SCOPE 22 | ) 23 | 24 | # Include the CMake build file of the Rust code. 25 | include(./rust.cmake) -------------------------------------------------------------------------------- /flutter_package/elinux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have CMake 3.10 or later 2 | # installed. You should not increase this version, as doing so will cause 3 | # the plugin to fail to compile for some customers of the plugin. 4 | cmake_minimum_required(VERSION 3.10) 5 | 6 | # Project-level configuration. 7 | set(PROJECT_NAME "rinf") 8 | project(${PROJECT_NAME} LANGUAGES CXX) 9 | 10 | # Invoke the build for native code shared with the other target platforms. 11 | # This can be changed to accommodate different builds. 12 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") 13 | 14 | # List of absolute paths to libraries that should be bundled with the plugin. 15 | # This list could contain prebuilt libraries, or libraries created by an 16 | # external build triggered from this build file. 17 | set(rinf_bundled_libraries 18 | # Defined in ../src/CMakeLists.txt. 19 | # This can be changed to accommodate different builds. 20 | $ 21 | PARENT_SCOPE 22 | ) 23 | 24 | # Include the CMake build file of the Rust code. 25 | include(./rust.cmake) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Cunarist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /documentation/source/contribution.md: -------------------------------------------------------------------------------- 1 | # Contribution 2 | 3 | ## Contribution 4 | 5 | If Rinf has been helpful, please consider giving a star to our [GitHub repository](https://github.com/cunarist/rinf) and a like to our [Pub package](https://pub.dev/packages/rinf). You can also support us by spreading the word and sharing this framework online. 6 | 7 | We appreciate your contribution to the development of this project! We're always open to discussions and pull requests, so please do not hesitate to leave your ideas or opinions at our GitHub repository. 8 | 9 | [![GitHub contributors](https://contrib.rocks/image?repo=cunarist/rinf)](https://github.com/cunarist/rinf/graphs/contributors) 10 | 11 | ## Credits 12 | 13 | Rinf was not made alone. There were pioneers that gave inspiration to the structure of this package. Credits to these wonderful efforts! 14 | 15 | - https://github.com/irondash/cargokit 16 | - https://github.com/shekohex/allo-isolate 17 | - https://github.com/superlistapp/super_native_extensions 18 | - https://github.com/brickpop/flutter-rust-ffi 19 | - https://github.com/corrosion-rs/corrosion 20 | - https://github.com/fzyzcjy/flutter_rust_bridge 21 | -------------------------------------------------------------------------------- /flutter_package/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Cunarist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /documentation/source/installing-components.md: -------------------------------------------------------------------------------- 1 | # Installing Components 2 | 3 | [flutter-install-steps]: https://docs.flutter.dev/get-started/install 4 | 5 | To get started, you need to have [Flutter SDK][flutter-install-steps] and [Rust toolchain](https://www.rust-lang.org/tools/install) installed on your system. 6 | 7 | Once you're done with the installations, verify your system's readiness with the following commands. Make sure you have installed all the subcomponents that Flutter suggests. If there are no issues in the output, you are good to go onto the next step! 8 | 9 | ```{code-block} shell 10 | :caption: CLI 11 | rustc --version 12 | flutter doctor 13 | ``` 14 | 15 | ```{warning} 16 | If you're working on Linux, it is recommended to install Flutter manually. Do not install Flutter from `snap`. 17 | 18 | Flutter from `snap` comes with its own binary linker called `ld`, which is fundamentally incompatible with Rust. Instead, follow the [manual installation steps per the Flutter docs][flutter-install-steps]. 19 | 20 | Typically, the Flutter SDK package found in Debian-based Linux distributions' app store (under the name "Flutter") is a `snap` package. 21 | ``` 22 | -------------------------------------------------------------------------------- /flutter_package/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have a version of Visual Studio 2 | # installed that includes CMake 3.14 or later. You should not increase this 3 | # version, as doing so will cause the plugin to fail to compile for some 4 | # customers of the plugin. 5 | cmake_minimum_required(VERSION 3.14) 6 | 7 | # Project-level configuration. 8 | set(PROJECT_NAME "rinf") 9 | project(${PROJECT_NAME} LANGUAGES CXX) 10 | 11 | # Invoke the build for native code shared with the other target platforms. 12 | # This can be changed to accommodate different builds. 13 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared") 14 | 15 | # List of absolute paths to libraries that should be bundled with the plugin. 16 | # This list could contain prebuilt libraries, or libraries created by an 17 | # external build triggered from this build file. 18 | set(rinf_bundled_libraries 19 | # Defined in ../src/CMakeLists.txt. 20 | # This can be changed to accommodate different builds. 21 | $ 22 | PARENT_SCOPE 23 | ) 24 | 25 | # Include the CMake build file of the Rust code. 26 | include(./rust.cmake) -------------------------------------------------------------------------------- /documentation/source/conf.py: -------------------------------------------------------------------------------- 1 | """Configuration file for the Sphinx documentation builder.""" 2 | 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | project = "Rinf" 10 | copyright = "2025, Cunarist" 11 | author = "Cunarist" 12 | release = "8.8.1" 13 | 14 | # -- General configuration --------------------------------------------------- 15 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 16 | 17 | extensions = ["myst_parser"] 18 | source_suffix = {".md": "markdown"} 19 | templates_path = ["_templates"] 20 | exclude_patterns = [] 21 | 22 | # -- Options for HTML output ------------------------------------------------- 23 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 24 | 25 | html_theme = "furo" 26 | html_title = "Rinf" 27 | html_favicon = "_static/logo.png" 28 | html_static_path = ["_static"] 29 | html_show_sphinx = False 30 | html_show_sourcelink = False 31 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/build_cmake.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as path; 4 | 5 | import 'artifacts_provider.dart'; 6 | import 'builder.dart'; 7 | import 'environment.dart'; 8 | import 'options.dart'; 9 | import 'target.dart'; 10 | 11 | class BuildCMake { 12 | final CargokitUserOptions userOptions; 13 | 14 | BuildCMake({required this.userOptions}); 15 | 16 | Future build() async { 17 | final targetPlatform = Environment.targetPlatform; 18 | final target = Target.forFlutterName(Environment.targetPlatform); 19 | if (target == null) { 20 | throw Exception("Unknown target platform: $targetPlatform"); 21 | } 22 | 23 | final environment = BuildEnvironment.fromEnvironment(isAndroid: false); 24 | final provider = 25 | ArtifactProvider(environment: environment, userOptions: userOptions); 26 | final artifacts = await provider.getArtifacts([target]); 27 | 28 | final libs = artifacts[target]!; 29 | 30 | for (final lib in libs) { 31 | if (lib.type == AritifactType.dylib) { 32 | File(lib.path) 33 | .copySync(path.join(Environment.outputDir, lib.finalFileName)); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the static analysis results for your project (errors, 2 | # warnings, and lints). 3 | # 4 | # This enables the 'recommended' set of lints from `package:lints`. 5 | # This set helps identify many issues that may lead to problems when running 6 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 7 | # style and format. 8 | # 9 | # If you want a smaller set of lints you can change this to specify 10 | # 'package:lints/core.yaml'. These are just the most critical lints 11 | # (the recommended set includes the core lints). 12 | # The core lints are also what is used by pub.dev for scoring packages. 13 | 14 | include: package:lints/recommended.yaml 15 | 16 | # Uncomment the following section to specify additional rules. 17 | 18 | linter: 19 | rules: 20 | - prefer_relative_imports 21 | - directives_ordering 22 | # analyzer: 23 | # exclude: 24 | # - path/to/excluded/files/** 25 | 26 | # For more information about the core and recommended set of lints, see 27 | # https://dart.dev/go/core-lints 28 | 29 | # For additional information about configuring this file, see 30 | # https://dart.dev/guides/language/analysis-options 31 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/src/actors/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module contains actors. 2 | //! To build a solid app, avoid communicating by sharing memory. 3 | //! Focus on message passing instead. 4 | 5 | mod first; 6 | mod second; 7 | 8 | use first::FirstActor; 9 | use messages::prelude::Context; 10 | use second::SecondActor; 11 | use tokio::spawn; 12 | 13 | // Uncomment below to target the web. 14 | // use tokio_with_wasm::alias as tokio; 15 | 16 | /// Creates and spawns the actors in the async system. 17 | pub async fn create_actors() { 18 | // Though simple async tasks work, using the actor model 19 | // is highly recommended for state management 20 | // to achieve modularity and scalability in your app. 21 | // Actors keep ownership of their state and run in their own loops, 22 | // handling messages from other actors or external sources, 23 | // such as websockets or timers. 24 | 25 | // Create actor contexts. 26 | let first_context = Context::new(); 27 | let first_addr = first_context.address(); 28 | let second_context = Context::new(); 29 | 30 | // Spawn the actors. 31 | let first_actor = FirstActor::new(first_addr.clone()); 32 | spawn(first_context.run(first_actor)); 33 | let second_actor = SecondActor::new(first_addr); 34 | spawn(second_context.run(second_actor)); 35 | } 36 | -------------------------------------------------------------------------------- /flutter_package/example/README.md: -------------------------------------------------------------------------------- 1 | # Example App 2 | 3 | Demonstrates how to use the Rinf framework. 4 | 5 | ## Using Rust Inside Flutter 6 | 7 | This project leverages Flutter for GUI and Rust for the backend logic, 8 | utilizing the capabilities of the 9 | [Rinf](https://pub.dev/packages/rinf) framework. 10 | 11 | To run and build this app, you need to have 12 | [Flutter SDK](https://docs.flutter.dev/get-started/install) 13 | and [Rust toolchain](https://www.rust-lang.org/tools/install) 14 | installed on your system. 15 | You can check that your system is ready with the commands below. 16 | Note that all the Flutter subcomponents should be installed. 17 | 18 | ```shell 19 | rustc --version 20 | flutter doctor 21 | ``` 22 | 23 | You also need to have the CLI tool for Rinf ready. 24 | 25 | ```shell 26 | cargo install rinf_cli 27 | ``` 28 | 29 | Signals sent between Dart and Rust are implemented using signal attributes. 30 | If you've modified the signal structs, run the following command 31 | to generate the corresponding Dart classes: 32 | 33 | ```shell 34 | rinf gen 35 | ``` 36 | 37 | Now you can run and build this app just like any other Flutter projects. 38 | 39 | ```shell 40 | flutter run 41 | ``` 42 | 43 | For detailed instructions on writing Rust and Flutter together, 44 | please refer to Rinf's [documentation](https://rinf.cunarist.org). 45 | -------------------------------------------------------------------------------- /documentation/source/field-attributes.md: -------------------------------------------------------------------------------- 1 | # Field Attributes 2 | 3 | To ignore a field or variant, annotate it with `#[serde(skip)]`. This is useful when transferring partially private data because it allows you to specify which data is exposed to Dart. See Serde's documentation on [variant](https://serde.rs/variant-attrs.html) and [field](https://serde.rs/field-attrs.html) attributes for more information on how Serde handles this attribute. 4 | 5 | ```{code-block} rust 6 | :caption: Rust 7 | #[derive(Serialize, RustSignal)] 8 | struct UpdateMessage { 9 | event: String, 10 | struct_data: StructData, 11 | enum_data: EnumData, 12 | } 13 | 14 | #[derive(Serialize, SignalPiece)] 15 | struct StructData { 16 | my_public_field: bool, 17 | #[serde(skip)] 18 | my_private_field: bool, 19 | } 20 | 21 | #[derive(Serialize, SignalPiece)] 22 | enum EnumData { 23 | Variant1(i32, #[serde(skip)] i32), 24 | Variant2 { 25 | my_public_field: bool, 26 | #[serde(skip)] 27 | my_private_field: bool, 28 | }, 29 | } 30 | ``` 31 | 32 | Some attributes from Serde are banned at compile-time. This is because `rinf gen` analyzes Rust code statically by reading type annotations, and it cannot infer the type behind special Serde attributes like `#[serde(with = "...")]`. This mechanism ensures that `rinf gen` always produces exactly corresponding Dart code from Rust structs. 33 | -------------------------------------------------------------------------------- /flutter_package/example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | example_app 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/logging.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:logging/logging.dart'; 4 | 5 | const String kSeparator = "--"; 6 | const String kDoubleSeparator = "=="; 7 | 8 | bool _lastMessageWasSeparator = false; 9 | 10 | void _log(LogRecord rec) { 11 | final prefix = '${rec.level.name}: '; 12 | final out = rec.level == Level.SEVERE ? stderr : stdout; 13 | if (rec.message == kSeparator) { 14 | if (!_lastMessageWasSeparator) { 15 | out.write(prefix); 16 | out.writeln('-' * 80); 17 | _lastMessageWasSeparator = true; 18 | } 19 | return; 20 | } else if (rec.message == kDoubleSeparator) { 21 | out.write(prefix); 22 | out.writeln('=' * 80); 23 | _lastMessageWasSeparator = true; 24 | return; 25 | } 26 | out.write(prefix); 27 | out.writeln(rec.message); 28 | _lastMessageWasSeparator = false; 29 | } 30 | 31 | void initLogging() { 32 | Logger.root.level = Level.INFO; 33 | Logger.root.onRecord.listen((LogRecord rec) { 34 | final lines = rec.message.split('\n'); 35 | for (final line in lines) { 36 | if (line.isNotEmpty || lines.length == 1 || line != lines.last) { 37 | _log(LogRecord( 38 | rec.level, 39 | line, 40 | rec.loggerName, 41 | )); 42 | } 43 | } 44 | }); 45 | } 46 | 47 | void enableVerboseLogging() { 48 | Logger.root.level = Level.ALL; 49 | } 50 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("kotlin-android") 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id("dev.flutter.flutter-gradle-plugin") 6 | } 7 | 8 | android { 9 | namespace = "com.example.example_app" 10 | compileSdk = flutter.compileSdkVersion 11 | ndkVersion = "27.0.12077973" 12 | 13 | compileOptions { 14 | sourceCompatibility = JavaVersion.VERSION_11 15 | targetCompatibility = JavaVersion.VERSION_11 16 | } 17 | 18 | kotlinOptions { 19 | jvmTarget = JavaVersion.VERSION_11.toString() 20 | } 21 | 22 | defaultConfig { 23 | applicationId = "com.example.example_app" 24 | // You can update the following values to match your application needs. 25 | // For more information, see: https://flutter.dev/to/review-gradle-config. 26 | minSdk = flutter.minSdkVersion 27 | targetSdk = flutter.targetSdkVersion 28 | versionCode = flutter.versionCode 29 | versionName = flutter.versionName 30 | } 31 | 32 | buildTypes { 33 | release { 34 | // Signing with the debug keys for now, so `flutter run --release` works. 35 | signingConfig = signingConfigs.getByName("debug") 36 | } 37 | } 38 | } 39 | 40 | flutter { 41 | source = "../.." 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/registry_push.yaml: -------------------------------------------------------------------------------- 1 | # Build and push web apps to container registry 2 | name: Registry Push 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | build-and-push-demo: 9 | name: Build and Push Demo 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v6 15 | 16 | - name: Set up Docker Buildx 17 | uses: docker/setup-buildx-action@v3 18 | 19 | - name: Build and push demo image 20 | uses: docker/build-push-action@v6 21 | with: 22 | context: . 23 | file: ./demo/Dockerfile 24 | tags: registry.cunarist.org/rinf-demo:latest 25 | push: true 26 | cache-from: type=gha 27 | cache-to: type=gha,mode=max 28 | 29 | build-and-push-docs: 30 | name: Build and Push Docs 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - name: Checkout repository 35 | uses: actions/checkout@v6 36 | 37 | - name: Set up Docker Buildx 38 | uses: docker/setup-buildx-action@v3 39 | 40 | - name: Build and push documentation image 41 | uses: docker/build-push-action@v6 42 | with: 43 | context: . 44 | file: ./documentation/Dockerfile 45 | tags: registry.cunarist.org/rinf-docs:latest 46 | push: true 47 | cache-from: type=gha 48 | cache-to: type=gha,mode=max 49 | -------------------------------------------------------------------------------- /flutter_package/example/native/sample_crate/src/extras.rs: -------------------------------------------------------------------------------- 1 | //! This crate is written for Rinf demonstrations. 2 | 3 | use crate::error::ExampleError; 4 | 5 | // `machineid_rs` only supports desktop platforms. 6 | #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] 7 | pub fn get_hardward_id() -> Result { 8 | let mut builder = machineid_rs::IdBuilder::new(machineid_rs::Encryption::MD5); 9 | builder 10 | .add_component(machineid_rs::HWIDComponent::SystemID) 11 | .add_component(machineid_rs::HWIDComponent::CPUCores); 12 | let hwid = builder 13 | .build("mykey") 14 | .map_err(|_| ExampleError::HardwareId)?; 15 | Ok(hwid) 16 | } 17 | #[cfg(not(any( 18 | target_os = "windows", 19 | target_os = "macos", 20 | target_os = "linux" 21 | )))] 22 | pub fn get_hardward_id() -> Result { 23 | Ok(String::from("UNSUPPORTED")) 24 | } 25 | 26 | // `chrono` supports all platforms, including web. 27 | use chrono::{DateTime, offset}; 28 | pub fn get_current_time() -> DateTime { 29 | offset::Local::now() 30 | } 31 | 32 | // `reqwest` supports all platforms, including web. 33 | pub async fn fetch_from_web_api(url: &str) -> Result { 34 | let fetched = reqwest::get(url) 35 | .await 36 | .map_err(|_| ExampleError::WebApi)? 37 | .text() 38 | .await 39 | .map_err(|_| ExampleError::WebApi)?; 40 | Ok(fetched) 41 | } 42 | -------------------------------------------------------------------------------- /demo/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build Rinf example app for web 2 | FROM debian:bookworm-slim AS builder 3 | 4 | # Install dependencies 5 | RUN apt-get update && apt-get install -y \ 6 | curl git unzip xz-utils zip \ 7 | build-essential pkg-config libssl-dev 8 | 9 | # Install Flutter 10 | ENV FLUTTER_HOME=/opt/flutter 11 | ENV PATH="${FLUTTER_HOME}/bin:${PATH}" 12 | RUN git clone https://github.com/flutter/flutter.git -b stable ${FLUTTER_HOME} 13 | 14 | # Install Rust 15 | ENV RUSTUP_HOME=/usr/local/rustup 16 | ENV CARGO_HOME=/usr/local/cargo 17 | ENV PATH="/usr/local/cargo/bin:${PATH}" 18 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 19 | 20 | # Set working directory 21 | WORKDIR /workspace 22 | 23 | # Copy project files 24 | COPY flutter_package/ flutter_package/ 25 | COPY rust_crate/ rust_crate/ 26 | COPY rust_crate_proc/ rust_crate_proc/ 27 | COPY rust_crate_cli/ rust_crate_cli/ 28 | COPY Cargo.toml Cargo.toml 29 | 30 | # Install Rinf CLI from local source 31 | RUN cargo install --path rust_crate_cli 32 | 33 | # Build web app 34 | WORKDIR /workspace/flutter_package/example 35 | RUN rinf gen 36 | RUN rinf wasm --release 37 | RUN flutter build web --release 38 | 39 | # Serve the app 40 | FROM python:3.13-slim 41 | 42 | WORKDIR /app 43 | 44 | # Copy built web app 45 | COPY --from=builder /workspace/flutter_package/example/build/web . 46 | 47 | # Copy server script 48 | COPY demo/server.py . 49 | 50 | EXPOSE 80 51 | 52 | CMD ["python", "server.py"] 53 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/cargo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:path/path.dart' as path; 4 | import 'package:toml/toml.dart'; 5 | 6 | class ManifestException { 7 | ManifestException(this.message, {required this.fileName}); 8 | 9 | final String? fileName; 10 | final String message; 11 | 12 | @override 13 | String toString() { 14 | if (fileName != null) { 15 | return 'Failed to parse package manifest at $fileName: $message'; 16 | } else { 17 | return 'Failed to parse package manifest: $message'; 18 | } 19 | } 20 | } 21 | 22 | class CrateInfo { 23 | CrateInfo({required this.packageName}); 24 | 25 | final String packageName; 26 | 27 | static CrateInfo parseManifest(String manifest, {final String? fileName}) { 28 | final toml = TomlDocument.parse(manifest); 29 | final package = toml.toMap()['package']; 30 | if (package == null) { 31 | throw ManifestException('Missing package section', fileName: fileName); 32 | } 33 | final name = package['name']; 34 | if (name == null) { 35 | throw ManifestException('Missing package name', fileName: fileName); 36 | } 37 | return CrateInfo(packageName: name); 38 | } 39 | 40 | static CrateInfo load(String manifestDir) { 41 | final manifestFile = File(path.join(manifestDir, 'Cargo.toml')); 42 | final manifest = manifestFile.readAsStringSync(); 43 | return parseManifest(manifest, fileName: manifestFile.path); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"example_app", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /documentation/source/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## About Rinf 4 | 5 | Rinf enables building cross-platform Rust apps, combining it with Flutter's UI ecosystem. 6 | 7 | ```{eval-rst} 8 | .. raw:: html 9 | :file: _templates/icon_pair.html 10 | ``` 11 | 12 | ## Design 13 | 14 | Rinf expects the entire business logic to be written in Rust, with Flutter only serving as the UI layer.[^1] 15 | 16 | [^1]: If your business logic is written in Dart, Rinf may not be a suitable choice. Consider other solutions in such cases. 17 | 18 | ![Rinf design](_static/rinf_design.png) 19 | 20 | The communication system is made up of a two-way, stream-based message-passing mechanism instead of function calls. This decouples the business logic from the UI, ensuring a clear separation of concerns. 21 | 22 | It is recommended to use the actor model on the Rust side and tree-based state management techniques such as `InheritedWidget` or `provider` in Flutter for efficient state propagation. 23 | 24 | Actors in Rust should hold the state, while Flutter widgets receive only the view data needed to update the UI. 25 | 26 | ## Cross-Platform Compatibility 27 | 28 | Rinf enables seamless development across major platforms: 29 | 30 | - ✅ Linux: Tested and supported 31 | - ✅ Android: Tested and supported 32 | - ✅ Windows: Tested and supported 33 | - ✅ macOS: Tested and supported 34 | - ✅ iOS: Tested and supported 35 | - ✅ Web: Tested and supported 36 | - 🔄 [eLinux](https://github.com/sony/flutter-elinux): Currently experimental 37 | -------------------------------------------------------------------------------- /flutter_package/lib/src/interface_web.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_web_libraries_in_flutter 2 | 3 | import 'dart:async'; 4 | import 'dart:js_interop'; 5 | import 'dart:js_interop_unsafe'; 6 | import 'dart:typed_data'; 7 | import 'load_web.dart'; 8 | import 'structure.dart'; 9 | 10 | /// Sets the path to the JavaScript module 11 | /// that needs to be loaded. 12 | void setCompiledLibPathReal(String path) { 13 | setJsLibPath(path); 14 | } 15 | 16 | Future prepareInterfaceReal(AssignRustSignal assignRustSignal) async { 17 | // Load the JavaScript module. 18 | await loadJsFile(); 19 | 20 | // Listen to Rust via JavaScript. 21 | rinfBindingsObject['rinf_send_rust_signal_extern'] = 22 | ((String endpoint, JSObject messageBytesJS, JSObject binaryJS) { 23 | final messageBytes = (messageBytesJS as JSUint8Array).toDart; 24 | final binary = (binaryJS as JSUint8Array).toDart; 25 | assignRustSignal[endpoint]!(messageBytes, binary); 26 | }).toJS; 27 | } 28 | 29 | void startRustLogicReal() { 30 | if (wasAlreadyLoaded) { 31 | return; 32 | } 33 | wasmBindingsObject.callMethod('rinf_start_rust_logic_extern'.toJS); 34 | } 35 | 36 | void stopRustLogicReal() { 37 | // Dummy function to match the structure of native platforms. 38 | } 39 | 40 | void sendDartSignalReal( 41 | String endpointSymbol, 42 | Uint8List messageBytes, 43 | Uint8List binary, 44 | ) { 45 | wasmBindingsObject.callMethod( 46 | endpointSymbol.toJS, 47 | messageBytes.toJS, 48 | binary.toJS, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /rust_crate_cli/src/tool/common.rs: -------------------------------------------------------------------------------- 1 | use owo_colors::OwoColorize; 2 | 3 | use crate::SetupError; 4 | use std::ffi::OsStr; 5 | use std::net::ToSocketAddrs; 6 | use std::path::PathBuf; 7 | use std::process::Output; 8 | 9 | #[cfg(target_family = "windows")] 10 | pub static DART_BIN: &str = "dart.bat"; 11 | #[cfg(target_family = "unix")] 12 | pub static DART_BIN: &str = "dart"; 13 | 14 | pub fn check_internet_connection() -> bool { 15 | "pub.dev:80" 16 | .to_socket_addrs() 17 | .map(|mut addrs| addrs.next().is_some()) 18 | .unwrap_or(false) 19 | } 20 | 21 | #[macro_export] 22 | macro_rules! dimmedln { 23 | ($($arg:tt)*) => { 24 | println!("{}", owo_colors::OwoColorize::dimmed(&format!($($arg)*))); 25 | }; 26 | } 27 | 28 | pub trait CleanFileName { 29 | fn clean_file_name(&self) -> Result; 30 | } 31 | 32 | impl CleanFileName for PathBuf { 33 | fn clean_file_name(&self) -> Result { 34 | let file_name = self 35 | .file_name() 36 | .and_then(OsStr::to_str) 37 | .ok_or_else(|| SetupError::BadFilePath(self.to_owned()))? 38 | .to_owned(); 39 | Ok(file_name) 40 | } 41 | } 42 | 43 | pub trait CaptureError { 44 | fn capture_err(self) -> Result<(), SetupError>; 45 | } 46 | 47 | impl CaptureError for Output { 48 | fn capture_err(self) -> Result<(), SetupError> { 49 | if self.status.success() { 50 | Ok(()) 51 | } else { 52 | eprintln!("{}", String::from_utf8_lossy(&self.stderr).red()); 53 | Err(SetupError::SubprocessError) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/build_gradle.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:logging/logging.dart'; 4 | import 'package:path/path.dart' as path; 5 | 6 | import 'artifacts_provider.dart'; 7 | import 'builder.dart'; 8 | import 'environment.dart'; 9 | import 'options.dart'; 10 | import 'target.dart'; 11 | 12 | final log = Logger('build_gradle'); 13 | 14 | class BuildGradle { 15 | BuildGradle({required this.userOptions}); 16 | 17 | final CargokitUserOptions userOptions; 18 | 19 | Future build() async { 20 | final targets = Environment.targetPlatforms.map((arch) { 21 | final target = Target.forFlutterName(arch); 22 | if (target == null) { 23 | throw Exception( 24 | "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); 25 | } 26 | return target; 27 | }).toList(); 28 | 29 | final environment = BuildEnvironment.fromEnvironment(isAndroid: true); 30 | final provider = 31 | ArtifactProvider(environment: environment, userOptions: userOptions); 32 | final artifacts = await provider.getArtifacts(targets); 33 | 34 | for (final target in targets) { 35 | final libs = artifacts[target]!; 36 | final outputDir = path.join(Environment.outputDir, target.android!); 37 | Directory(outputDir).createSync(recursive: true); 38 | 39 | for (final lib in libs) { 40 | if (lib.type == AritifactType.dylib) { 41 | File(lib.path).copySync(path.join(outputDir, lib.finalFileName)); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.14' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | target 'RunnerTests' do 35 | inherit! :search_paths 36 | end 37 | end 38 | 39 | post_install do |installer| 40 | installer.pods_project.targets.each do |target| 41 | flutter_additional_macos_build_settings(target) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /flutter_package/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /documentation/source/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ## YAML File 4 | 5 | You can customize the behavior of Rinf CLI commands by configuring the `pubspec.yaml` file. All fields are optional and it's not necessary to write them. 6 | 7 | ```{code-block} yaml 8 | :caption: pubspec.yaml 9 | rinf: 10 | gen_input_crates: 11 | - hub 12 | gen_output_dir: lib/src/bindings 13 | ``` 14 | 15 | - `gen_input_crates`: A list of crate names under the `native` folder. The `rinf gen` command will search for signal structs in these crates. Each crate should be located directly under the `native` folder. 16 | - `gen_output_dir`: The directory where the generated Dart code will be placed by the `rinf gen` command. 17 | 18 | You can check the current configuration status by running the command below in the CLI. 19 | 20 | ```{code-block} shell 21 | :caption: CLI 22 | rinf config 23 | ``` 24 | 25 | ## Crate Features 26 | 27 | Customizing the behavior of the Rinf crate is possible through its crate features. 28 | 29 | ```{code-block} toml 30 | :caption: native/hub/Cargo.toml 31 | rinf = { version = "0.0.0", features = ["feature-name"] } 32 | ``` 33 | 34 | - `show-backtrace`: Prints the full backtrace in the CLI when a panic occurs in debug mode. In general, backtrace is not very helpful when debugging async apps, so consider using [`tracing`](https://crates.io/crates/tracing) for logging purposes. Note that this feature does not affect debugging on the web platform. 35 | - `bevy`: Implements the `Event` trait from `bevy_ecs` for `DartSignalPack`, allowing Bevy's entity component system to listen for events from Dart. This feature is highly experimental, and using it in production is not recommended. 36 | -------------------------------------------------------------------------------- /flutter_package/example/native/hub/src/actors/counting.rs: -------------------------------------------------------------------------------- 1 | use crate::signals::{SampleNumberInput, SampleNumberOutput}; 2 | use async_trait::async_trait; 3 | use messages::prelude::{Actor, Address, Context, Notifiable}; 4 | use rinf::{DartSignal, RustSignal, debug_print}; 5 | use tokio::task::JoinSet; 6 | use tokio_with_wasm::alias as tokio; 7 | 8 | /// The actor that holds the counter state. 9 | pub struct CountingActor { 10 | count: i32, 11 | _owned_tasks: JoinSet<()>, 12 | } 13 | 14 | impl Actor for CountingActor {} 15 | 16 | impl CountingActor { 17 | pub fn new(self_addr: Address) -> Self { 18 | let mut owned_tasks = JoinSet::new(); 19 | owned_tasks.spawn(Self::listen_to_button_click(self_addr)); 20 | CountingActor { 21 | count: 0, 22 | _owned_tasks: owned_tasks, 23 | } 24 | } 25 | 26 | async fn listen_to_button_click(mut self_addr: Address) { 27 | let receiver = SampleNumberInput::get_dart_signal_receiver(); 28 | while let Some(signal_pack) = receiver.recv().await { 29 | let message = signal_pack.message; 30 | let _ = self_addr.notify(message).await; 31 | } 32 | } 33 | } 34 | 35 | #[async_trait] 36 | impl Notifiable for CountingActor { 37 | async fn notify(&mut self, msg: SampleNumberInput, _: &Context) { 38 | // Increase the counter number. 39 | debug_print!("{}", msg.letter); 40 | self.count += 7; 41 | 42 | // The send method is generated on structs that derive `RustSignal`. 43 | SampleNumberOutput { 44 | current_number: self.count, 45 | dummy_one: 11, 46 | dummy_two: None, 47 | dummy_three: vec![22, 33, 44, 55], 48 | } 49 | .send_signal_to_dart(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /flutter_package/lib/rinf.dart: -------------------------------------------------------------------------------- 1 | /// This module supports communication with Rust. 2 | library; 3 | 4 | import 'dart:typed_data'; 5 | import 'dart:convert'; 6 | import 'src/structure.dart'; 7 | import 'src/interface.dart'; 8 | 9 | export 'src/structure.dart' show RustSignalPack; 10 | 11 | /// Starts the `main` function in Rust. 12 | Future initializeRust( 13 | AssignRustSignal assignRustSignal, { 14 | String? compiledLibPath, 15 | }) async { 16 | // Override the default library path if provided. 17 | if (compiledLibPath != null) { 18 | setCompiledLibPathReal(compiledLibPath); 19 | } 20 | 21 | // Add the print delegation endpoint. 22 | assignRustSignal['RinfOut'] = (messageBytes, binary) { 23 | final rustReport = utf8.decode(binary); 24 | print(rustReport); 25 | }; 26 | 27 | // Prepare the interface with Rust. 28 | await prepareInterfaceReal(assignRustSignal); 29 | startRustLogicReal(); 30 | } 31 | 32 | /// Terminates all Rust tasks by dropping the async runtime. 33 | /// This function very briefly blocks the Dart thread 34 | /// until the async runtime in Rust is completely dropped. 35 | /// It's recommended to call this before closing your Flutter app 36 | /// to prevent potential resource leaks from Rust. 37 | /// On the web, this function has no effect as tasks are managed by 38 | /// the JavaScript runtime rather than the Rust async runtime. 39 | void finalizeRust() { 40 | stopRustLogicReal(); 41 | } 42 | 43 | /// Sends a signal to Rust by using a symbol 44 | /// that exists inside local space of the loaded dynamic library. 45 | void sendDartSignal( 46 | String endpointSymbol, 47 | Uint8List messageBytes, 48 | Uint8List binary, 49 | ) { 50 | sendDartSignalReal(endpointSymbol, messageBytes, binary); 51 | } 52 | -------------------------------------------------------------------------------- /flutter_package/lib/src/interface_os.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ffi'; 2 | import 'dart:typed_data'; 3 | import 'dart:async'; 4 | import 'dart:isolate'; 5 | import 'load_os.dart'; 6 | import 'structure.dart'; 7 | 8 | /// Sets the exact file path of the dynamic library 9 | /// compiled from the `hub` crate. 10 | void setCompiledLibPathReal(String path) { 11 | overrideLibPath(path); 12 | } 13 | 14 | Future prepareInterfaceReal(AssignRustSignal assignRustSignal) async { 15 | // Prepare ports for communication over isolates. 16 | final rustSignalPort = ReceivePort(); 17 | 18 | // Listen to Rust via isolate port. 19 | rustSignalPort.listen((rustSignalRaw) { 20 | String endpoint = rustSignalRaw[0]; 21 | Uint8List? messageBytes = rustSignalRaw[1]; 22 | Uint8List? binary = rustSignalRaw[2]; 23 | 24 | // Rust will send null if the vector is empty. 25 | // Converting is needed on the Dart side. 26 | binary ??= Uint8List(0); 27 | // Rust will send null if the vector is empty. 28 | // Converting is needed on the Dart side. 29 | messageBytes ??= Uint8List(0); 30 | 31 | assignRustSignal[endpoint]!(messageBytes, binary); 32 | }); 33 | 34 | // Make Rust prepare its isolate to send data to Dart. 35 | // This is handled by `allo_isolate`. 36 | rustLibrary.prepareIsolate( 37 | NativeApi.postCObject, 38 | rustSignalPort.sendPort.nativePort, 39 | ); 40 | } 41 | 42 | void startRustLogicReal() { 43 | rustLibrary.startRustLogic(); 44 | } 45 | 46 | void stopRustLogicReal() { 47 | rustLibrary.stopRustLogic(); 48 | } 49 | 50 | void sendDartSignalReal( 51 | String endpointSymbol, 52 | Uint8List messageBytes, 53 | Uint8List binary, 54 | ) { 55 | rustLibrary.sendDartSignal(endpointSymbol, messageBytes, binary); 56 | } 57 | -------------------------------------------------------------------------------- /rust_crate/src/interface_web.rs: -------------------------------------------------------------------------------- 1 | use crate::AppError; 2 | use crate::shutdown::{SHUTDOWN_EVENTS, ShutdownEventsLock}; 3 | use js_sys::Uint8Array; 4 | use wasm_bindgen::prelude::{JsValue, wasm_bindgen}; 5 | 6 | // There is no shutdown mechanism on the web. 7 | static _SHUTDOWN_EVENTS: &ShutdownEventsLock = &SHUTDOWN_EVENTS; 8 | 9 | pub fn start_rust_logic_real(main_fn: F) -> Result<(), AppError> 10 | where 11 | F: Fn() -> T + 'static, 12 | { 13 | // Add kind description for panics. 14 | #[cfg(debug_assertions)] 15 | { 16 | use crate::debug_print; 17 | use std::panic::set_hook; 18 | set_hook(Box::new(|panic_info| { 19 | debug_print!("A panic occurred in Rust.\n{}", panic_info); 20 | })); 21 | } 22 | 23 | // Run the main function. 24 | main_fn(); 25 | 26 | Ok(()) 27 | } 28 | 29 | #[wasm_bindgen] 30 | extern "C" { 31 | // The reason this extern function is marked `catch` 32 | // and returns a `Result` is that the 33 | // `rinfBindings` JavaScript object created by Dart 34 | // does not exist in web workers; it is only available 35 | // in the main JavaScript thread. Loading the function 36 | // fails in web workers. 37 | #[wasm_bindgen(js_namespace = rinfBindings, catch)] 38 | pub fn rinf_send_rust_signal_extern( 39 | endpoint: &str, 40 | message_bytes: Uint8Array, 41 | binary: Uint8Array, 42 | ) -> Result<(), JsValue>; 43 | } 44 | 45 | pub fn send_rust_signal_real( 46 | endpoint: &str, 47 | message_bytes: Vec, 48 | binary: Vec, 49 | ) -> Result<(), AppError> { 50 | let result = rinf_send_rust_signal_extern( 51 | endpoint, 52 | Uint8Array::from(message_bytes.as_slice()), 53 | Uint8Array::from(binary.as_slice()), 54 | ); 55 | result.map_err(|_| AppError::NoBindings) 56 | } 57 | -------------------------------------------------------------------------------- /documentation/source/unit-testing.md: -------------------------------------------------------------------------------- 1 | # Unit Testing 2 | 3 | ## Pure Rust 4 | 5 | Writing tests that only involve the business logic of Rust is relatively simple: 6 | 7 | ```{code-block} rust 8 | :caption: Rust 9 | #[tokio::test] 10 | async fn my_async_test() { 11 | let result = async_function().await; 12 | assert_eq!(result, 42); 13 | } 14 | 15 | async fn async_function() -> i32 { 16 | 42 17 | } 18 | ``` 19 | 20 | ```{code-block} shell 21 | :caption: CLI 22 | cargo test 23 | ``` 24 | 25 | ## Dart and Rust 26 | 27 | Writing tests that pass signals between Dart and Rust requires a few extra lines of code. First, you need to build the `hub` crate so that it is located in the `target` directory, and then load the dynamic library. 28 | 29 | ```{code-block} dart 30 | :caption: test/custom_test.dart 31 | import 'dart:io'; 32 | import 'package:test/test.dart'; 33 | import 'package:rinf/rinf.dart'; 34 | import 'package:my_app/src/bindings/bindings.dart'; 35 | 36 | void main() async { 37 | // Build the dynamic library and load it. 38 | await Process.run('cargo', ['build'], runInShell: true); 39 | await initializeRust(assignRustSignal, compiledLibPath: getLibPath()); 40 | 41 | // Your test logic goes here. 42 | expect(42, 42); 43 | // ... 44 | } 45 | 46 | 47 | /// Gets the expected path of the dynamic library file. 48 | /// The path should reflect the project folder structure. 49 | String getLibPath() { 50 | if (Platform.isMacOS) { 51 | return 'target/debug/libhub.dylib'; 52 | } else if (Platform.isLinux) { 53 | return 'target/debug/libhub.so'; 54 | } else if (Platform.isWindows) { 55 | return 'target/debug/hub.dll'; 56 | } else { 57 | throw UnsupportedError('This operating system is not for tests'); 58 | } 59 | } 60 | ``` 61 | 62 | ```{code-block} shell 63 | :caption: CLI 64 | flutter test 65 | ``` 66 | -------------------------------------------------------------------------------- /rust_crate/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | /// Writes the interface code 3 | /// needed to communicate with Dart. 4 | /// This should be used once, and only once, 5 | /// at the root of the `hub` crate. 6 | macro_rules! write_interface { 7 | () => { 8 | #[cfg(not(target_family = "wasm"))] 9 | #[unsafe(no_mangle)] 10 | extern "C" fn rinf_start_rust_logic_extern() { 11 | use rinf::debug_print; 12 | let result = $crate::start_rust_logic(main); 13 | if let Err(err) = result { 14 | debug_print!("{}", err); 15 | } 16 | } 17 | 18 | #[cfg(target_family = "wasm")] 19 | #[wasm_bindgen::prelude::wasm_bindgen] 20 | pub fn rinf_start_rust_logic_extern() { 21 | use rinf::debug_print; 22 | let result = $crate::start_rust_logic(main); 23 | if let Err(err) = result { 24 | debug_print!("{}", err); 25 | } 26 | } 27 | }; 28 | } 29 | 30 | /// Delegates the printing operation to Flutter, 31 | /// which excels at handling various platforms 32 | /// including web and mobile emulators. 33 | /// When debugging, using this macro is recommended over `println!`, 34 | /// as it seamlessly adapts to different environments. 35 | /// Note that this macro does nothing in release mode. 36 | #[macro_export] 37 | macro_rules! debug_print { 38 | ( $( $t:tt )* ) => { 39 | { 40 | let rust_report = format!( $( $t )* ); 41 | #[cfg(debug_assertions)] 42 | { 43 | let result = $crate::send_rust_signal( 44 | "RinfOut", // Special message ID for Rust output 45 | Vec::new(), 46 | rust_report.clone().into_bytes(), 47 | ); 48 | if let Err(err) = result { 49 | println!("{}\n{}", err, rust_report); 50 | } 51 | } 52 | #[cfg(not(debug_assertions))] 53 | let _ = rust_report; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /documentation/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build Flutter web app 2 | FROM debian:bookworm-slim AS flutter-builder 3 | 4 | # Install dependencies 5 | RUN apt-get update 6 | RUN apt-get install -y \ 7 | curl git unzip xz-utils zip libglu1-mesa \ 8 | build-essential pkg-config libssl-dev 9 | 10 | # Install Flutter 11 | ENV FLUTTER_HOME=/opt/flutter 12 | ENV PATH="${FLUTTER_HOME}/bin:${PATH}" 13 | RUN git clone https://github.com/flutter/flutter.git -b stable ${FLUTTER_HOME} 14 | 15 | # Install Rust 16 | ENV RUSTUP_HOME=/usr/local/rustup 17 | ENV CARGO_HOME=/usr/local/cargo 18 | ENV PATH="/usr/local/cargo/bin:${PATH}" 19 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 20 | 21 | # Set working directory 22 | WORKDIR /workspace 23 | 24 | # Copy only essential files for building 25 | COPY flutter_package/ flutter_package/ 26 | COPY rust_crate/ rust_crate/ 27 | COPY rust_crate_proc/ rust_crate_proc/ 28 | COPY rust_crate_cli/ rust_crate_cli/ 29 | COPY Cargo.toml Cargo.toml 30 | 31 | # Install Rinf CLI from local source 32 | RUN cargo install --path rust_crate_cli 33 | 34 | # Build Flutter web app 35 | WORKDIR /workspace/flutter_package/example 36 | RUN rinf gen 37 | RUN rinf wasm --release 38 | RUN flutter build web --release --base-href="/_static/web_app/" 39 | 40 | # Build documentation and serve 41 | FROM python:3.13-slim 42 | 43 | # Set working directory 44 | WORKDIR /app 45 | 46 | # Copy documentation files 47 | COPY documentation/ . 48 | 49 | # Copy built web app from flutter-builder stage 50 | COPY --from=flutter-builder \ 51 | /workspace/flutter_package/example/build/web \ 52 | source/_static/web_app/ 53 | 54 | # Install dependencies 55 | RUN pip install --no-cache-dir . 56 | 57 | # Build documentation 58 | RUN sphinx-build -b dirhtml source dist/dirhtml 59 | 60 | # Expose port 80 61 | EXPOSE 80 62 | 63 | # Run the server 64 | CMD ["python", "server.py"] 65 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Example App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example_app 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /flutter_package/example/test/complex_signal_test.dart: -------------------------------------------------------------------------------- 1 | // Import the test package and Counter class 2 | import 'dart:io'; 3 | import 'package:test/test.dart'; 4 | import 'package:rinf/rinf.dart'; 5 | import 'package:example_app/src/bindings/bindings.dart'; 6 | 7 | Future main() async { 8 | // Build the dynamic library and load it. 9 | await Process.run('cargo', ['build'], runInShell: true); 10 | await initializeRust(assignRustSignal, compiledLibPath: getLibPath()); 11 | 12 | // Start the test mechanism in Rust. 13 | final duration = Duration(milliseconds: 100); 14 | UnitTestStart().sendSignalToRust(); 15 | await Future.delayed(duration); 16 | 17 | // Send signals of complex types back and forth. 18 | SerdeData.rustSignalStream.listen((signalPack) async { 19 | // Receive a signal from Rust and send it back. 20 | final serdeData = signalPack.message; 21 | serdeData.sendSignalToRust(); 22 | final resultPack = await ComplexSignalTestResult.rustSignalStream.first; 23 | test('Signals should remain the same', () { 24 | expect( 25 | resultPack.message.value, 26 | true, 27 | reason: 'Signal data is different from the original:\n$serdeData', 28 | ); 29 | }); 30 | }); 31 | 32 | // Wait for the test to be completed. 33 | await Future.delayed(duration); 34 | await UnitTestEnd.rustSignalStream.first; 35 | } 36 | 37 | /// Gets the expected path of the dynamic library file. 38 | /// The path should reflect the project folder structure. 39 | String getLibPath() { 40 | if (Platform.isMacOS) { 41 | return '../../target/debug/libhub.dylib'; 42 | } else if (Platform.isLinux) { 43 | return '../../target/debug/libhub.so'; 44 | } else if (Platform.isWindows) { 45 | return '../../target/debug/hub.dll'; 46 | } else { 47 | throw UnsupportedError('This operating system is not for tests'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /flutter_package/example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "d8a9f9a52e5af486f80d932e838ee93861ffd863" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 17 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 18 | - platform: android 19 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 20 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 21 | - platform: ios 22 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 23 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 24 | - platform: linux 25 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 26 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 27 | - platform: macos 28 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 29 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 30 | - platform: web 31 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 32 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 33 | - platform: windows 34 | create_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 35 | base_revision: d8a9f9a52e5af486f80d932e838ee93861ffd863 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /documentation/source/applying-template.md: -------------------------------------------------------------------------------- 1 | # Applying Rust Template 2 | 3 | ```{note} 4 | This section assumes that you've already created a Flutter project with `flutter create [my_app_name]`. You can get further guidance from [this awesome Flutter tutorial](https://docs.flutter.dev/get-started/codelab). 5 | ``` 6 | 7 | First of all, add this framework to your Flutter project. 8 | 9 | ```{code-block} shell 10 | :caption: CLI 11 | flutter pub add rinf 12 | ``` 13 | 14 | Now install the command executable to easily run Rinf commands in the CLI.[^1] 15 | 16 | [^1]: If you're curious about all the available commands, use `rinf --help`. 17 | 18 | ```{code-block} shell 19 | :caption: CLI 20 | cargo install rinf_cli 21 | ``` 22 | 23 | Then, simply run this in the command-line from your Flutter project's directory. 24 | 25 | ```{code-block} shell 26 | :caption: CLI 27 | rinf template 28 | ``` 29 | 30 | After running the command, you'll have new files and folders as your starter Rust template. 31 | 32 | ```{code-block} diff 33 | :caption: Folder Tree 34 | my_flutter_project/ 35 | ├── android/ 36 | ├── ios/ 37 | ├── lib/ 38 | * │ ├── main.dart 39 | │ └── ... 40 | ├── linux/ 41 | + ├── native/ 42 | + │ ├── hub/ 43 | + │ │ ├── src/ 44 | + │ │ └── Cargo.toml 45 | + │ └── README.md 46 | ├── web/ 47 | ├── windows/ 48 | * ├── .gitignore 49 | + ├── Cargo.toml 50 | * ├── pubspec.yaml 51 | * ├── README.md 52 | └── ... 53 | ``` 54 | 55 | Various comments are written in the actual code to help you understand the whole structure. 56 | 57 | If you already have a Rust crate that you want to use here, just put it inside `native` and set it as a dependency of the `hub` crate. 58 | 59 | Now, by heading over to `native/hub/src/lib.rs`, you can start writing Rust! 60 | 61 | Example code for guidance can be found [here](https://github.com/cunarist/rinf/tree/main/flutter_package/example). 62 | -------------------------------------------------------------------------------- /flutter_package/cargokit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Matej Knopp 2 | 3 | ================================================================================ 4 | 5 | MIT LICENSE 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 11 | of the Software, and to permit persons to whom the Software is furnished to do 12 | so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 20 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | ================================================================================ 25 | 26 | APACHE LICENSE, VERSION 2.0 27 | 28 | Licensed under the Apache License, Version 2.0 (the "License"); 29 | you may not use this file except in compliance with the License. 30 | You may obtain a copy of the License at 31 | 32 | http://www.apache.org/licenses/LICENSE-2.0 33 | 34 | Unless required by applicable law or agreed to in writing, software 35 | distributed under the License is distributed on an "AS IS" BASIS, 36 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 37 | See the License for the specific language governing permissions and 38 | limitations under the License. 39 | 40 | -------------------------------------------------------------------------------- /flutter_package/android/build.gradle: -------------------------------------------------------------------------------- 1 | group = "com.cunarist.rinf" 2 | version = "1.0-SNAPSHOT" 3 | 4 | buildscript { 5 | ext.kotlin_version = "1.7.10" 6 | repositories { 7 | google() 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | classpath("com.android.tools.build:gradle:7.3.0") 13 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | apply plugin: "com.android.library" 25 | apply plugin: "kotlin-android" 26 | 27 | android { 28 | if (project.android.hasProperty("namespace")) { 29 | namespace = "com.cunarist.rinf" 30 | } 31 | 32 | compileSdk = 34 33 | 34 | compileOptions { 35 | sourceCompatibility = JavaVersion.VERSION_1_8 36 | targetCompatibility = JavaVersion.VERSION_1_8 37 | } 38 | 39 | kotlinOptions { 40 | jvmTarget = "1.8" 41 | } 42 | 43 | sourceSets { 44 | main.java.srcDirs += "src/main/kotlin" 45 | test.java.srcDirs += "src/test/kotlin" 46 | } 47 | 48 | defaultConfig { 49 | minSdk = 21 50 | } 51 | 52 | dependencies { 53 | testImplementation("org.jetbrains.kotlin:kotlin-test") 54 | testImplementation("org.mockito:mockito-core:5.0.0") 55 | } 56 | 57 | testOptions { 58 | unitTests.all { 59 | useJUnitPlatform() 60 | 61 | testLogging { 62 | events "passed", "skipped", "failed", "standardOut", "standardError" 63 | outputs.upToDateWhen {false} 64 | showStandardStreams = true 65 | } 66 | } 67 | } 68 | } 69 | 70 | // Include Rust crates in the build process 71 | apply from: "../cargokit/gradle/plugin.gradle" 72 | cargokit { 73 | manifestDir = "${rootProject.projectDir}/../native/hub" 74 | libname = "hub" 75 | } 76 | -------------------------------------------------------------------------------- /rust_crate/src/interface.rs: -------------------------------------------------------------------------------- 1 | use crate::AppError; 2 | 3 | #[cfg(not(target_family = "wasm"))] 4 | use crate::interface_os::{send_rust_signal_real, start_rust_logic_real}; 5 | #[cfg(target_family = "wasm")] 6 | use crate::interface_web::{send_rust_signal_real, start_rust_logic_real}; 7 | 8 | /// This contains a message from Dart. 9 | /// Optionally, a custom binary called `binary` can also be included. 10 | #[cfg_attr(feature = "bevy", derive(bevy_ecs::event::Event))] 11 | pub struct DartSignalPack { 12 | /// The message instance. 13 | pub message: T, 14 | /// Binary data included in the signal. 15 | /// This field is useful for sending custom bytes 16 | /// without the overhead of serialization/deserialization. 17 | pub binary: Vec, 18 | } 19 | 20 | /// Runs the async main function in Rust. 21 | /// On native platforms, futures usually implement the `Send` trait 22 | /// to be safely sent between threads. 23 | /// Even in a single-threaded (current-thread) runtime, 24 | /// the `Runtime` object itself might be moved between threads, 25 | /// along with all the tasks it manages. 26 | #[doc(hidden)] 27 | #[cfg(not(target_family = "wasm"))] 28 | pub fn start_rust_logic(main_fn: F) -> Result<(), AppError> 29 | where 30 | F: Fn() -> T + Send + 'static, 31 | { 32 | start_rust_logic_real(main_fn) 33 | } 34 | 35 | /// Runs the async main function in Rust. 36 | /// On the web, futures usually don't implement the `Send` trait 37 | /// because JavaScript environment is fundamentally single-threaded. 38 | #[cfg(target_family = "wasm")] 39 | pub fn start_rust_logic(main_fn: F) -> Result<(), AppError> 40 | where 41 | F: Fn() -> T + 'static, 42 | { 43 | start_rust_logic_real(main_fn) 44 | } 45 | 46 | /// Send a signal to Dart. 47 | #[doc(hidden)] 48 | pub fn send_rust_signal( 49 | endpoint: &str, 50 | message_bytes: Vec, 51 | binary: Vec, 52 | ) -> Result<(), AppError> { 53 | send_rust_signal_real(endpoint, message_bytes, binary) 54 | } 55 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 37 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 38 | 39 | # Run the Flutter tool portions of the build. This must not be removed. 40 | add_dependencies(${BINARY_NAME} flutter_assemble) 41 | -------------------------------------------------------------------------------- /flutter_package/macos/rinf.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint rinf.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'rinf' 7 | s.version = '0.1.0' 8 | s.summary = 'Summary' 9 | s.description = 'Description' 10 | s.homepage = 'http://cunarist.org' 11 | s.license = { :file => '../LICENSE' } 12 | s.author = { 'Your Company' => 'email@cunarist.org' } 13 | 14 | # This will ensure the source files in Classes/ are included in the native 15 | # builds of apps using this FFI plugin. Podspec does not support relative 16 | # paths, so Classes contains a forwarder C file that relatively imports 17 | # `../src/*` so that the C sources can be shared among all target platforms. 18 | s.source = { :path => '.' } 19 | s.source_files = 'Classes/**/*' 20 | s.dependency 'FlutterMacOS' 21 | 22 | s.platform = :osx, '10.11' 23 | s.swift_version = '5.0' 24 | 25 | # Include Rust crates in the build process. 26 | s.script_phase = { 27 | :name => 'Build a Rust library', 28 | :script => 'sh ${PODS_TARGET_SRCROOT}/../cargokit/build_pod.sh ${PROJECT_DIR}/../../native/hub hub', 29 | :execution_position=> :before_compile, 30 | :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], 31 | # Let XCode know that the static library referenced in -force_load below is 32 | # created by this build step. 33 | :output_files => ["${BUILT_PRODUCTS_DIR}/libhub.a"], 34 | } 35 | s.pod_target_xcconfig = { 36 | 'DEFINES_MODULE' => 'YES', 37 | # Flutter.framework does not contain a i386 slice. 38 | 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 39 | # We use `-force_load` instead of `-l` since Xcode strips out unused symbols from static libraries. 40 | 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libhub.a -Wl -undefined dynamic_lookup', 41 | } 42 | end 43 | -------------------------------------------------------------------------------- /flutter_package/ios/rinf.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint rinf.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'rinf' 7 | s.version = '0.1.0' 8 | s.summary = 'Summary' 9 | s.description = 'Description' 10 | s.homepage = 'http://cunarist.org' 11 | s.license = { :file => '../LICENSE' } 12 | s.author = { 'Your Company' => 'email@cunarist.org' } 13 | 14 | # This will ensure the source files in Classes/ are included in the native 15 | # builds of apps using this FFI plugin. Podspec does not support relative 16 | # paths, so Classes contains a forwarder C file that relatively imports 17 | # `../src/*` so that the C sources can be shared among all target platforms. 18 | s.source = { :path => '.' } 19 | s.source_files = 'Classes/**/*' 20 | s.dependency 'Flutter' 21 | 22 | s.platform = :ios, '11.0' 23 | s.swift_version = '5.0' 24 | 25 | # Include Rust crates in the build process. 26 | s.script_phase = { 27 | :name => 'Build a Rust library', 28 | :script => 'sh ${PODS_TARGET_SRCROOT}/../cargokit/build_pod.sh ${PROJECT_DIR}/../../native/hub hub', 29 | :execution_position=> :before_compile, 30 | :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], 31 | # Let XCode know that the static library referenced in -force_load below is 32 | # created by this build step. 33 | :output_files => ["${BUILT_PRODUCTS_DIR}/libhub.a"], 34 | } 35 | s.pod_target_xcconfig = { 36 | 'DEFINES_MODULE' => 'YES', 37 | # Flutter framework does not contain a i386 slice. From default Flutter template. 38 | 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 39 | # We use `-force_load` instead of `-l` since Xcode strips out unused symbols from static libraries. 40 | 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libhub.a -Wl -undefined dynamic_lookup', 41 | } 42 | end 43 | -------------------------------------------------------------------------------- /documentation/source/graceful-shutdown.md: -------------------------------------------------------------------------------- 1 | # Graceful Shutdown 2 | 3 | When the Flutter app is closed, the entire async runtime on the Rust side doesn't get dropped by default. 4 | 5 | In some cases, you might need to drop all Rust resources properly before closing the app. This could include instances of structs that implement the `Drop` trait, which have roles like saving files or disposing of resources. 6 | 7 | To achieve this, you can utilize Flutter's `AppLifecycleListener` to call the `finalizeRust` function before closing the Flutter app. 8 | 9 | ```{code-block} dart 10 | :caption: lib/main.dart 11 | import 'dart:ui'; 12 | import 'package:flutter/material.dart'; 13 | import 'package:rinf/rinf.dart'; 14 | 15 | class MyApp extends StatefulWidget { 16 | const MyApp({super.key}); 17 | @override 18 | State createState() => _MyAppState(); 19 | } 20 | 21 | class _MyAppState extends State { 22 | late final AppLifecycleListener _listener; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | _listener = AppLifecycleListener( 28 | onExitRequested: () async { 29 | finalizeRust(); // Shut down the async Rust runtime. 30 | return AppExitResponse.exit; 31 | }, 32 | ); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | _listener.dispose(); 38 | super.dispose(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | // Return a widget. 44 | } 45 | } 46 | ``` 47 | 48 | It's worth noting that `AppLifecycleListener` cannot always be relied upon for app closings. Below is a text snippet quoted from the official [Flutter docs](https://api.flutter.dev/flutter/widgets/State/dispose.html): 49 | 50 | > There is no way to predict when application shutdown will happen. For example, a user's battery could catch fire, or the user could drop the device into a swimming pool, or the operating system could unilaterally terminate the application process due to memory pressure. Applications are responsible for ensuring they behave well even in the face of rapid, unscheduled termination. 51 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_pod.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | BASEDIR=$(dirname "$0") 5 | 6 | # Workaround for https://github.com/dart-lang/pub/issues/4010 7 | BASEDIR=$(cd "$BASEDIR" ; pwd -P) 8 | 9 | # Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project 10 | NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"` 11 | 12 | export PATH=${NEW_PATH%?} # remove trailing : 13 | 14 | env 15 | 16 | # Platform name (macosx, iphoneos, iphonesimulator) 17 | export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME 18 | 19 | # Arctive architectures (arm64, armv7, x86_64), space separated. 20 | export CARGOKIT_DARWIN_ARCHS=$ARCHS 21 | 22 | # Current build configuration (Debug, Release) 23 | export CARGOKIT_CONFIGURATION=$CONFIGURATION 24 | 25 | # Path to directory containing Cargo.toml. 26 | export CARGOKIT_MANIFEST_DIR=$1 #Different from upstream 27 | 28 | # Temporary directory for build artifacts. 29 | export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR 30 | 31 | # Output directory for final artifacts. 32 | export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME 33 | 34 | # Directory to store built tool artifacts. 35 | export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool 36 | 37 | # Directory inside root project. Not necessarily the top level directory of root project. 38 | export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT 39 | 40 | FLUTTER_EXPORT_BUILD_ENVIRONMENT=( 41 | "$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS 42 | "$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS 43 | ) 44 | 45 | for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}" 46 | do 47 | if [[ -f "$path" ]]; then 48 | source "$path" 49 | fi 50 | done 51 | 52 | sh "$BASEDIR/run_build_tool.sh" build-pod "$@" 53 | 54 | # Make a symlink from built framework to phony file, which will be used as input to 55 | # build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate 56 | # attribute on custom build phase) 57 | ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony" 58 | ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out" 59 | -------------------------------------------------------------------------------- /flutter_package/lib/src/load_web.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_web_libraries_in_flutter 2 | 3 | import 'dart:async'; 4 | import 'dart:js_interop'; 5 | import 'dart:js_interop_unsafe'; 6 | import 'package:web/web.dart'; 7 | 8 | String? jsLibPath; 9 | 10 | void setJsLibPath(String path) { 11 | jsLibPath = path; 12 | } 13 | 14 | bool wasAlreadyLoaded = false; 15 | final rinfBindingsObject = globalContext['rinfBindings'] as JSObject; 16 | final wasmBindingsObject = globalContext['wasmBindings'] as JSObject; 17 | 18 | Future loadJsFile() async { 19 | // When Dart performs hot restart, 20 | // the `rinfBindings` JavaScript object is already defined 21 | // as a global JavaScript variable. 22 | wasAlreadyLoaded = globalContext.hasProperty('rinfBindings'.toJS).toDart; 23 | 24 | // Stop loading if it already has been done. 25 | if (wasAlreadyLoaded) { 26 | return; 27 | } 28 | 29 | // Create the namespace JavaScript object. 30 | // This namespace object is used by Rust 31 | // to call functions defined in Dart. 32 | globalContext['rinfBindings'] = JSObject(); 33 | 34 | // Prepare to await the module load. 35 | final loadCompleter = Completer(); 36 | rinfBindingsObject['completeRinfLoad'] = (() { 37 | loadCompleter.complete(); 38 | }).toJS; 39 | 40 | // Get the domain and the base path. 41 | // Flutter app doesn't always have the top-level path of the domain. 42 | // Sometimes, the flutter app might be placed in a lower path. 43 | final baseHref = Uri.base; 44 | final path = jsLibPath ?? 'pkg/hub.js'; 45 | final fullUrl = baseHref.resolve(path); 46 | 47 | // Insert the script element into the document head. 48 | // This will load the webassembly module. 49 | final scriptElement = HTMLScriptElement(); 50 | scriptElement.type = 'module'; 51 | scriptElement.innerHTML = 52 | ''' 53 | import init, * as wasmBindings from "$fullUrl"; 54 | globalThis.wasmBindings = wasmBindings; 55 | await init(); 56 | rinfBindings.completeRinfLoad(); 57 | delete rinfBindings.completeRinfLoad; 58 | ''' 59 | .toJS; 60 | document.head!.append(scriptElement); 61 | 62 | // Await for the module to load. 63 | await loadCompleter.future; 64 | } 65 | -------------------------------------------------------------------------------- /documentation/source/_static/flutter_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /documentation/source/_templates/landing.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | 79 | 80 |
81 |
82 |
83 | 84 |
85 |
86 |

Rinf

87 |

RUST IN FLUTTER

88 |
89 |
90 |
91 | -------------------------------------------------------------------------------- /flutter_package/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /flutter_package/example/windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/environment.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | extension on String { 4 | String resolveSymlink() => File(this).resolveSymbolicLinksSync(); 5 | } 6 | 7 | class Environment { 8 | /// Current build configuration (debug or release). 9 | static String get configuration => 10 | _getEnv("CARGOKIT_CONFIGURATION").toLowerCase(); 11 | 12 | static bool get isDebug => configuration == 'debug'; 13 | static bool get isRelease => configuration == 'release'; 14 | 15 | /// Temporary directory where Rust build artifacts are placed. 16 | static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR"); 17 | 18 | /// Final output directory where the build artifacts are placed. 19 | static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR'); 20 | 21 | /// Path to the crate manifest (containing Cargo.toml). 22 | static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR'); 23 | 24 | /// Directory inside root project. Not necessarily root folder. Symlinks are 25 | /// not resolved on purpose. 26 | static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR'); 27 | 28 | // Pod 29 | 30 | /// Platform name (macosx, iphoneos, iphonesimulator). 31 | static String get darwinPlatformName => 32 | _getEnv("CARGOKIT_DARWIN_PLATFORM_NAME"); 33 | 34 | /// List of architectures to build for (arm64, armv7, x86_64). 35 | static List get darwinArchs => 36 | _getEnv("CARGOKIT_DARWIN_ARCHS").split(' '); 37 | 38 | // Gradle 39 | static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION"); 40 | static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION"); 41 | static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR"); 42 | static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME"); 43 | static List get targetPlatforms => 44 | _getEnv("CARGOKIT_TARGET_PLATFORMS").split(','); 45 | 46 | // CMAKE 47 | static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM"); 48 | 49 | static String _getEnv(String key) { 50 | final res = Platform.environment[key]; 51 | if (res == null) { 52 | throw Exception("Missing environment variable $key"); 53 | } 54 | return res; 55 | } 56 | 57 | static String _getEnvPath(String key) { 58 | final res = _getEnv(key); 59 | if (Directory(res).existsSync()) { 60 | return res.resolveSymlink(); 61 | } else { 62 | return res; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rust_crate_cli/src/tool/config.rs: -------------------------------------------------------------------------------- 1 | use crate::SetupError; 2 | use serde::Deserialize; 3 | use serde_yml::{Value, from_str, from_value}; 4 | use std::fmt::{Display, Formatter}; 5 | use std::fs::read_to_string; 6 | use std::path::Path; 7 | 8 | /// Rinf message configuration structure. 9 | #[derive(Deserialize)] 10 | pub struct RinfConfig { 11 | #[serde(default = "create_default_gen_input_crates")] 12 | pub gen_input_crates: Vec, 13 | #[serde(default = "create_default_gen_output_dir")] 14 | pub gen_output_dir: String, 15 | } 16 | 17 | impl Display for RinfConfig { 18 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 19 | write!( 20 | f, 21 | "gen_input_crates: {}\ 22 | \ngen_output_dir: {}", 23 | self.gen_input_crates.join(", "), 24 | self.gen_output_dir, 25 | ) 26 | } 27 | } 28 | 29 | impl Default for RinfConfig { 30 | fn default() -> Self { 31 | Self { 32 | gen_input_crates: create_default_gen_input_crates(), 33 | gen_output_dir: create_default_gen_output_dir(), 34 | } 35 | } 36 | } 37 | 38 | fn create_default_gen_input_crates() -> Vec { 39 | vec!["hub".to_owned()] 40 | } 41 | 42 | fn create_default_gen_output_dir() -> String { 43 | "lib/src/bindings".to_owned() 44 | } 45 | 46 | /// Attempts to load the rinf configuration from the provided pubspec.yaml file. 47 | /// If no rinf configuration is found, the default configuration is returned. 48 | /// If the Rinf configuration is invalid, an exception is thrown. 49 | /// Otherwise it loads all values found in the config, using defaults for missing values. 50 | pub fn load_verified_rinf_config( 51 | root_dir: &Path, 52 | ) -> Result { 53 | let file_path = root_dir.join("pubspec.yaml"); 54 | let content = read_to_string(file_path)?; 55 | let file_yaml: Value = from_str(&content)?; 56 | let rinf_yaml = file_yaml 57 | .as_mapping() 58 | .ok_or(SetupError::PubConfig("Parsing failed".to_owned()))? 59 | .get("rinf") 60 | .cloned(); 61 | let config = match rinf_yaml { 62 | Some(map) => from_value(map)?, 63 | None => RinfConfig::default(), 64 | }; 65 | Ok(config) 66 | } 67 | 68 | pub fn read_publish_to(file_path: &Path) -> Option { 69 | let content = std::fs::read_to_string(file_path).ok()?; 70 | let file_yaml: Value = from_str(&content).ok()?; 71 | let field_value = file_yaml.as_mapping()?.get("publish_to")?; 72 | let config = field_value.as_str()?.to_string(); 73 | Some(config) 74 | } 75 | -------------------------------------------------------------------------------- /documentation/source/running-and-building.md: -------------------------------------------------------------------------------- 1 | # Running and Building 2 | 3 | ## For Native Platforms 4 | 5 | The following commands are just enough to run and build apps for native platforms. It's that simple.[^1] 6 | 7 | [^1]: Rinf builds the native Rust library and links it to the Flutter app using [Cargokit](https://github.com/irondash/cargokit). 8 | 9 | To run the app: 10 | 11 | ```{code-block} shell 12 | :caption: CLI 13 | flutter run 14 | ``` 15 | 16 | To build the app for a specific platform: 17 | 18 | ```{code-block} shell 19 | :caption: CLI 20 | flutter build [platform] 21 | ``` 22 | 23 | ## For the Web 24 | 25 | You need to manually build webassembly module from Rust before running or building the app for the web.[^2] 26 | 27 | [^2]: Internally, Rinf uses `wasm-bindgen` and `wasm-pack` with the `web` [target](https://rustwasm.github.io/docs/wasm-pack/commands/build.html#target). 28 | 29 | To serve the web application[^3]: 30 | 31 | [^3]: Since repeatedly writing web header arguments during development can be overwhelming, Rinf provides a convenient command `rinf server` that prints the full Flutter web command. 32 | 33 | ```{code-block} shell 34 | :caption: CLI 35 | rinf wasm 36 | flutter run --web-header=cross-origin-opener-policy=same-origin --web-header=cross-origin-embedder-policy=require-corp 37 | ``` 38 | 39 | To build the optimized release version of the web application: 40 | 41 | ```{code-block} shell 42 | :caption: CLI 43 | rinf wasm --release 44 | flutter build web 45 | ``` 46 | 47 | When deploying your web app on a web server[^4], ensure that your web server is configured to include cross-origin-related HTTP headers in its responses. These headers enable web browsers using your website to gain access to `SharedArrayBuffer` web API, which is something similar to shared memory on the web. 48 | 49 | [^4]: Rinf supports hosting a Flutter app at a [non-root location](https://docs.flutter.dev/ui/navigation/url-strategies#hosting-a-flutter-app-at-a-non-root-location). For example, you can place your Flutter app in `https://mywebsite.com/subpath/deeperpath/`. 50 | 51 | - [`cross-origin-opener-policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cross-origin-opener-policy): `same-origin` 52 | - [`cross-origin-embedder-policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cross-origin-embedder-policy): `require-corp`. 53 | 54 | Additionally, don't forget to specify the MIME type `application/wasm` for `.wasm` files within the server configuration to ensure optimal performance. 55 | -------------------------------------------------------------------------------- /flutter_package/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /rust_crate_cli/template/native/hub/src/actors/first.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use crate::signals::{BigBool, SmallNumber, SmallText}; 4 | use async_trait::async_trait; 5 | use messages::prelude::{Actor, Address, Context, Handler, Notifiable}; 6 | use rinf::{DartSignal, RustSignal, debug_print}; 7 | use tokio::task::JoinSet; 8 | use tokio::time::interval; 9 | 10 | // Uncomment below to target the web. 11 | // use tokio_with_wasm::alias as tokio; 12 | 13 | /// The first actor. 14 | pub struct FirstActor { 15 | /// Owned tasks that are canceled when the actor is dropped. 16 | _owned_tasks: JoinSet<()>, 17 | } 18 | 19 | // Implementing the `Actor` trait for `CountingActor`. 20 | // This defines `FirstActor` as an actor in the async system. 21 | impl Actor for FirstActor {} 22 | 23 | impl FirstActor { 24 | /// Creates the actor and initializes its fields. 25 | pub fn new(self_addr: Address) -> Self { 26 | let mut _owned_tasks = JoinSet::new(); 27 | _owned_tasks.spawn(Self::listen_to_dart(self_addr.clone())); 28 | _owned_tasks.spawn(Self::listen_to_timer(self_addr)); 29 | FirstActor { _owned_tasks } 30 | } 31 | } 32 | 33 | // Implementing the `Notifiable` trait 34 | // allows an actor's loop to listen for a specific message type. 35 | #[async_trait] 36 | impl Notifiable for FirstActor { 37 | async fn notify(&mut self, msg: SmallText, _: &Context) { 38 | debug_print!("{}", msg.text); 39 | SmallNumber { number: 7 }.send_signal_to_dart(); 40 | } 41 | } 42 | 43 | // Implementing the `Handler` trait 44 | // allows an actor's loop to respond to a specific message type. 45 | #[async_trait] 46 | impl Handler for FirstActor { 47 | type Result = bool; 48 | async fn handle(&mut self, msg: BigBool, _: &Context) -> bool { 49 | msg.send_signal_to_dart(); 50 | false 51 | } 52 | } 53 | 54 | impl FirstActor { 55 | /// Listen to an external source, which in this case is Dart. 56 | async fn listen_to_dart(mut self_addr: Address) { 57 | let receiver = SmallText::get_dart_signal_receiver(); 58 | while let Some(signal_pack) = receiver.recv().await { 59 | let _ = self_addr.notify(signal_pack.message).await; 60 | } 61 | } 62 | 63 | /// Listen to an external source, which in this case is a timer. 64 | async fn listen_to_timer(mut self_addr: Address) { 65 | let mut time_interval = interval(Duration::from_secs(3)); 66 | let text = "From an owned task".to_owned(); 67 | loop { 68 | time_interval.tick().await; 69 | let _ = self_addr.notify(SmallText { text: text.clone() }).await; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/lib/src/verify_binaries.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:ed25519_edwards/ed25519_edwards.dart'; 4 | import 'package:http/http.dart'; 5 | 6 | import 'artifacts_provider.dart'; 7 | import 'cargo.dart'; 8 | import 'crate_hash.dart'; 9 | import 'options.dart'; 10 | import 'precompile_binaries.dart'; 11 | import 'target.dart'; 12 | 13 | class VerifyBinaries { 14 | VerifyBinaries({ 15 | required this.manifestDir, 16 | }); 17 | 18 | final String manifestDir; 19 | 20 | Future run() async { 21 | final crateInfo = CrateInfo.load(manifestDir); 22 | 23 | final config = CargokitCrateOptions.load(manifestDir: manifestDir); 24 | final precompiledBinaries = config.precompiledBinaries; 25 | if (precompiledBinaries == null) { 26 | stdout.writeln('Crate does not support precompiled binaries.'); 27 | } else { 28 | final crateHash = CrateHash.compute(manifestDir); 29 | stdout.writeln('Crate hash: $crateHash'); 30 | 31 | for (final target in Target.all) { 32 | final message = 'Checking ${target.rust}...'; 33 | stdout.write(message.padRight(40)); 34 | stdout.flush(); 35 | 36 | final artifacts = getArtifactNames( 37 | target: target, 38 | libraryName: crateInfo.packageName, 39 | remote: true, 40 | ); 41 | 42 | final prefix = precompiledBinaries.uriPrefix; 43 | 44 | bool ok = true; 45 | 46 | for (final artifact in artifacts) { 47 | final fileName = PrecompileBinaries.fileName(target, artifact); 48 | final signatureFileName = 49 | PrecompileBinaries.signatureFileName(target, artifact); 50 | 51 | final url = Uri.parse('$prefix$crateHash/$fileName'); 52 | final signatureUrl = 53 | Uri.parse('$prefix$crateHash/$signatureFileName'); 54 | 55 | final signature = await get(signatureUrl); 56 | if (signature.statusCode != 200) { 57 | stdout.writeln('MISSING'); 58 | ok = false; 59 | break; 60 | } 61 | final asset = await get(url); 62 | if (asset.statusCode != 200) { 63 | stdout.writeln('MISSING'); 64 | ok = false; 65 | break; 66 | } 67 | 68 | if (!verify(precompiledBinaries.publicKey, asset.bodyBytes, 69 | signature.bodyBytes)) { 70 | stdout.writeln('INVALID SIGNATURE'); 71 | ok = false; 72 | } 73 | } 74 | 75 | if (ok) { 76 | stdout.writeln('OK'); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/test/rustup_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_tool/src/rustup.dart'; 2 | import 'package:build_tool/src/util.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | test('rustup with no toolchains', () { 7 | bool didListToolchains = false; 8 | bool didInstallStable = false; 9 | bool didListTargets = false; 10 | testRunCommandOverride = (args) { 11 | expect(args.executable, 'rustup'); 12 | switch (args.arguments) { 13 | case ['toolchain', 'list']: 14 | didListToolchains = true; 15 | return TestRunCommandResult(stdout: 'no installed toolchains\n'); 16 | case ['toolchain', 'install', 'stable']: 17 | didInstallStable = true; 18 | return TestRunCommandResult(); 19 | case ['target', 'list', '--toolchain', 'stable', '--installed']: 20 | didListTargets = true; 21 | return TestRunCommandResult( 22 | stdout: 'x86_64-unknown-linux-gnu\nx86_64-apple-darwin\n'); 23 | default: 24 | throw Exception('Unexpected call: ${args.arguments}'); 25 | } 26 | }; 27 | final rustup = Rustup(); 28 | rustup.installToolchain('stable'); 29 | expect(didInstallStable, true); 30 | expect(didListToolchains, true); 31 | expect(didListTargets, true); 32 | expect(rustup.installedTargets('stable'), [ 33 | 'x86_64-unknown-linux-gnu', 34 | 'x86_64-apple-darwin', 35 | ]); 36 | testRunCommandOverride = null; 37 | }); 38 | 39 | test('rustup with esp toolchain', () { 40 | final targetsQueried = []; 41 | testRunCommandOverride = (args) { 42 | expect(args.executable, 'rustup'); 43 | switch (args.arguments) { 44 | case ['toolchain', 'list']: 45 | return TestRunCommandResult( 46 | stdout: 'stable-aarch64-apple-darwin (default)\n' 47 | 'nightly-aarch64-apple-darwin\n' 48 | 'esp\n'); 49 | case ['target', 'list', '--toolchain', String toolchain, '--installed']: 50 | targetsQueried.add(toolchain); 51 | return TestRunCommandResult(stdout: '$toolchain:target\n'); 52 | default: 53 | throw Exception('Unexpected call: ${args.arguments}'); 54 | } 55 | }; 56 | final rustup = Rustup(); 57 | expect(targetsQueried, [ 58 | 'stable-aarch64-apple-darwin', 59 | 'nightly-aarch64-apple-darwin', 60 | ]); 61 | expect(rustup.installedTargets('stable'), 62 | ['stable-aarch64-apple-darwin:target']); 63 | expect(rustup.installedTargets('nightly'), 64 | ['nightly-aarch64-apple-darwin:target']); 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /.github/workflows/publication.yaml: -------------------------------------------------------------------------------- 1 | # Publish packages online. 2 | # This is performed only when a new Git tag 3 | # with version information is added. 4 | name: Publication 5 | 6 | # With default Git settings, Unix-like systems use LF (`\n`) for new lines, 7 | # while Windows uses CRLF (`\r\n`) in local repositories. 8 | # This default Git behavior is not ideal for a cross-platform project like Rinf. 9 | # Also, the file permission system on Windows is not compatible with unix-like OS. 10 | 11 | # If you publish the packages on Windows with `dart pub publish` 12 | # script files are very likely to produce error on unix-like OS. 13 | # This issue has already been observed with `.sh` files. 14 | # That's why we must use this automated Ubuntu workflow to publish packages. 15 | 16 | on: 17 | push: 18 | tags: 19 | - "v[0-9]+.[0-9]+.[0-9]+*" # Should match the tag pattern set on `pub.dev` 20 | workflow_dispatch: 21 | 22 | jobs: 23 | upload: 24 | name: upload-all 25 | runs-on: ubuntu-latest 26 | permissions: 27 | id-token: write # Required for authentication using OIDC for `pub.dev` 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v6 32 | 33 | - name: Setup Dart SDK 34 | uses: dart-lang/setup-dart@v1 # Required for configuring OIDC token 35 | 36 | - name: Setup Flutter SDK 37 | uses: subosito/flutter-action@v2 # Required for the Flutter FFI plugin 38 | with: 39 | channel: "stable" 40 | 41 | - name: Setup Rust toolchain 42 | uses: dtolnay/rust-toolchain@stable 43 | 44 | # https://dart.dev/tools/pub/automated-publishing 45 | 46 | - name: Publish the Flutter package 47 | working-directory: flutter_package/ 48 | run: | 49 | dart pub publish --dry-run 50 | dart pub publish --force 51 | 52 | # Save the `crates.io` API token at 53 | # `GitHub repo - Settings - Security - Secrets and variables - Actions`. 54 | 55 | - name: Login to the crates registry 56 | run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }} 57 | 58 | - name: Publish the procedural macro crate 59 | run: | 60 | cargo publish --manifest-path rust_crate_proc/Cargo.toml --dry-run 61 | cargo publish --manifest-path rust_crate_proc/Cargo.toml 62 | 63 | - name: Publish the binary crate 64 | run: | 65 | cargo publish --manifest-path rust_crate_cli/Cargo.toml --dry-run 66 | cargo publish --manifest-path rust_crate_cli/Cargo.toml 67 | 68 | - name: Publish the library crate 69 | run: | 70 | cargo publish --manifest-path rust_crate/Cargo.toml --dry-run 71 | cargo publish --manifest-path rust_crate/Cargo.toml 72 | -------------------------------------------------------------------------------- /flutter_package/cargokit/build_tool/test/options_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:build_tool/src/builder.dart'; 2 | import 'package:build_tool/src/options.dart'; 3 | import 'package:hex/hex.dart'; 4 | import 'package:test/test.dart'; 5 | import 'package:yaml/yaml.dart'; 6 | 7 | void main() { 8 | test('parseCargoBuildOptions', () { 9 | final yaml = """ 10 | toolchain: nightly 11 | extra_flags: 12 | - -Z 13 | # Comment here 14 | - build-std=panic_abort,std 15 | """; 16 | final node = loadYamlNode(yaml); 17 | final options = CargoBuildOptions.parse(node); 18 | expect(options.toolchain, Toolchain.nightly); 19 | expect(options.flags, ['-Z', 'build-std=panic_abort,std']); 20 | }); 21 | 22 | test('parsePrecompiledBinaries', () { 23 | final yaml = """ 24 | url_prefix: https://url-prefix 25 | public_key: a4c3433798eb2c36edf2b94dbb4dd899d57496ca373a8982d8a792410b7f6445 26 | """; 27 | final precompiledBinaries = PrecompiledBinaries.parse(loadYamlNode(yaml)); 28 | final key = HEX.decode( 29 | 'a4c3433798eb2c36edf2b94dbb4dd899d57496ca373a8982d8a792410b7f6445'); 30 | expect(precompiledBinaries.uriPrefix, 'https://url-prefix'); 31 | expect(precompiledBinaries.publicKey.bytes, key); 32 | }); 33 | 34 | test('parseCargokitOptions', () { 35 | const yaml = ''' 36 | cargo: 37 | # For smalles binaries rebuilt the standard library with panic=abort 38 | debug: 39 | toolchain: nightly 40 | extra_flags: 41 | - -Z 42 | # Comment here 43 | - build-std=panic_abort,std 44 | release: 45 | toolchain: beta 46 | 47 | precompiled_binaries: 48 | url_prefix: https://url-prefix 49 | public_key: a4c3433798eb2c36edf2b94dbb4dd899d57496ca373a8982d8a792410b7f6445 50 | '''; 51 | final options = CargokitCrateOptions.parse(loadYamlNode(yaml)); 52 | expect(options.precompiledBinaries?.uriPrefix, 'https://url-prefix'); 53 | final key = HEX.decode( 54 | 'a4c3433798eb2c36edf2b94dbb4dd899d57496ca373a8982d8a792410b7f6445'); 55 | expect(options.precompiledBinaries?.publicKey.bytes, key); 56 | 57 | final debugOptions = options.cargo[BuildConfiguration.debug]!; 58 | expect(debugOptions.toolchain, Toolchain.nightly); 59 | expect(debugOptions.flags, ['-Z', 'build-std=panic_abort,std']); 60 | 61 | final releaseOptions = options.cargo[BuildConfiguration.release]!; 62 | expect(releaseOptions.toolchain, Toolchain.beta); 63 | expect(releaseOptions.flags, []); 64 | }); 65 | 66 | test('parseCargokitUserOptions', () { 67 | const yaml = ''' 68 | use_precompiled_binaries: false 69 | verbose_logging: true 70 | '''; 71 | final options = CargokitUserOptions.parse(loadYamlNode(yaml)); 72 | expect(options.usePrecompiledBinaries, false); 73 | expect(options.verboseLogging, true); 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /flutter_package/cargokit/run_build_tool.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | setlocal ENABLEDELAYEDEXPANSION 5 | 6 | SET BASEDIR=%~dp0 7 | 8 | if not exist "%CARGOKIT_TOOL_TEMP_DIR%" ( 9 | mkdir "%CARGOKIT_TOOL_TEMP_DIR%" 10 | ) 11 | cd /D "%CARGOKIT_TOOL_TEMP_DIR%" 12 | 13 | SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool 14 | SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart 15 | 16 | set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/% 17 | 18 | ( 19 | echo name: build_tool_runner 20 | echo version: 1.0.0 21 | echo publish_to: none 22 | echo. 23 | echo environment: 24 | echo sdk: '^>=3.0.0 ^<4.0.0' 25 | echo. 26 | echo dependencies: 27 | echo build_tool: 28 | echo path: %BUILD_TOOL_PKG_DIR_POSIX% 29 | ) >pubspec.yaml 30 | 31 | if not exist bin ( 32 | mkdir bin 33 | ) 34 | 35 | ( 36 | echo import 'package:build_tool/build_tool.dart' as build_tool; 37 | echo void main^(List^ args^) ^{ 38 | echo build_tool.runMain^(args^); 39 | echo ^} 40 | ) >bin\build_tool_runner.dart 41 | 42 | SET PRECOMPILED=bin\build_tool_runner.dill 43 | 44 | REM To detect changes in package we compare output of DIR /s (recursive) 45 | set PREV_PACKAGE_INFO=.dart_tool\package_info.prev 46 | set CUR_PACKAGE_INFO=.dart_tool\package_info.cur 47 | 48 | DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig" 49 | 50 | REM Last line in dir output is free space on harddrive. That is bound to 51 | REM change between invocation so we need to remove it 52 | ( 53 | Set "Line=" 54 | For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do ( 55 | SetLocal EnableDelayedExpansion 56 | If Defined Line Echo !Line! 57 | EndLocal 58 | Set "Line=%%A") 59 | ) >"%CUR_PACKAGE_INFO%" 60 | DEL "%CUR_PACKAGE_INFO%_orig" 61 | 62 | REM Compare current directory listing with previous 63 | FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1 64 | 65 | If %ERRORLEVEL% neq 0 ( 66 | REM Changed - copy current to previous and remove precompiled kernel 67 | if exist "%PREV_PACKAGE_INFO%" ( 68 | DEL "%PREV_PACKAGE_INFO%" 69 | ) 70 | MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" 71 | if exist "%PRECOMPILED%" ( 72 | DEL "%PRECOMPILED%" 73 | ) 74 | ) 75 | 76 | REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO% 77 | REM which means we need to do pub get and precompile 78 | if not exist "%PRECOMPILED%" ( 79 | echo Running pub get in "%cd%" 80 | "%DART%" pub get --no-precompile 81 | "%DART%" compile kernel bin/build_tool_runner.dart 82 | ) 83 | 84 | "%DART%" "%PRECOMPILED%" %* 85 | 86 | REM 253 means invalid snapshot version. 87 | If %ERRORLEVEL% equ 253 ( 88 | "%DART%" pub get --no-precompile 89 | "%DART%" compile kernel bin/build_tool_runner.dart 90 | "%DART%" "%PRECOMPILED%" %* 91 | ) 92 | -------------------------------------------------------------------------------- /flutter_package/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rinf 2 | description: Rust for native business logic, Flutter for flexible and beautiful GUI 3 | version: 8.8.1 4 | repository: https://github.com/cunarist/rinf 5 | 6 | environment: 7 | sdk: ">=3.8.0 <4.0.0" 8 | flutter: ">=3.22.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | ffi: ^2.1.0 14 | web: ^1.1.0 15 | 16 | dev_dependencies: 17 | flutter_lints: ^6.0.0 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://dart.dev/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter packages. 23 | flutter: 24 | # This section identifies this Flutter project as a plugin project. 25 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 26 | # which should be registered in the plugin registry. This is required for 27 | # using method channels. 28 | # The Android 'package' specifies package in which the registered class is. 29 | # This is required for using method channels on Android. 30 | # The 'ffiPlugin' specifies that native code should be built and bundled. 31 | # This is required for using `dart:ffi`. 32 | # All these are used by the tooling to maintain consistency when 33 | # adding or updating assets for this project. 34 | # 35 | # Please refer to README.md for a detailed explanation. 36 | plugin: 37 | platforms: 38 | android: 39 | ffiPlugin: true 40 | ios: 41 | ffiPlugin: true 42 | linux: 43 | ffiPlugin: true 44 | elinux: 45 | ffiPlugin: true 46 | macos: 47 | ffiPlugin: true 48 | windows: 49 | ffiPlugin: true 50 | web: 51 | 52 | # To add assets to your plugin package, add an assets section, like this: 53 | # assets: 54 | # - images/a_dot_burr.jpeg 55 | # - images/a_dot_ham.jpeg 56 | # 57 | # For details regarding assets in packages, see 58 | # https://flutter.dev/assets-and-images/#from-packages 59 | # 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.dev/assets-and-images/#resolution-aware 62 | 63 | # To add custom fonts to your plugin package, add a fonts section here, 64 | # in this "flutter" section. Each entry in this list should have a 65 | # "family" key with the font family name, and a "fonts" key with a 66 | # list giving the asset and other descriptors for the font. For 67 | # example: 68 | # fonts: 69 | # - family: Schyler 70 | # fonts: 71 | # - asset: fonts/Schyler-Regular.ttf 72 | # - asset: fonts/Schyler-Italic.ttf 73 | # style: italic 74 | # - family: Trajan Pro 75 | # fonts: 76 | # - asset: fonts/TrajanPro.ttf 77 | # - asset: fonts/TrajanPro_Bold.ttf 78 | # weight: 700 79 | # 80 | # For details regarding fonts in packages, see 81 | # https://flutter.dev/custom-fonts/#from-packages 82 | --------------------------------------------------------------------------------