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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
//! `dustr` is as a binary that parses rust code to generate its dart bindings. The rust code must //! be marked using procedural macros from the [ffishim_derive][1] library. //! //! With dustr, you can call this rust code: //! //! ```ignore //! #[ffishim_function] //! fn hello(s: String) -> String { //! format!("Hello, {}!", s) //! } //! ``` //! //! from dart: //! //! ```Dart //! import 'package:hello/hello.dart'; //! //! void main() { //! var greeting = hello("fred"); //! print("${greeting}"); //! } //! ``` //! //! For more context, please take a look at the [README.md][2]. //! //! [1]: https://github.com/mqnfred/ffishim //! [2]: https://github.com/mqnfred/dustr #[macro_use] extern crate serde_derive; #[macro_use] mod helpers; /// A rust module (hierarchy), built by parsing a crate. /// /// The `Module` can be parsed from a full crate, a simple .rs file, or from a `mod` block in /// a file. When parsing from a crate, all three methods are used whenever required. #[derive(Debug)] pub struct Module { name: String, crate_name: String, structs: Vec<::ffishim::Data>, enums: Vec<::ffishim::Data>, functions: Vec<::syn::ItemFn>, subs: Vec<Module>, } mod module; /// The dart package built from rust sources. /// /// This package is nothing but a set of [`Library`][1] objects with a name. You can build the dart /// package by calling its `build` method and providing the folder in which you would like the dart /// package to be built. /// /// [1]: struct.Library.html #[derive(Debug)] pub struct Package { name: String, libraries: Vec<Library>, } mod package; /// The dart equivalent of a rust [`Module`][1]. /// /// `Library`s map 1:1 with rust modules. You can initialize a `Library` by calling its `try_from` /// static method and providing it with the rust module you want to create bindings for. /// /// [1]: struct.Module.html #[derive(Debug)] pub struct Library { name: String, imports: Imports, structs: Vec<Struct>, enums: Vec<Enum>, functions: Vec<Function>, wrappers: Vec<Wrapper>, subs: Vec<Library>, } mod library; /// Imports helps manage imports (remove duplicates etc.) /// /// A set of imports can be built from many other objects in dustr. You can get the imports list /// for a rust module, from a data structure, from a function, fields... All imports from all items /// in a library are then bubbled up to be used by the [`Library`][2] object, which will finally /// generate them. /// /// The `Imports` structure ensures nothing is imported twice. /// /// [1]: struct.Module.html /// [2]: struct.Library.html #[derive(Debug)] pub struct Imports(Vec<String>); mod imports; /// The dart representation of a rust structure. /// /// `Struct` is created from a struct [`ffishim::Data`][1] object. It contains all metadata /// necessary to generate the final bindings for this structure (field names, types, constructor, /// destructor, ...) /// /// [1]: https://docs.rs/ffishim/0.1.2/ffishim/struct.Data.html #[derive(Debug)] pub struct Struct { name: String, declarations: Vec<FieldDeclaration>, getters: Vec<Getter>, new_func: Option<Function>, new_method: Option<NewMethod>, free_func: Option<Function>, free_method: Option<FreeMethod>, } #[derive(Debug)] struct NewMethod { struct_name: String, args: Vec<(String, String)>, // native type, field name call_expr: String, } #[derive(Debug)] struct FreeMethod { func_name: String, cast_to: Option<String>, } #[derive(Debug)] struct FieldDeclaration { annotation: Option<String>, ffi_type: String, name: String, } #[derive(Debug)] struct Getter { native_type: String, name: String, expr: String, } mod r#struct; /// The dart representation of a rust enum. /// /// `Enum` is created from an enum [`ffishim::Data`][1]. It contains all metadata necessary to /// generate the final bindings for this enum (variants, field names, types, constructors, /// destructors...) /// /// [1]: https://docs.rs/ffishim/0.1.2/ffishim/struct.Data.html #[derive(Debug)] pub struct Enum { name: String, base_struct: Struct, variant_structs: Vec<Struct>, variant_tags: Vec<String>, } mod r#enum; /// A dart ffi function binding declaration. /// /// `Function` is created from the rust `syn::ItemFn` to expose in Dart. Upon calling `fmt`, this /// will generate the declaration of the function across the ffi boundary in dart as a global /// variable. That function will never be called directly, it'll instead be called by our generated /// [`Wrapper`][1]. /// /// [1]: struct.Wrapper.html #[derive(Debug)] pub struct Function { lib_name: String, name: String, field_types: Vec<String>, ret_type: String, shim_name: String, shim_field_types: Vec<String>, shim_ret_type: String, } mod function; /// A dart wrapper around our function declarations. /// /// `Wrapper` is created from the rust `syn::ItemFn` we want to wrap in Dart. The wrapper calls the /// inner function after sanitizing input/outputs. It will also transform any `Result::Err` /// variants returned into a Dart exception. This `Wrapper` contains all metadata necessary for /// generation of the wrapper. #[derive(Debug)] pub struct Wrapper { name: String, fields: Vec<(String, String)>, ret: String, func_name: String, field_conversions: Vec<String>, ret_conversion: String, result_cast: Option<String>, } mod wrapper; pub mod types;