diff --git a/frb_codegen/src/config.rs b/frb_codegen/src/config.rs index 5f638608de..20a45f2d70 100644 --- a/frb_codegen/src/config.rs +++ b/frb_codegen/src/config.rs @@ -18,6 +18,9 @@ pub struct RawOpts { /// Path of output generated Dart code #[structopt(short, long)] pub dart_output: String, + /// If provided, generated Dart declaration code to this separate file + #[structopt(short, long)] + pub dart_decl_output: Option, /// Path of output generated C header #[structopt(short, long)] @@ -49,6 +52,7 @@ pub struct RawOpts { pub struct Opts { pub rust_input_path: String, pub dart_output_path: String, + pub dart_decl_output_path: Option, pub c_output_path: String, pub rust_crate_dir: String, pub rust_output_path: String, @@ -82,6 +86,7 @@ pub fn parse(raw: RawOpts) -> Opts { Opts { rust_input_path, dart_output_path: canon_path(&raw.dart_output), + dart_decl_output_path: raw.dart_decl_output.as_ref().map(canon_path), c_output_path, rust_crate_dir, rust_output_path, diff --git a/frb_codegen/src/generator_dart.rs b/frb_codegen/src/generator_dart.rs index 5e60efe8d5..0e364374d1 100644 --- a/frb_codegen/src/generator_dart.rs +++ b/frb_codegen/src/generator_dart.rs @@ -5,18 +5,12 @@ use crate::api_types::ApiType::*; use crate::api_types::*; use crate::others::*; -pub struct Output { - pub header: String, - pub api_class: String, - pub other: String, -} - pub fn generate( api_file: &ApiFile, dart_api_class_name: &str, dart_api_impl_class_name: &str, dart_wire_class_name: &str, -) -> Output { +) -> (DartBasicCode, DartBasicCode) { let distinct_types = api_file.distinct_types(true, true); let distinct_input_types = api_file.distinct_types(true, false); let distinct_output_types = api_file.distinct_types(false, true); @@ -54,45 +48,41 @@ pub fn generate( .any(|ty| matches!(ty, EnumRef(e) if e.is_struct)); let freezed_header = if needs_freezed { "import 'package:freezed_annotation/freezed_annotation.dart'; - // import 'package:flutter/foundation.dart'; + part 'bridge_generated.freezed.dart';" } else { "" }; - let header = format!( + let common_header = format!( "{} // ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal import 'dart:convert'; - import 'dart:typed_data'; - - import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';", - CODE_HEADER, + import 'dart:typed_data';", + CODE_HEADER ); - let api_class = format!( + let decl_header = format!( "{} - abstract class {} extends FlutterRustBridgeBase<{}> {{ - factory {}(ffi.DynamicLibrary dylib) => {}.raw({}(dylib)); + {}", + common_header, freezed_header, + ); - {}.raw({} inner) : super(inner); + let impl_header = format!( + "{} + import 'package:flutter_rust_bridge/flutter_rust_bridge.dart';", + common_header + ); + let decl_body = format!( + "abstract class {} {{ {} }} {} - - // ------------------------- Implementation Details ------------------------- ", - freezed_header, - dart_api_class_name, - dart_wire_class_name, - dart_api_class_name, - dart_api_impl_class_name, - dart_wire_class_name, dart_api_class_name, - dart_wire_class_name, dart_func_signatures_and_implementations .iter() .map(|(sig, _, comm)| format!("{}{}", comm, sig)) @@ -101,11 +91,10 @@ pub fn generate( dart_structs.join("\n\n"), ); - let other = format!( - "/// Implementations for {}. Prefer using {} if possible; but this class allows more - /// flexible customizations (such as subclassing to create an initializer, a logger, or - /// a timer). - class {} extends {} {{ + let impl_body = format!( + "class {} extends FlutterRustBridgeBase<{}> implements {} {{ + factory {}(ffi.DynamicLibrary dylib) => {}.raw({}(dylib)); + {}.raw({} inner) : super.raw(inner); {} @@ -120,11 +109,13 @@ pub fn generate( // Section: wire2api {} ", - dart_api_class_name, - dart_api_class_name, dart_api_impl_class_name, + dart_wire_class_name, dart_api_class_name, dart_api_impl_class_name, + dart_api_impl_class_name, + dart_wire_class_name, + dart_api_impl_class_name, dart_wire_class_name, dart_func_signatures_and_implementations .iter() @@ -136,11 +127,16 @@ pub fn generate( dart_wire2api_funcs.join("\n\n"), ); - Output { - header, - api_class, - other, - } + ( + DartBasicCode { + header: decl_header, + body: decl_body, + }, + DartBasicCode { + header: impl_header, + body: impl_body, + }, + ) } fn generate_api_func(func: &ApiFunc) -> (String, String, String) { diff --git a/frb_codegen/src/main.rs b/frb_codegen/src/main.rs index f5a5ecc421..90136a6add 100644 --- a/frb_codegen/src/main.rs +++ b/frb_codegen/src/main.rs @@ -52,7 +52,7 @@ fn main() { fs::write(&config.rust_output_path, generated_rust.code).unwrap(); info!("Phase: Generate Dart code"); - let generated_dart_api = generator_dart::generate( + let (generated_dart_decl_raw, generated_dart_impl_raw) = generator_dart::generate( &api_file, &config.dart_api_class_name(), &config.dart_api_impl_class_name(), @@ -116,27 +116,33 @@ fn main() { fs::create_dir_all(&dart_output_dir).unwrap(); let generated_dart_wire_code_raw = fs::read_to_string(temp_dart_wire_file).unwrap(); - let (generated_dart_wire_import_code, generated_dart_wire_body_code) = - extract_dart_wire_content(&modify_dart_wire_content( - &generated_dart_wire_code_raw, - &config.dart_wire_class_name(), - )); + 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_code, &config.dart_wire_class_name(), ); - let generated_dart_code = format!( - "{}\n{}\n{}\n{}\n{}", - generated_dart_api.header, - generated_dart_wire_import_code, - generated_dart_api.api_class, - generated_dart_api.other, - generated_dart_wire_body_code, - ); - fs::write(&config.dart_output_path, generated_dart_code).unwrap(); + let generated_dart_decl_all = generated_dart_decl_raw; + let generated_dart_impl_all = generated_dart_impl_raw + generated_dart_wire; + if let Some(dart_decl_output_path) = &config.dart_decl_output_path { + fs::write(&dart_decl_output_path, generated_dart_decl_all.to_text()).unwrap(); + fs::write(&config.dart_output_path, generated_dart_impl_all.to_text()).unwrap(); + } else { + fs::write( + &config.dart_output_path, + (&generated_dart_decl_all + &generated_dart_impl_all).to_text(), + ) + .unwrap(); + } + commands::format_dart(&config.dart_output_path, config.dart_format_line_length); + if let Some(dart_decl_output_path) = &config.dart_decl_output_path { + commands::format_dart(&dart_decl_output_path, config.dart_format_line_length); + } info!("Success! Now go and use it :)"); } diff --git a/frb_codegen/src/others.rs b/frb_codegen/src/others.rs index 4f42a4d772..f95dc621b1 100644 --- a/frb_codegen/src/others.rs +++ b/frb_codegen/src/others.rs @@ -1,4 +1,5 @@ use std::fs; +use std::ops::Add; use std::path::Path; use anyhow::{anyhow, Result}; @@ -56,7 +57,29 @@ pub fn modify_dart_wire_content(content_raw: &str, dart_wire_class_name: &str) - content.to_string() } -pub fn extract_dart_wire_content(content: &str) -> (String, String) { +pub struct DartBasicCode { + pub header: String, + pub body: String, +} + +impl Add for &DartBasicCode { + type Output = DartBasicCode; + + fn add(self, rhs: Self) -> Self::Output { + DartBasicCode { + header: format!("{}\n{}", self.header, rhs.header), + body: format!("{}\n{}", self.body, rhs.body), + } + } +} + +impl DartBasicCode { + pub fn to_text(&self) -> String { + format!("{}\n{}", self.header, self.body) + } +} + +pub fn extract_dart_wire_content(content: &str) -> DartBasicCode { let (mut imports, mut body) = (Vec::new(), Vec::new()); for line in content.split('\n') { (if line.starts_with("import ") { @@ -66,7 +89,10 @@ pub fn extract_dart_wire_content(content: &str) -> (String, String) { }) .push(line); } - (imports.join("\n"), body.join("\n")) + DartBasicCode { + header: imports.join("\n"), + body: body.join("\n"), + } } pub fn sanity_check(generated_dart_wire_code: &str, dart_wire_class_name: &str) {