Struct lib_flutter_rust_bridge_codegen::Opts
source · pub struct Opts {Show 18 fields
pub rust_input_path: String,
pub dart_output_path: String,
pub dart_decl_output_path: Option<String>,
pub c_output_path: Vec<String>,
pub rust_crate_dir: String,
pub rust_output_path: String,
pub class_name: String,
pub dart_format_line_length: u32,
pub skip_add_mod_to_lib: bool,
pub llvm_path: Vec<String>,
pub llvm_compiler_opts: String,
pub manifest_path: String,
pub dart_root: Option<String>,
pub build_runner: bool,
pub block_index: BlockIndex,
pub skip_deps_check: bool,
pub wasm_enabled: bool,
pub inline_rust: bool,
}
Fields§
§rust_input_path: String
§dart_output_path: String
§dart_decl_output_path: Option<String>
§c_output_path: Vec<String>
§rust_crate_dir: String
§rust_output_path: String
§class_name: String
§dart_format_line_length: u32
§skip_add_mod_to_lib: bool
§llvm_path: Vec<String>
§llvm_compiler_opts: String
§manifest_path: String
§dart_root: Option<String>
§build_runner: bool
§block_index: BlockIndex
§skip_deps_check: bool
§wasm_enabled: bool
§inline_rust: bool
Implementations§
source§impl Opts
impl Opts
sourcepub fn get_ir_file(&self) -> Result<IrFile>
pub fn get_ir_file(&self) -> Result<IrFile>
Examples found in repository?
src/utils.rs (line 51)
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
pub fn get_symbols_if_no_duplicates(configs: &[crate::Opts]) -> Result<Vec<String>, anyhow::Error> {
let mut explicit_raw_symbols = Vec::new();
let mut all_symbols = Vec::new();
for config in configs {
let raw_ir_file = config.get_ir_file()?;
// for checking explicit api duplication
explicit_raw_symbols.extend(raw_ir_file.funcs.iter().map(|f| f.name.clone()));
// for avoiding redundant generation in dart
all_symbols.extend(raw_ir_file.get_all_symbols(config));
}
let duplicates = find_all_duplicates(&explicit_raw_symbols);
if !duplicates.is_empty() {
let duplicated_symbols = duplicates.join(",");
let (symbol_str, verb_str) = if duplicates.len() == 1 {
("symbol", "has")
} else {
("symbols", "have")
};
return Err(anyhow!(
"{} [{}] {} already been defined",
symbol_str,
duplicated_symbols,
verb_str
));
}
Ok(all_symbols)
}
More examples
src/lib.rs (line 54)
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
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
sourcepub fn dart_api_class_name(&self) -> String
pub fn dart_api_class_name(&self) -> String
Examples found in repository?
src/generator/dart/ty_rust_opaque.rs (line 36)
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
fn structs(&self) -> String {
let field_bridge = format!(
"final {} bridge;",
self.context.config.dart_api_class_name(),
);
format!(
"@sealed class {0} extends FrbOpaque {{
{field_bridge}
{0}.fromRaw(int ptr, int size, this.bridge) : super.unsafe(ptr, size);
@override
DropFnType get dropFn => bridge.dropOpaque{0};
@override
ShareFnType get shareFn => bridge.shareOpaque{0};
@override
OpaqueTypeFinalizer get staticFinalizer => bridge.{0}Finalizer;
}}",
self.ir.dart_api_type()
)
}
More examples
src/generator/dart/mod.rs (line 55)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
pub fn generate(ir_file: &IrFile, config: &Opts, wasm_funcs: &[IrFuncDisplay]) -> Output {
let dart_api_class_name = &config.dart_api_class_name();
let dart_output_file_root = config.dart_output_root().expect("Internal error");
let spec = DartApiSpec::from(ir_file, config, wasm_funcs);
let DartApiSpec {
dart_funcs,
dart_structs,
..
} = &spec;
let needs_freezed = spec.needs_freezed;
let common_header = generate_common_header();
let decl_code = generate_dart_declaration_code(
&common_header,
generate_freezed_header(dart_output_file_root, needs_freezed),
generate_import_header(get_dart_imports(ir_file), spec.import_array.as_deref()),
generate_dart_declaration_body(dart_api_class_name, dart_funcs, dart_structs),
);
let impl_code = generate_dart_implementation_code(
&common_header,
generate_dart_implementation_body(&spec, config),
);
let file_prelude = generate_file_prelude();
Output {
file_prelude,
decl_code,
impl_code,
needs_freezed,
}
}
struct DartApiSpec {
dart_funcs: Vec<GeneratedApiFunc>,
dart_structs: Vec<String>,
dart_api2wire_funcs: Acc<String>,
dart_opaque_funcs: Acc<String>,
dart_api_fill_to_wire_funcs: Vec<String>,
dart_wire2api_funcs: Vec<String>,
dart_wasm_funcs: Vec<String>,
dart_wasm_module: Option<String>,
needs_freezed: bool,
import_array: Option<String>,
}
impl DartApiSpec {
fn from(ir_file: &IrFile, config: &Opts, extra_funcs: &[IrFuncDisplay]) -> Self {
let dart_api_class_name = config.dart_api_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let distinct_types = ir_file.distinct_types(true, true);
let distinct_input_types = ir_file.distinct_types(true, false);
let distinct_output_types = ir_file.distinct_types(false, true);
debug!("distinct_input_types={:?}", distinct_input_types);
debug!("distinct_output_types={:?}", distinct_output_types);
let dart_structs = distinct_types
.iter()
.map(|ty| {
TypeDartGenerator::new(
ty.clone(),
ir_file,
// Some(dart_api_class_name.to_string()),
config,
)
.structs()
})
.collect::<Vec<_>>();
let dart_api2wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api2wire_func(ty, ir_file, config))
.collect::<Acc<_>>()
.join("\n");
let mut dart_funcs = ir_file
.funcs
.iter()
.map(|f| generate_api_func(f, ir_file, &dart_api2wire_funcs.common))
.collect::<Vec<_>>();
dart_funcs.extend(
distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_getters),
);
let dart_api_fill_to_wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api_fill_to_wire_func(ty, ir_file, config))
.collect::<Vec<_>>();
let dart_wire2api_funcs = distinct_output_types
.iter()
.map(|ty| generate_wire2api_func(ty, ir_file, &dart_api_class_name, config))
.collect::<Vec<_>>();
let dart_opaque_funcs = distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_func)
.collect::<Acc<_>>()
.join("\n");
let ir_wasm_func_exports = config.wasm_enabled.then(|| {
ir_file
.funcs
.iter()
.map(|fun| IrFuncDisplay::from_ir(fun, Target::Wasm))
.chain(extra_funcs.iter().cloned())
.collect::<Vec<_>>()
});
let dart_wasm_funcs = if let Some(exports) = &ir_wasm_func_exports {
exports.iter().map(generate_wasm_wire_func_decl).collect()
} else {
Default::default()
};
let dart_wasm_module = (ir_wasm_func_exports.as_ref()).map(|exports| {
generate_wasm_wire(exports, &dart_wire_class_name, &config.dart_wasm_module())
});
let needs_freezed = distinct_types.iter().any(|ty| match ty {
EnumRef(_) => true,
StructRef(st) => st.freezed,
_ => false,
});
let import_array = distinct_types
.iter()
.any(IrType::is_array)
.then(|| "import 'package:collection/collection.dart';".to_owned());
DartApiSpec {
dart_funcs,
dart_structs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
needs_freezed,
import_array,
}
}
}
fn generate_freezed_header(dart_output_file_root: &str, needs_freezed: bool) -> DartBasicCode {
if needs_freezed {
DartBasicCode {
import: "import 'package:freezed_annotation/freezed_annotation.dart' hide protected;"
.to_string(),
part: format!("part '{}.freezed.dart';", dart_output_file_root),
body: "".to_string(),
}
} else {
DartBasicCode::default()
}
}
fn generate_import_header(
imports: HashSet<&IrDartImport>,
import_array: Option<&str>,
) -> DartBasicCode {
if !imports.is_empty() || import_array.is_some() {
DartBasicCode {
import: imports
.iter()
.map(|it| match &it.alias {
Some(alias) => format!("import '{}' as {};", it.uri, alias),
_ => format!("import '{}';", it.uri),
})
.collect::<Vec<_>>()
.join("\n")
+ import_array.unwrap_or(""),
part: "".to_string(),
body: "".to_string(),
}
} else {
DartBasicCode::default()
}
}
fn generate_common_header() -> DartBasicCode {
DartBasicCode {
import: format!(
"{}{}",
"import 'dart:convert';
import 'dart:async';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';",
if cfg!(feature = "uuid") {
"\nimport 'package:uuid/uuid.dart';"
} else {
""
},
),
part: "".to_string(),
body: "".to_string(),
}
}
fn get_dart_imports(ir_file: &IrFile) -> HashSet<&IrDartImport> {
ir_file
.struct_pool
.values()
.flat_map(|s| s.dart_metadata.iter().flat_map(|it| &it.library))
.collect()
}
fn generate_dart_declaration_body(
dart_api_class_name: &str,
dart_funcs: &[GeneratedApiFunc],
dart_structs: &[String],
) -> String {
format!(
"
abstract class {0} {{
{1}
}}
{2}
",
dart_api_class_name,
dart_funcs
.iter()
.map(|func| format!(
"{}{}\n\n{}",
func.comments, func.signature, func.companion_field_signature,
))
.collect::<Vec<_>>()
.join("\n\n"),
dart_structs.join("\n\n"),
)
}
fn section_header(header: &str) -> String {
format!("// Section: {}\n", header)
}
/// A Dart bridge module consists of several members:
/// - An `_Impl` class exposing the public Rust functions
/// - One or more `_Platform` classes implementing platform-specific helpers
///
/// The `_Impl` class takes a `_Platform _platform` instance as a private member,
/// and the `_Platform` exposes all of its methods decorated as `@protected`.
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
src/generator/dart/ty_struct.rs (line 109)
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 201 202 203 204 205 206 207 208
fn structs(&self) -> String {
let src = self.ir.get(self.context.ir_file);
let comments = dart_comments(&src.comments);
let metadata = dart_metadata(&src.dart_metadata);
let ir_file = self.context.ir_file;
let methods = ir_file
.funcs
.iter()
.filter(|f| {
let f = FunctionName::deserialize(&f.name);
f.is_method_for_struct(&src.name) || f.is_static_method_for_struct(&src.name)
})
.collect::<Vec<_>>();
let has_methods = !methods.is_empty();
let methods = methods
.iter()
.map(|func| generate_api_method(func, src, self.context.config.dart_api_class_name()))
.collect::<Vec<_>>();
let methods_string = methods
.iter()
.map(|g| format!("{}=>{};\n\n", g.signature.clone(), g.implementation.clone()))
.collect::<Vec<_>>()
.concat();
let extra_argument = "required this.bridge,".to_string();
let field_bridge = format!(
"final {} bridge;",
self.context.config.dart_api_class_name(),
);
if src.using_freezed() {
let mut constructor_params = src
.fields
.iter()
.map(|f| {
format!(
"{} {} {},",
f.ty.dart_required_modifier(),
f.ty.dart_api_type(),
f.name.dart_style()
)
})
.collect::<Vec<_>>();
if has_methods {
constructor_params.insert(0, extra_argument);
}
let constructor_params = constructor_params.join("");
format!(
"{}{}class {} with _${} {{
const factory {}({{{}}}) = _{};
{}
}}",
comments,
metadata,
self.ir.name,
self.ir.name,
self.ir.name,
constructor_params,
self.ir.name,
methods_string
)
} else {
let mut field_declarations = src
.fields
.iter()
.map(|f| {
let comments = dart_comments(&f.comments);
format!(
"{}{} {} {};",
comments,
if f.is_final { "final" } else { "" },
f.ty.dart_api_type(),
f.name.dart_style()
)
})
.collect::<Vec<_>>();
if has_methods {
field_declarations.insert(0, field_bridge);
}
let field_declarations = field_declarations.join("\n");
let mut constructor_params = src
.fields
.iter()
.map(|f| {
format!(
"{}this.{},",
f.ty.dart_required_modifier(),
f.name.dart_style()
)
})
.collect::<Vec<_>>();
if has_methods {
constructor_params.insert(0, extra_argument);
}
let constructor_params = constructor_params.join("");
format!(
"{}{}class {} {{
{}
{}({{{}}});
{}
}}",
comments,
metadata,
self.ir.name,
field_declarations,
self.ir.name,
constructor_params,
methods_string
)
}
}
sourcepub fn dart_api_impl_class_name(&self) -> String
pub fn dart_api_impl_class_name(&self) -> String
Examples found in repository?
src/generator/dart/mod.rs (line 301)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
sourcepub fn dart_wire_class_name(&self) -> String
pub fn dart_wire_class_name(&self) -> String
Examples found in repository?
src/generator/dart/mod.rs (line 104)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
fn from(ir_file: &IrFile, config: &Opts, extra_funcs: &[IrFuncDisplay]) -> Self {
let dart_api_class_name = config.dart_api_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let distinct_types = ir_file.distinct_types(true, true);
let distinct_input_types = ir_file.distinct_types(true, false);
let distinct_output_types = ir_file.distinct_types(false, true);
debug!("distinct_input_types={:?}", distinct_input_types);
debug!("distinct_output_types={:?}", distinct_output_types);
let dart_structs = distinct_types
.iter()
.map(|ty| {
TypeDartGenerator::new(
ty.clone(),
ir_file,
// Some(dart_api_class_name.to_string()),
config,
)
.structs()
})
.collect::<Vec<_>>();
let dart_api2wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api2wire_func(ty, ir_file, config))
.collect::<Acc<_>>()
.join("\n");
let mut dart_funcs = ir_file
.funcs
.iter()
.map(|f| generate_api_func(f, ir_file, &dart_api2wire_funcs.common))
.collect::<Vec<_>>();
dart_funcs.extend(
distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_getters),
);
let dart_api_fill_to_wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api_fill_to_wire_func(ty, ir_file, config))
.collect::<Vec<_>>();
let dart_wire2api_funcs = distinct_output_types
.iter()
.map(|ty| generate_wire2api_func(ty, ir_file, &dart_api_class_name, config))
.collect::<Vec<_>>();
let dart_opaque_funcs = distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_func)
.collect::<Acc<_>>()
.join("\n");
let ir_wasm_func_exports = config.wasm_enabled.then(|| {
ir_file
.funcs
.iter()
.map(|fun| IrFuncDisplay::from_ir(fun, Target::Wasm))
.chain(extra_funcs.iter().cloned())
.collect::<Vec<_>>()
});
let dart_wasm_funcs = if let Some(exports) = &ir_wasm_func_exports {
exports.iter().map(generate_wasm_wire_func_decl).collect()
} else {
Default::default()
};
let dart_wasm_module = (ir_wasm_func_exports.as_ref()).map(|exports| {
generate_wasm_wire(exports, &dart_wire_class_name, &config.dart_wasm_module())
});
let needs_freezed = distinct_types.iter().any(|ty| match ty {
EnumRef(_) => true,
StructRef(st) => st.freezed,
_ => false,
});
let import_array = distinct_types
.iter()
.any(IrType::is_array)
.then(|| "import 'package:collection/collection.dart';".to_owned());
DartApiSpec {
dart_funcs,
dart_structs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
needs_freezed,
import_array,
}
}
}
fn generate_freezed_header(dart_output_file_root: &str, needs_freezed: bool) -> DartBasicCode {
if needs_freezed {
DartBasicCode {
import: "import 'package:freezed_annotation/freezed_annotation.dart' hide protected;"
.to_string(),
part: format!("part '{}.freezed.dart';", dart_output_file_root),
body: "".to_string(),
}
} else {
DartBasicCode::default()
}
}
fn generate_import_header(
imports: HashSet<&IrDartImport>,
import_array: Option<&str>,
) -> DartBasicCode {
if !imports.is_empty() || import_array.is_some() {
DartBasicCode {
import: imports
.iter()
.map(|it| match &it.alias {
Some(alias) => format!("import '{}' as {};", it.uri, alias),
_ => format!("import '{}';", it.uri),
})
.collect::<Vec<_>>()
.join("\n")
+ import_array.unwrap_or(""),
part: "".to_string(),
body: "".to_string(),
}
} else {
DartBasicCode::default()
}
}
fn generate_common_header() -> DartBasicCode {
DartBasicCode {
import: format!(
"{}{}",
"import 'dart:convert';
import 'dart:async';
import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';",
if cfg!(feature = "uuid") {
"\nimport 'package:uuid/uuid.dart';"
} else {
""
},
),
part: "".to_string(),
body: "".to_string(),
}
}
fn get_dart_imports(ir_file: &IrFile) -> HashSet<&IrDartImport> {
ir_file
.struct_pool
.values()
.flat_map(|s| s.dart_metadata.iter().flat_map(|it| &it.library))
.collect()
}
fn generate_dart_declaration_body(
dart_api_class_name: &str,
dart_funcs: &[GeneratedApiFunc],
dart_structs: &[String],
) -> String {
format!(
"
abstract class {0} {{
{1}
}}
{2}
",
dart_api_class_name,
dart_funcs
.iter()
.map(|func| format!(
"{}{}\n\n{}",
func.comments, func.signature, func.companion_field_signature,
))
.collect::<Vec<_>>()
.join("\n\n"),
dart_structs.join("\n\n"),
)
}
fn section_header(header: &str) -> String {
format!("// Section: {}\n", header)
}
/// A Dart bridge module consists of several members:
/// - An `_Impl` class exposing the public Rust functions
/// - One or more `_Platform` classes implementing platform-specific helpers
///
/// The `_Impl` class takes a `_Platform _platform` instance as a private member,
/// and the `_Platform` exposes all of its methods decorated as `@protected`.
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
More examples
src/lib.rs (line 98)
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
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
sourcepub fn dart_platform_class_name(&self) -> String
pub fn dart_platform_class_name(&self) -> String
Examples found in repository?
src/generator/dart/mod.rs (line 304)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
sourcepub fn dart_wasm_module(&self) -> String
pub fn dart_wasm_module(&self) -> String
Examples found in repository?
src/generator/dart/wasm.rs (line 33)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
pub fn push_wasm_module(
lines: &mut Acc<Vec<String>>,
dart_wasm_funcs: &[String],
dart_wasm_module: Option<&str>,
config: &Opts,
) {
let dart_wasm_module_name = config.dart_wasm_module();
lines.wasm.push(section_header("WASM wire module"));
lines.wasm.push(format!(
"@JS('wasm_bindgen') external {} get wasmModule;",
dart_wasm_module_name,
));
lines.wasm.push(format!(
"@JS() @anonymous class {wasm} implements WasmModule {{
external Object /* Promise */ call([String? moduleName]);
external {wasm} bind(dynamic thisArg, String moduleName);",
wasm = dart_wasm_module_name,
));
lines.wasm.push(dart_wasm_funcs.join("\n\n"));
lines.wasm.push("}\n".into());
lines.wasm.push(section_header("WASM wire connector"));
(lines.wasm).push(dart_wasm_module.unwrap_or_default().to_string());
}
More examples
src/generator/dart/mod.rs (line 172)
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
fn from(ir_file: &IrFile, config: &Opts, extra_funcs: &[IrFuncDisplay]) -> Self {
let dart_api_class_name = config.dart_api_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let distinct_types = ir_file.distinct_types(true, true);
let distinct_input_types = ir_file.distinct_types(true, false);
let distinct_output_types = ir_file.distinct_types(false, true);
debug!("distinct_input_types={:?}", distinct_input_types);
debug!("distinct_output_types={:?}", distinct_output_types);
let dart_structs = distinct_types
.iter()
.map(|ty| {
TypeDartGenerator::new(
ty.clone(),
ir_file,
// Some(dart_api_class_name.to_string()),
config,
)
.structs()
})
.collect::<Vec<_>>();
let dart_api2wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api2wire_func(ty, ir_file, config))
.collect::<Acc<_>>()
.join("\n");
let mut dart_funcs = ir_file
.funcs
.iter()
.map(|f| generate_api_func(f, ir_file, &dart_api2wire_funcs.common))
.collect::<Vec<_>>();
dart_funcs.extend(
distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_getters),
);
let dart_api_fill_to_wire_funcs = distinct_input_types
.iter()
.map(|ty| generate_api_fill_to_wire_func(ty, ir_file, config))
.collect::<Vec<_>>();
let dart_wire2api_funcs = distinct_output_types
.iter()
.map(|ty| generate_wire2api_func(ty, ir_file, &dart_api_class_name, config))
.collect::<Vec<_>>();
let dart_opaque_funcs = distinct_output_types
.iter()
.filter(|ty| ty.is_rust_opaque())
.map(generate_opaque_func)
.collect::<Acc<_>>()
.join("\n");
let ir_wasm_func_exports = config.wasm_enabled.then(|| {
ir_file
.funcs
.iter()
.map(|fun| IrFuncDisplay::from_ir(fun, Target::Wasm))
.chain(extra_funcs.iter().cloned())
.collect::<Vec<_>>()
});
let dart_wasm_funcs = if let Some(exports) = &ir_wasm_func_exports {
exports.iter().map(generate_wasm_wire_func_decl).collect()
} else {
Default::default()
};
let dart_wasm_module = (ir_wasm_func_exports.as_ref()).map(|exports| {
generate_wasm_wire(exports, &dart_wire_class_name, &config.dart_wasm_module())
});
let needs_freezed = distinct_types.iter().any(|ty| match ty {
EnumRef(_) => true,
StructRef(st) => st.freezed,
_ => false,
});
let import_array = distinct_types
.iter()
.any(IrType::is_array)
.then(|| "import 'package:collection/collection.dart';".to_owned());
DartApiSpec {
dart_funcs,
dart_structs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
needs_freezed,
import_array,
}
}
sourcepub fn dart_wasm_output_path(&self) -> PathBuf
pub fn dart_wasm_output_path(&self) -> PathBuf
Examples found in repository?
src/generator/dart/mod.rs (line 416)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
More examples
src/lib.rs (line 156)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
fn write_dart_decls(
config: &Opts,
dart_decl_output_path: &str,
dart_output_dir: &Path,
generated_dart: &crate::generator::dart::Output,
generated_dart_decl_all: &DartBasicCode,
generated_dart_impl_io_wire: &DartBasicCode,
) -> anyhow::Result<()> {
let impl_import_decl = DartBasicCode {
import: format!(
"import \"{}\";",
diff_paths(dart_decl_output_path, dart_output_dir)
.unwrap()
.to_str()
.unwrap()
),
..Default::default()
};
let common_import = DartBasicCode {
import: if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
},
..Default::default()
};
fs::write(
dart_decl_output_path,
(&generated_dart.file_prelude + &common_import + generated_dart_decl_all).to_text(),
)?;
if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + generated_dart_impl_io_wire)
.to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.wasm)
.to_text(),
)?;
} else {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ &impl_import_decl
+ &generated_dart.impl_code.common
+ generated_dart_impl_io_wire)
.to_text(),
)?;
}
Ok(())
}
sourcepub fn dart_io_output_path(&self) -> PathBuf
pub fn dart_io_output_path(&self) -> PathBuf
Examples found in repository?
src/generator/dart/mod.rs (line 411)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
fn generate_dart_implementation_body(spec: &DartApiSpec, config: &Opts) -> Acc<DartBasicCode> {
let mut lines = Acc::<Vec<_>>::default();
let dart_api_impl_class_name = config.dart_api_impl_class_name();
let dart_wire_class_name = config.dart_wire_class_name();
let dart_api_class_name = config.dart_api_class_name();
let dart_platform_class_name = config.dart_platform_class_name();
let DartApiSpec {
dart_funcs,
dart_api2wire_funcs,
dart_opaque_funcs,
dart_api_fill_to_wire_funcs,
dart_wire2api_funcs,
dart_wasm_funcs,
dart_wasm_module,
..
} = spec;
lines.push_acc(Acc {
common: format!(
"class {impl} implements {} {{
final {plat} _platform;
factory {impl}(ExternalLibrary dylib) => {impl}.raw({plat}(dylib));
/// Only valid on web/WASM platforms.
factory {impl}.wasm(FutureOr<WasmModule> module) =>
{impl}(module as ExternalLibrary);
{impl}.raw(this._platform);",
dart_api_class_name,
impl = dart_api_impl_class_name,
plat = dart_platform_class_name,
),
io: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> {{
{plat}(ffi.DynamicLibrary dylib) : super({wire}(dylib));",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
wasm: format!(
"class {plat} extends FlutterRustBridgeBase<{wire}> with FlutterRustBridgeSetupMixin {{
{plat}(FutureOr<WasmModule> dylib) : super({wire}(dylib)) {{
setupMixinConstructor();
}}
Future<void> setup() => inner.init;",
plat = dart_platform_class_name,
wire = dart_wire_class_name,
),
});
lines.extend(dart_funcs.iter().map(|func| {
format!(
"{}\n\n{}",
func.implementation, func.companion_field_implementation,
)
}));
lines.push_acc(Acc {
common: "void dispose() {_platform.dispose();}".to_owned(),
..Default::default()
});
lines.push(section_header("wire2api"));
lines.push(dart_wire2api_funcs.join("\n\n"));
lines.push("}\n".into());
lines.push_all(section_header("api2wire"));
lines.push_acc(dart_api2wire_funcs.clone());
lines.push_all(section_header("finalizer"));
lines.push_acc(dart_opaque_funcs.clone());
lines.io.push(section_header("api_fill_to_wire"));
lines.io.push(dart_api_fill_to_wire_funcs.join("\n\n"));
lines.push_acc(Acc::new(|target| match target {
Io | Wasm => "}\n".into(),
Common => "".into(),
}));
if config.wasm_enabled {
push_wasm_module(
&mut lines,
dart_wasm_funcs,
dart_wasm_module.as_deref(),
config,
);
}
let Acc { common, io, wasm } = lines.join("\n");
let impl_import = format!(
"{} import 'package:meta/meta.dart';",
if config.wasm_enabled {
format!(
"import '{}'; export '{0}';",
Path::new(&config.dart_output_path)
.file_name()
.and_then(OsStr::to_str)
.unwrap()
)
} else {
"".into()
}
);
let common_import = format!(
"{}
import 'package:meta/meta.dart';",
// If WASM is not enabled, the common and IO branches are
// combined into one, making this import statement invalid.
if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
}
);
Acc {
common: DartBasicCode {
body: common,
import: common_import,
..Default::default()
},
io: DartBasicCode {
import: impl_import.clone(),
body: io,
..Default::default()
},
wasm: DartBasicCode {
import: impl_import,
body: wasm,
..Default::default()
},
}
}
More examples
src/lib.rs (line 152)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
fn write_dart_decls(
config: &Opts,
dart_decl_output_path: &str,
dart_output_dir: &Path,
generated_dart: &crate::generator::dart::Output,
generated_dart_decl_all: &DartBasicCode,
generated_dart_impl_io_wire: &DartBasicCode,
) -> anyhow::Result<()> {
let impl_import_decl = DartBasicCode {
import: format!(
"import \"{}\";",
diff_paths(dart_decl_output_path, dart_output_dir)
.unwrap()
.to_str()
.unwrap()
),
..Default::default()
};
let common_import = DartBasicCode {
import: if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
},
..Default::default()
};
fs::write(
dart_decl_output_path,
(&generated_dart.file_prelude + &common_import + generated_dart_decl_all).to_text(),
)?;
if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + generated_dart_impl_io_wire)
.to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.wasm)
.to_text(),
)?;
} else {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ &impl_import_decl
+ &generated_dart.impl_code.common
+ generated_dart_impl_io_wire)
.to_text(),
)?;
}
Ok(())
}
pub fn dart_common_output_path(&self) -> PathBuf
sourcepub fn rust_wasm_output_path(&self) -> PathBuf
pub fn rust_wasm_output_path(&self) -> PathBuf
Examples found in repository?
src/lib.rs (line 73)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
fn write_dart_decls(
config: &Opts,
dart_decl_output_path: &str,
dart_output_dir: &Path,
generated_dart: &crate::generator::dart::Output,
generated_dart_decl_all: &DartBasicCode,
generated_dart_impl_io_wire: &DartBasicCode,
) -> anyhow::Result<()> {
let impl_import_decl = DartBasicCode {
import: format!(
"import \"{}\";",
diff_paths(dart_decl_output_path, dart_output_dir)
.unwrap()
.to_str()
.unwrap()
),
..Default::default()
};
let common_import = DartBasicCode {
import: if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
},
..Default::default()
};
fs::write(
dart_decl_output_path,
(&generated_dart.file_prelude + &common_import + generated_dart_decl_all).to_text(),
)?;
if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + generated_dart_impl_io_wire)
.to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.wasm)
.to_text(),
)?;
} else {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ &impl_import_decl
+ &generated_dart.impl_code.common
+ generated_dart_impl_io_wire)
.to_text(),
)?;
}
Ok(())
}
fn write_rust_modules(
config: &Opts,
generated_rust: &crate::generator::rust::Output,
) -> anyhow::Result<()> {
let Acc { common, io, wasm } = &generated_rust.code;
fn emit_platform_module(name: &str, body: &str, config: &Opts, target: Target) -> String {
if config.inline_rust {
format!("mod {} {{ use super::*;\n {} }}", name, body)
} else {
let path = match target {
Target::Io => config.rust_io_output_path(),
Target::Wasm => config.rust_wasm_output_path(),
_ => panic!("unsupported target: {:?}", target),
};
let path = path.file_name().and_then(OsStr::to_str).unwrap();
format!("#[path = \"{}\"] mod {};", path, name)
}
}
let common = format!(
"{}
{mod_web}
#[cfg(not(target_family = \"wasm\"))]
{mod_io}
#[cfg(not(target_family = \"wasm\"))]
pub use io::*;
",
common,
mod_web = if config.wasm_enabled {
format!(
"
/// cbindgen:ignore
#[cfg(target_family = \"wasm\")]
{}
#[cfg(target_family = \"wasm\")]
pub use web::*;",
emit_platform_module("web", wasm, config, Target::Wasm)
)
} else {
"".into()
},
mod_io = emit_platform_module("io", io, config, Target::Io),
);
fs::write(&config.rust_output_path, common)?;
if !config.inline_rust {
fs::write(
config.rust_io_output_path(),
format!("use super::*;\n{}", io),
)?;
if config.wasm_enabled {
fs::write(
config.rust_wasm_output_path(),
format!("use super::*;\n{}", wasm),
)?;
}
}
Ok(())
}
sourcepub fn rust_io_output_path(&self) -> PathBuf
pub fn rust_io_output_path(&self) -> PathBuf
Examples found in repository?
src/lib.rs (line 72)
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 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
fn write_dart_decls(
config: &Opts,
dart_decl_output_path: &str,
dart_output_dir: &Path,
generated_dart: &crate::generator::dart::Output,
generated_dart_decl_all: &DartBasicCode,
generated_dart_impl_io_wire: &DartBasicCode,
) -> anyhow::Result<()> {
let impl_import_decl = DartBasicCode {
import: format!(
"import \"{}\";",
diff_paths(dart_decl_output_path, dart_output_dir)
.unwrap()
.to_str()
.unwrap()
),
..Default::default()
};
let common_import = DartBasicCode {
import: if config.wasm_enabled {
format!(
"import '{}' if (dart.library.html) '{}';",
config
.dart_io_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
config
.dart_wasm_output_path()
.file_name()
.and_then(OsStr::to_str)
.unwrap(),
)
} else {
"".into()
},
..Default::default()
};
fs::write(
dart_decl_output_path,
(&generated_dart.file_prelude + &common_import + generated_dart_decl_all).to_text(),
)?;
if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + generated_dart_impl_io_wire)
.to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &impl_import_decl + &generated_dart.impl_code.wasm)
.to_text(),
)?;
} else {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ &impl_import_decl
+ &generated_dart.impl_code.common
+ generated_dart_impl_io_wire)
.to_text(),
)?;
}
Ok(())
}
fn write_rust_modules(
config: &Opts,
generated_rust: &crate::generator::rust::Output,
) -> anyhow::Result<()> {
let Acc { common, io, wasm } = &generated_rust.code;
fn emit_platform_module(name: &str, body: &str, config: &Opts, target: Target) -> String {
if config.inline_rust {
format!("mod {} {{ use super::*;\n {} }}", name, body)
} else {
let path = match target {
Target::Io => config.rust_io_output_path(),
Target::Wasm => config.rust_wasm_output_path(),
_ => panic!("unsupported target: {:?}", target),
};
let path = path.file_name().and_then(OsStr::to_str).unwrap();
format!("#[path = \"{}\"] mod {};", path, name)
}
}
let common = format!(
"{}
{mod_web}
#[cfg(not(target_family = \"wasm\"))]
{mod_io}
#[cfg(not(target_family = \"wasm\"))]
pub use io::*;
",
common,
mod_web = if config.wasm_enabled {
format!(
"
/// cbindgen:ignore
#[cfg(target_family = \"wasm\")]
{}
#[cfg(target_family = \"wasm\")]
pub use web::*;",
emit_platform_module("web", wasm, config, Target::Wasm)
)
} else {
"".into()
},
mod_io = emit_platform_module("io", io, config, Target::Io),
);
fs::write(&config.rust_output_path, common)?;
if !config.inline_rust {
fs::write(
config.rust_io_output_path(),
format!("use super::*;\n{}", io),
)?;
if config.wasm_enabled {
fs::write(
config.rust_wasm_output_path(),
format!("use super::*;\n{}", wasm),
)?;
}
}
Ok(())
}
sourcepub fn dart_root_or_default(&self) -> String
pub fn dart_root_or_default(&self) -> String
Examples found in repository?
src/lib.rs (line 45)
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
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}
sourcepub fn dart_freezed_path(&self) -> PathBuf
pub fn dart_freezed_path(&self) -> PathBuf
Examples found in repository?
src/lib.rs (line 192)
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
pub fn frb_codegen(config: &config::Opts, all_symbols: &[String]) -> anyhow::Result<()> {
let dart_root = config.dart_root_or_default();
ensure_tools_available(&dart_root, config.skip_deps_check)?;
info!("Picked config: {:?}", config);
let rust_output_dir = Path::new(&config.rust_output_path).parent().unwrap();
let dart_output_dir = Path::new(&config.dart_output_path).parent().unwrap();
info!("Phase: Parse source code to AST, then to IR");
let raw_ir_file = config.get_ir_file()?;
info!("Phase: Transform IR");
let ir_file = transformer::transform(raw_ir_file);
info!("Phase: Generate Rust code");
fs::create_dir_all(rust_output_dir)?;
let generated_rust = ir_file.generate_rust(config);
write_rust_modules(config, &generated_rust)?;
info!("Phase: Generate Dart code");
let generated_dart = ir_file.generate_dart(config, &generated_rust.wasm_exports);
run!(
commands::format_rust,
&config.rust_output_path,
(
config.wasm_enabled && !config.inline_rust,
config.rust_io_output_path(),
config.rust_wasm_output_path(),
)
)?;
if !config.skip_add_mod_to_lib {
others::try_add_mod_to_lib(&config.rust_crate_dir, &config.rust_output_path);
}
info!("Phase: Generating Dart bindings for Rust");
let temp_dart_wire_file = tempfile::NamedTempFile::new()?;
let temp_bindgen_c_output_file = tempfile::Builder::new().suffix(".h").tempfile()?;
let exclude_symbols = generated_rust.get_exclude_symbols(all_symbols);
with_changed_file(
&config.rust_output_path,
DUMMY_WIRE_CODE_FOR_BINDGEN,
|| {
commands::bindgen_rust_to_dart(
BindgenRustToDartArg {
rust_crate_dir: &config.rust_crate_dir,
c_output_path: temp_bindgen_c_output_file
.path()
.as_os_str()
.to_str()
.unwrap(),
dart_output_path: temp_dart_wire_file.path().as_os_str().to_str().unwrap(),
dart_class_name: &config.dart_wire_class_name(),
c_struct_names: ir_file.get_c_struct_names(),
exclude_symbols,
llvm_install_path: &config.llvm_path[..],
llvm_compiler_opts: &config.llvm_compiler_opts,
},
&dart_root,
)
},
)?;
let effective_func_names = [
generated_rust.extern_func_names,
EXTRA_EXTERN_FUNC_NAMES.to_vec(),
]
.concat();
let c_dummy_code = generator::c::generate_dummy(&effective_func_names);
for output in &config.c_output_path {
fs::create_dir_all(Path::new(output).parent().unwrap())?;
fs::write(
output,
fs::read_to_string(&temp_bindgen_c_output_file)? + "\n" + &c_dummy_code,
)?;
}
fs::create_dir_all(dart_output_dir)?;
let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file)?;
let generated_dart_wire = extract_dart_wire_content(&modify_dart_wire_content(
&generated_dart_wire_code_raw,
&config.dart_wire_class_name(),
));
sanity_check(&generated_dart_wire.body, &config.dart_wire_class_name())?;
let generated_dart_decl_all = &generated_dart.decl_code;
let generated_dart_impl_io_wire = &generated_dart.impl_code.io + &generated_dart_wire;
if let Some(dart_decl_output_path) = &config.dart_decl_output_path {
write_dart_decls(
config,
dart_decl_output_path,
dart_output_dir,
&generated_dart,
generated_dart_decl_all,
&generated_dart_impl_io_wire,
)?;
} else if config.wasm_enabled {
fs::write(
&config.dart_output_path,
(&generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common)
.to_text(),
)?;
fs::write(
config.dart_io_output_path(),
(&generated_dart.file_prelude + &generated_dart_impl_io_wire).to_text(),
)?;
fs::write(
config.dart_wasm_output_path(),
(&generated_dart.file_prelude + &generated_dart.impl_code.wasm).to_text(),
)?;
} else {
let mut out = generated_dart.file_prelude
+ generated_dart_decl_all
+ &generated_dart.impl_code.common
+ &generated_dart_impl_io_wire;
out.import = out.import.lines().unique().join("\n");
fs::write(&config.dart_output_path, out.to_text())?;
}
info!("Phase: Running build_runner");
let dart_root = &config.dart_root;
if generated_dart.needs_freezed && config.build_runner {
let dart_root = dart_root.as_ref().ok_or_else(|| {
Error::str(
"build_runner configured to run, but Dart root could not be inferred.
Please specify --dart-root, or disable build_runner with --no-build-runner.",
)
})?;
commands::build_runner(dart_root)?;
}
info!("Phase: Formatting Dart code");
run!(
commands::format_dart[config.dart_format_line_length],
&config.dart_output_path,
?config.dart_decl_output_path,
(
config.wasm_enabled,
config.dart_wasm_output_path(),
config.dart_io_output_path(),
),
(
generated_dart.needs_freezed && config.build_runner,
config.dart_freezed_path(),
)
)?;
info!("Success!");
Ok(())
}