Skip to content

Commit

Permalink
Merge pull request #2093 from fzyzcjy/feat/12281
Browse files Browse the repository at this point in the history
  • Loading branch information
fzyzcjy authored Jun 16, 2024
2 parents 256ed44 + 32c4796 commit c8e0736
Show file tree
Hide file tree
Showing 107 changed files with 21,978 additions and 2,226 deletions.
2 changes: 1 addition & 1 deletion .all-contributors-custom.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- sagudev: Make code generator a `lib`. Add error types. Depend on `cbindgen`. Fix LLVM paths. Update deps. Fix CI errors.
- surban: Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields.
- Roms1383: Fix build_runner calling bug. Remove global `ffigen` dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup.
- dbsxdbsx: Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging.
- dbsxdbsx: Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods.
- GregoryConrad: Add doc to setup frb inside a Dart/Flutter library.
- huang12zheng: Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model.
- trobanga: Add support for `[T;N]` structs. Add `usize` support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque.
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 2.0.0-dev.40

* Please refer to https://fzyzcjy.github.io/flutter_rust_bridge/guides/miscellaneous/whats-new for what's changed in V2.
* Support returning types with non-static lifetime (i.e. borrowed types / reference types) #2088 #2093
* Loosen config field `rust_input` syntax with delimit `,` #2092 (thanks @dbsxdbsx)
* Add prefix for automatically generated get/set methods of `#[frb(opaque)]` types to avoid conflicting with existing methods #2090 (thanks @dbsxdbsx)
* Support adding arbitrary code in generated Rust file via rust_preamble config #2086
* Support ignoring a whole module by `#[frb(ignore)]` on module #2085
* Support `/// frb:...` #2085

## 2.0.0-dev.39

