Skip to content

Commit

Permalink
Merge pull request #2050 from fzyzcjy/feat/12184
Browse files Browse the repository at this point in the history
Support `#[frb(proxy)]` (part 1)
  • Loading branch information
fzyzcjy authored Jun 9, 2024
2 parents 5f2065e + 7bcc32f commit 1dcc30b
Show file tree
Hide file tree
Showing 46 changed files with 2,259 additions and 213 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use crate::codegen::generator::api_dart;
use crate::codegen::generator::api_dart::spec_generator::class::proxy_variant;
use crate::codegen::generator::api_dart::spec_generator::function::{
compute_params_str, ApiDartGeneratedFunction, ApiDartGeneratedFunctionParam,
};
use crate::codegen::generator::api_dart::spec_generator::misc::generate_dart_comments;
use crate::codegen::ir::mir::func::{
MirFunc, MirFuncAccessorMode, MirFuncArgMode, MirFuncDefaultConstructorMode, MirFuncOwnerInfo,
MirFuncOwnerInfoMethod, MirFuncOwnerInfoMethodMode,
MirFunc, MirFuncAccessorMode, MirFuncArgMode, MirFuncDefaultConstructorMode, MirFuncImplMode,
MirFuncImplModeDartOnly, MirFuncOwnerInfo, MirFuncOwnerInfoMethod, MirFuncOwnerInfoMethodMode,
};
use crate::codegen::ir::mir::ty::delegate::MirTypeDelegate;
use crate::codegen::ir::mir::ty::MirType;
use crate::if_then_some;
use crate::library::codegen::generator::api_dart::spec_generator::base::*;
use crate::utils::basic_code::dart_header_code::DartHeaderCode;
use crate::utils::namespace::NamespacedName;
use convert_case::{Case, Casing};
use itertools::Itertools;
use lazy_static::lazy_static;
use regex::Regex;