* Please refer to https://fzyzcjy.github.io/flutter_rust_bridge/guides/miscellaneous/whats-new for what's changed in V2.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ More specifically, thanks for all these contributions:
* [sagudev](https://github.com/sagudev): Make code generator a `lib`. Add error types. Depend on `cbindgen`. Fix LLVM paths. Update deps. Fix CI errors.
* [surban](https://github.com/surban): Support unit return type. Skip unresolvable modules. Ignore prefer_const_constructors. Non-final Dart fields.
* [Roms1383](https://github.com/Roms1383): Fix build_runner calling bug. Remove global `ffigen` dependency. Improve version check. Fix enum name-variant conflicts. Support Chrono date time and UUID types. Migrate to Rust 1.64 workspace. Update and refactor CI. Update header comments. Code cleanup.
* [dbsxdbsx](https://github.com/dbsxdbsx): Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging.
* [dbsxdbsx](https://github.com/dbsxdbsx): Allow generating multiple Rust and Dart files. Fix lint. Update doc. Add logging. Loosen config. Prefix methods.
* [GregoryConrad](https://github.com/GregoryConrad): Add doc to setup frb inside a Dart/Flutter library.
* [huang12zheng](https://github.com/huang12zheng): Support type aliases and nested ones. Tweak code generation. Fix rust_build_and_test on Mac. Improve CI logic and cache. Remove bridge field in model.
* [trobanga](https://github.com/trobanga): Add support for `[T;N]` structs. Add `usize` support. Add a cmd argument. Separate dart tests. Fix fallible list case. Fix test compile. Fix Result + RustAutoOpaque.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use super::*;
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lockable};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};

// Section: boilerplate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
clippy::too_many_arguments,
clippy::match_single_binding,
clippy::clone_on_copy,
clippy::let_unit_value
clippy::let_unit_value,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::borrow_deref_ref,
clippy::needless_borrow
)]

// Section: imports

use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lockable};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};

// Section: boilerplate
Expand Down Expand Up @@ -64,8 +68,9 @@ fn wire__crate__api__simple__greet_impl(
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_name = <String>::sse_decode(&mut deserializer);
deserializer.end();
transform_result_sse((move || {
Result::<_, ()>::Ok(crate::api::simple::greet(api_name))
transform_result_sse::<_, ()>((move || {
let output_ok = Result::<_, ()>::Ok(crate::api::simple::greet(api_name))?;
Ok(output_ok)
})())
},
)
Expand Down Expand Up @@ -94,10 +99,11 @@ fn wire__crate__api__simple__init_app_impl(
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
deserializer.end();
move |context| {
transform_result_sse((move || {
Result::<_, ()>::Ok({
transform_result_sse::<_, ()>((move || {
let output_ok = Result::<_, ()>::Ok({
crate::api::simple::init_app();
})
})?;
Ok(output_ok)
})())
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::*;
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
use flutter_rust_bridge::for_generated::wasm_bindgen;
use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;
use flutter_rust_bridge::for_generated::{transform_result_dco, Lockable};
use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};

// Section: boilerplate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,16 @@ pub(super) fn generate_code_postprocess_inner_output(func: &MirFunc) -> String {
let dependencies = (func.inputs.iter())
.filter(|field| is_interest_field(field))
.map(get_variable_name)
.flat_map(|field_name| {
vec![
format!("api_{field_name}"),
format!("api_{field_name}_guard"),
]
.map(|field_name| {
format!(
"flutter_rust_bridge::for_generated::LifetimeableDependency::new_guard_lockable(
Box::new(api_{field_name}_guard.clone()),
Box::new(api_{field_name}.clone()),
)"
)
})
.map(|var_name| format!("Box::new({var_name}.clone())"))
.join(", ");
format!("let output_ok = RustAutoOpaque::new(flutter_rust_bridge::for_generated::Lifetimeable::new(output_ok, vec![{dependencies}]));")
format!(
"let output_ok = RustAutoOpaque::new(Lifetimeable::new(output_ok, vec![{dependencies}]));"
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ fn compute_interest_field_ownership_mode(ty: &MirType) -> Option<OwnershipMode>
}
// temporarily only support Ref
MirType::Delegate(MirTypeDelegate::DynTrait(_)) => Some(OwnershipMode::Ref),
MirType::Delegate(MirTypeDelegate::Lifetimeable(_)) => Some(OwnershipMode::Ref),
MirType::Delegate(MirTypeDelegate::Lifetimeable(mir)) => {
Some(if mir.api_type.ownership_mode == OwnershipMode::RefMut {
OwnershipMode::RefMut
} else {
OwnershipMode::Ref
})
}
_ => None,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ clippy::let_and_return,
clippy::too_many_arguments,
clippy::match_single_binding,
clippy::clone_on_copy,
clippy::let_unit_value
clippy::let_unit_value,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::borrow_deref_ref,
clippy::needless_borrow
)]"#;

fn generate_imports(
Expand All @@ -117,7 +121,7 @@ fn generate_imports(

// NOTE Do *not* use imports when possible, instead use fully specified name directly
let static_imports = "use flutter_rust_bridge::{Handler, IntoIntoDart};
use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco};
use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable};
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};";

Acc::new(|target| {
Expand Down
4 changes: 3 additions & 1 deletion frb_codegen/src/library/codegen/ir/mir/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ pub(crate) fn compute_interest_name_of_owner_ty(owner_ty: &MirType) -> Option<Na
NamespacedName::new(ty.self_namespace().unwrap(), ty.rust_api_type())
}
MirType::Delegate(MirTypeDelegate::Lifetimeable(ty)) => {
return compute_interest_name_of_owner_ty(&ty.api_type)
return compute_interest_name_of_owner_ty(&MirType::RustAutoOpaqueImplicit(
ty.api_type.clone(),
))
}
MirType::TraitDef(ty) => ty.name.clone(),
_ => return None,
Expand Down
6 changes: 4 additions & 2 deletions frb_codegen/src/library/codegen/ir/mir/ty/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use crate::codegen::ir::mir::ty::general_list::{mir_list, MirTypeGeneralList};
use crate::codegen::ir::mir::ty::primitive::MirTypePrimitive;
use crate::codegen::ir::mir::ty::primitive_list::MirTypePrimitiveList;
use crate::codegen::ir::mir::ty::record::MirTypeRecord;
use crate::codegen::ir::mir::ty::rust_auto_opaque_implicit::MirRustAutoOpaqueRaw;
use crate::codegen::ir::mir::ty::rust_auto_opaque_implicit::{
MirRustAutoOpaqueRaw, MirTypeRustAutoOpaqueImplicit,
};
use crate::codegen::ir::mir::ty::rust_opaque::MirTypeRustOpaque;
use crate::codegen::ir::mir::ty::{MirContext, MirType, MirTypeTrait};
use crate::utils::namespace::{Namespace, NamespacedName};
Expand Down Expand Up @@ -113,7 +115,7 @@ pub struct MirTypeDelegateDynTrait {
}

pub struct MirTypeDelegateLifetimeable {
pub api_type: Box<MirType>,
pub api_type: MirTypeRustAutoOpaqueImplicit,
pub delegate: MirTypeDelegateRustAutoOpaqueExplicit,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use crate::codegen::parser::mir::parser::lifetime_extractor::{Lifetime, Lifetime
use anyhow::ensure;
use itertools::Itertools;
use std::collections::HashSet;
use syn::{ReturnType, Signature};
use syn::{ReturnType, Signature, Type};

pub(crate) fn parse_function_lifetime(
sig: &Signature,
owner: &MirFuncOwnerInfo,
) -> anyhow::Result<ParseFunctionLifetimeOutput> {
let inputs_lifetimes = (sig.inputs.iter())
.map(|x| {
Ok(LifetimeExtractor::extract_skipping_static(
Ok(extract_lifetime_skipping_static_and_anonymous(
&parse_argument_ty_and_name(x, owner)?.0,
))
})
.collect::<anyhow::Result<Vec<_>>>()?;
let output_lifetimes = match &sig.output {
ReturnType::Type(_, ty) => LifetimeExtractor::extract_skipping_static(ty),
ReturnType::Type(_, ty) => extract_lifetime_skipping_static_and_anonymous(ty),
ReturnType::Default => vec![],
};

Expand All @@ -37,6 +37,12 @@ pub(crate) fn parse_function_lifetime(
Ok(ans)
}

fn extract_lifetime_skipping_static_and_anonymous(ty: &Type) -> Vec<Lifetime> {
(LifetimeExtractor::extract_skipping_static(ty).into_iter())
.filter(|x| !x.is_anonymous())
.collect_vec()
}

fn ensure_one_lifetime(
inputs_lifetimes: &[Vec<Lifetime>],
output_lifetimes: &[Lifetime],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ pub(crate) fn is_struct_or_enum_or_opaque_from_them(ty: &MirType) -> bool {
ty.reason == Some(MirTypeRustAutoOpaqueImplicitReason::StructOrEnumRequireOpaque)
}
MirType::Delegate(MirTypeDelegate::Lifetimeable(ty)) => {
is_struct_or_enum_or_opaque_from_them(&ty.api_type)
is_struct_or_enum_or_opaque_from_them(&MirType::RustAutoOpaqueImplicit(
ty.api_type.clone(),
))
}
_ => false,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl LifetimeExtractor {
pub(crate) fn extract_skipping_static(ty: &Type) -> Vec<Lifetime> {
// log::debug!("extract_skipping_static ans={ans:?} ty={ty:?}");
(Self::extract(ty).into_iter())
.filter(|lifetime| lifetime.0 != LIFETIME_STATIC)
.filter(|lifetime| !lifetime.is_static())
.collect_vec()
}

Expand Down Expand Up @@ -38,11 +38,22 @@ impl LifetimeExtractor {
}

pub(crate) const LIFETIME_STATIC: &str = "static";
pub(crate) const LIFETIME_ANONYMOUS: &str = "_";

// TODO maybe move
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct Lifetime(pub String);

impl Lifetime {
pub(crate) fn is_static(&self) -> bool {
self.0 == LIFETIME_STATIC
}

pub(crate) fn is_anonymous(&self) -> bool {
self.0 == LIFETIME_ANONYMOUS
}
}

impl From<&syn::Lifetime> for Lifetime {
fn from(value: &syn::Lifetime) -> Self {
Self(value.ident.to_string())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ impl<'a, 'b, 'c> TypeParserWithContext<'a, 'b, 'c> {
namespace: Option<Namespace>,
) -> anyhow::Result<MirType> {
if !self.context.enable_lifetime {
self.maybe_log_not_enable_lifetime();
return Ok(MirType::RustAutoOpaqueImplicit(original));
}

Expand All @@ -26,15 +27,15 @@ impl<'a, 'b, 'c> TypeParserWithContext<'a, 'b, 'c> {
}

let delegate_ty_str = format!(
"flutter_rust_bridge::for_generated::Lifetimeable<{}>",
"Lifetimeable<{}>",
replace_lifetimes_to_static(ty_str, &lifetimes)
);

let inner_dart_api_type = original.inner.sanitized_type();

Ok(MirType::Delegate(MirTypeDelegate::Lifetimeable(
MirTypeDelegateLifetimeable {
api_type: Box::new(MirType::RustAutoOpaqueImplicit(original)),
api_type: original,
delegate: self.parse_rust_auto_opaque_explicit_typed(
&syn::parse_str(&delegate_ty_str)?,
namespace,
Expand All @@ -44,4 +45,12 @@ impl<'a, 'b, 'c> TypeParserWithContext<'a, 'b, 'c> {
},
)))
}

fn maybe_log_not_enable_lifetime(&mut self) {
if !self.inner.has_logged_lifetimeable {
log::info!("To handle some types, `enable_lifetime: true` may need to be set. \
Please visit https://fzyzcjy.github.io/flutter_rust_bridge/guides/lifetimes for more details");
}
self.inner.has_logged_lifetimeable = true;
}
}
2 changes: 2 additions & 0 deletions frb_codegen/src/library/codegen/parser/mir/parser/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub(crate) struct TypeParser<'a> {
rust_opaque_parser_info: RustOpaqueParserInfo,
rust_auto_opaque_parser_info: RustAutoOpaqueParserInfo,
array_parser_info: ArrayParserInfo,
has_logged_lifetimeable: bool,
}

impl<'a> TypeParser<'a> {
Expand Down Expand Up @@ -102,6 +103,7 @@ impl<'a> TypeParser<'a> {
rust_opaque_parser_info: RustOpaqueParserInfo::default(),
rust_auto_opaque_parser_info: RustAutoOpaqueParserInfo::default(),
array_parser_info: Default::default(),
has_logged_lifetimeable: false,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"mir": {
"default_rust_opaque_codec": "Moi",
"default_stream_sink_codec": "Sse",
"enable_lifetime": false,
"force_codec_mode_pack": {
"dart2rust": "Pde",
"rust2dart": "Pde"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"mir": {
"default_rust_opaque_codec": "Moi",
"default_stream_sink_codec": "Sse",
"enable_lifetime": false,
"force_codec_mode_pack": {
"dart2rust": "Pde",
"rust2dart": "Pde"
Expand Down
Loading

0 comments on commit c8e0736

Please sign in to comment.