#[derive(Debug, Clone)]
pub(crate) struct GenerateApiMethodConfig {
Expand Down Expand Up @@ -53,23 +58,47 @@ struct GeneratedApiMethod {
}

pub(crate) fn generate_api_methods(
generalized_class_name: &NamespacedName,
owner_ty: &MirType,
context: ApiDartGeneratorContext,
config: &GenerateApiMethodConfig,
dart_class_name: &str,
) -> GeneratedApiMethods {
let methods =
get_methods_of_enum_or_struct(generalized_class_name, &context.mir_pack.funcs_all)
.iter()
.filter_map(|func| generate_api_method(func, context, config, dart_class_name))
.collect_vec();
let query_class_name = compute_class_name_for_querying_methods(owner_ty);
let methods = get_methods_of_ty(&query_class_name, &context.mir_pack.funcs_all)
.iter()
.filter_map(|func| generate_api_method(func, context, config, dart_class_name))
.collect_vec();
GeneratedApiMethods {
num_methods: methods.len(),
code: methods.iter().map(|x| x.code.clone()).join("\n"),
header: (methods.iter().map(|x| x.header.clone())).fold(Default::default(), |a, b| a + b),
}
}

fn compute_class_name_for_querying_methods(ty: &MirType) -> NamespacedName {
match ty {
MirType::EnumRef(ty) => ty.ident.0.clone(),
MirType::StructRef(ty) => ty.ident.0.clone(),
MirType::TraitDef(ty) => ty.name.clone(),
MirType::Delegate(MirTypeDelegate::ProxyVariant(ty)) => {
compute_class_name_for_querying_methods(&*ty.inner)
}
MirType::RustAutoOpaqueImplicit(ty) => {
compute_class_name_for_querying_methods(&MirType::RustOpaque(ty.inner.clone()))
}
MirType::RustOpaque(ty) => {
lazy_static! {
static ref FILTER: Regex =
Regex::new(r"^flutter_rust_bridge::for_generated::RustAutoOpaqueInner<(.*)>$")
.unwrap();
}
let name = FILTER.replace_all(&ty.inner.0, "$1").to_string();
NamespacedName::new(ty.namespace.clone(), name)
}
_ => panic!("compute_query_class_name see unknown ty={ty:?}"),
}
}

// TODO move
pub(crate) fn dart_constructor_postfix(
name: &NamespacedName,
Expand All @@ -83,17 +112,12 @@ pub(crate) fn dart_constructor_postfix(
}

fn has_default_dart_constructor(name: &NamespacedName, all_funcs: &[MirFunc]) -> bool {
get_methods_of_enum_or_struct(name, all_funcs)
.iter()
.any(|m| {
m.default_constructor_mode() == Some(MirFuncDefaultConstructorMode::DartConstructor)
})
get_methods_of_ty(name, all_funcs).iter().any(|m| {
m.default_constructor_mode() == Some(MirFuncDefaultConstructorMode::DartConstructor)
})
}

fn get_methods_of_enum_or_struct<'a>(
name: &NamespacedName,
all_funcs: &'a [MirFunc],
) -> Vec<&'a MirFunc> {
fn get_methods_of_ty<'a>(name: &NamespacedName, all_funcs: &'a [MirFunc]) -> Vec<&'a MirFunc> {
(all_funcs.iter())
.filter(|f| matches!(&f.owner, MirFuncOwnerInfo::Method(m) if m.owner_ty_name().as_ref() == Some(name)))
.collect_vec()
Expand Down Expand Up @@ -232,20 +256,30 @@ fn generate_implementation(
method_info: &MirFuncOwnerInfoMethod,
params: &[ApiDartGeneratedFunctionParam],
) -> String {
let dart_entrypoint_class_name = &context.config.dart_entrypoint_class_name;
let dart_api_instance = format!("{dart_entrypoint_class_name}.instance.api");
match &func.impl_mode {
MirFuncImplMode::Normal => {
let dart_entrypoint_class_name = &context.config.dart_entrypoint_class_name;
let dart_api_instance = format!("{dart_entrypoint_class_name}.instance.api");

let func_name = func.name_dart_wire();
let func_name = func.name_dart_wire();

let arg_names = params
.iter()
.map(|x| format!("{name}: {name}", name = x.name_str))
.join(", ");
let arg_names = params
.iter()
.map(|x| format!("{name}: {name}", name = x.name_str))
.join(", ");

if method_info.mode == MirFuncOwnerInfoMethodMode::Static {
format!("{dart_api_instance}.{func_name}({arg_names})")
} else {
let extra_arg_name = func.inputs[0].inner.name.dart_style();
format!("{dart_api_instance}.{func_name}({extra_arg_name}: this, {arg_names})")
if method_info.mode == MirFuncOwnerInfoMethodMode::Static {
format!("{dart_api_instance}.{func_name}({arg_names})")
} else {
let extra_arg_name = func.inputs[0].inner.name.dart_style();
format!("{dart_api_instance}.{func_name}({extra_arg_name}: this, {arg_names})")
}
}
MirFuncImplMode::NoImpl => "should_not_reach_here".to_owned(),
MirFuncImplMode::DartOnly(inner) => match inner {
MirFuncImplModeDartOnly::CreateProxyVariant(inner) => {
proxy_variant::compute_func_implementation(inner, context, func.mode)
}
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use serde::Serialize;
pub(crate) mod field;
pub(crate) mod method;
pub(super) mod misc;
pub(crate) mod proxy_variant;
pub(crate) mod ty;

#[derive(Debug, Serialize)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::codegen::generator::api_dart::spec_generator::base::{
ApiDartGenerator, ApiDartGeneratorContext,
};
use crate::codegen::ir::mir::func::MirFuncMode;
use crate::codegen::ir::mir::ty::delegate::MirTypeDelegateProxyVariant;
use crate::library::codegen::generator::api_dart::spec_generator::info::ApiDartGeneratorInfoTrait;

pub(crate) fn compute_func_implementation(
ir: &MirTypeDelegateProxyVariant,
context: ApiDartGeneratorContext,
func_mode: MirFuncMode,
) -> String {
let mut ans = format!("{}(this)", compute_dart_extra_type(ir, context));
if func_mode == MirFuncMode::Normal {
ans = format!("Future.value({ans})");
}
ans
}

pub(crate) fn compute_dart_extra_type(
ir: &MirTypeDelegateProxyVariant,
context: ApiDartGeneratorContext,
) -> String {
let inner_dart_api_type = ApiDartGenerator::new(ir.inner.clone(), context).dart_api_type();
let upstream_dart_api_type =
ApiDartGenerator::new(ir.upstream.clone(), context).dart_api_type();
format!(
"{}ProxyVariant{}",
inner_dart_api_type, upstream_dart_api_type
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
use crate::codegen::generator::api_dart::spec_generator::class::method::{
generate_api_methods, GenerateApiMethodConfig, GenerateApiMethodMode,
};
use crate::codegen::generator::api_dart::spec_generator::class::ty::ApiDartGeneratorClassTrait;
use crate::codegen::generator::api_dart::spec_generator::class::ApiDartGeneratedClass;
use crate::codegen::generator::api_dart::spec_generator::class::{
proxy_variant, ApiDartGeneratedClass,
};
use crate::codegen::ir::mir::ty::delegate::{
MirTypeDelegate, MirTypeDelegateArray, MirTypeDelegateArrayMode, MirTypeDelegatePrimitiveEnum,
MirTypeDelegateProxyVariant,
};
use crate::codegen::ir::mir::ty::MirType;
use crate::library::codegen::generator::api_dart::spec_generator::base::*;
use crate::library::codegen::generator::api_dart::spec_generator::info::ApiDartGeneratorInfoTrait;
use crate::utils::basic_code::dart_header_code::DartHeaderCode;
use crate::utils::namespace::NamespacedName;

impl<'a> ApiDartGeneratorClassTrait for DelegateApiDartGenerator<'a> {
fn generate_class(&self) -> Option<ApiDartGeneratedClass> {
Expand All @@ -17,6 +25,13 @@ impl<'a> ApiDartGeneratorClassTrait for DelegateApiDartGenerator<'a> {
_ => None,
}
}

fn generate_extra_impl_code(&self) -> Option<String> {
match &self.mir {
MirTypeDelegate::ProxyVariant(mir) => Some(generate_proxy_variant(mir, self.context)),
_ => None,
}
}
}

fn generate_array(
Expand Down Expand Up @@ -66,3 +81,34 @@ fn generate_array(
needs_freezed: false,
})
}

fn generate_proxy_variant(
mir: &MirTypeDelegateProxyVariant,
context: ApiDartGeneratorContext,
) -> String {
let class_name = proxy_variant::compute_dart_extra_type(mir, context);

let implements_name = ApiDartGenerator::new(mir.inner.clone(), context).dart_api_type();
let upstream_name = ApiDartGenerator::new(mir.upstream.clone(), context).dart_api_type();

let methods = generate_api_methods(
&MirType::Delegate(MirTypeDelegate::ProxyVariant(mir.clone())),
context,
&GenerateApiMethodConfig {
mode_static: GenerateApiMethodMode::Nothing,
mode_non_static: GenerateApiMethodMode::DeclAndImpl,
},
&class_name,
);
let methods_str = methods.code;

format!(
"class {class_name} with SimpleDisposable implements {implements_name} {{
final {upstream_name} _upstream;
{class_name}(this._upstream);
{methods_str}
}}"
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use crate::codegen::generator::api_dart::spec_generator::class::misc::generate_c
use crate::codegen::generator::api_dart::spec_generator::class::ty::ApiDartGeneratorClassTrait;
use crate::codegen::generator::api_dart::spec_generator::class::ApiDartGeneratedClass;
use crate::codegen::ir::mir::ty::enumeration::MirEnumMode;
use crate::codegen::ir::mir::ty::MirType;
use crate::library::codegen::generator::api_dart::spec_generator::base::*;

impl<'a> ApiDartGeneratorClassTrait for EnumRefApiDartGenerator<'a> {
fn generate_class(&self) -> Option<ApiDartGeneratedClass> {
let src = self.mir.get(self.context.mir_pack);

let methods = generate_api_methods(
&src.name,
&MirType::EnumRef(self.mir.clone()),
self.context,
&GenerateApiMethodConfig::COMBINED,
&src.name.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,9 @@ impl RustOpaqueApiDartGenerator<'_> {
dart_class_name_postfix: &str,
) -> Info {
let dart_api_type = ApiDartGenerator::new(self.mir.clone(), self.context).dart_api_type();
let type_query_name = compute_query_name(&self.mir);

let methods = generate_api_methods(
&NamespacedName::new(self.mir.namespace.clone(), type_query_name.clone()),
&MirType::RustOpaque(self.mir.clone()),
self.context,
config,
&format!("{dart_api_type}{dart_class_name_postfix}"),
Expand All @@ -126,15 +125,6 @@ struct Info {
methods: GeneratedApiMethods,
}

fn compute_query_name(mir: &MirTypeRustOpaque) -> String {
lazy_static! {
static ref FILTER: Regex =
Regex::new(r"^flutter_rust_bridge::for_generated::RustAutoOpaqueInner<(.*)>$").unwrap();
}

FILTER.replace_all(&mir.inner.0, "$1").to_string()
}

fn generate_implements(
all_trait_impls: &[MirTraitImpl],
self_type: &MirTypeRustOpaque,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::codegen::generator::api_dart::spec_generator::class::ApiDartGenerated
use crate::codegen::generator::api_dart::spec_generator::misc::{
generate_dart_comments, generate_dart_metadata,
};
use crate::codegen::ir::mir::ty::MirType;
use crate::library::codegen::generator::api_dart::spec_generator::base::*;

impl<'a> ApiDartGeneratorClassTrait for StructRefApiDartGenerator<'a> {
Expand All @@ -20,7 +21,7 @@ impl<'a> ApiDartGeneratorClassTrait for StructRefApiDartGenerator<'a> {
let class_name = &self.mir.ident.0.name;

let methods = generate_api_methods(
&src.name,
&MirType::StructRef(self.mir.clone()),
self.context,
&GenerateApiMethodConfig::COMBINED,
class_name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use crate::codegen::generator::api_dart::spec_generator::class::method::{
};
use crate::codegen::generator::api_dart::spec_generator::class::ty::ApiDartGeneratorClassTrait;
use crate::codegen::generator::api_dart::spec_generator::class::ApiDartGeneratedClass;
use crate::codegen::ir::mir::ty::MirType;
use crate::library::codegen::generator::api_dart::spec_generator::base::*;

impl<'a> ApiDartGeneratorClassTrait for TraitDefApiDartGenerator<'a> {
fn generate_class(&self) -> Option<ApiDartGeneratedClass> {
let dart_api_type = &self.mir.name.name;
let methods = generate_api_methods(
&self.mir.name,
&MirType::TraitDef(self.mir.clone()),
self.context,
&GenerateApiMethodConfig {
mode_static: GenerateApiMethodMode::Nothing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ impl<'a> ApiDartGeneratorInfoTrait for DelegateApiDartGenerator<'a> {
MirTypeDelegate::RustAutoOpaqueExplicit(mir) => {
ApiDartGenerator::new(mir.inner.clone(), self.context).dart_api_type()
} // MirTypeDelegate::DynTrait(mir) => mir.trait_def_name.name.clone(),
MirTypeDelegate::ProxyVariant(mir) => {
ApiDartGenerator::new(mir.inner.clone(), self.context).dart_api_type()
}
MirTypeDelegate::ProxyEnum(mir) => {
ApiDartGenerator::new(mir.original.clone(), self.context).dart_api_type()
}
}
}

Expand Down
Loading

0 comments on commit 1dcc30b

Please sign in to comment.