Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Result<MyType, MyError> with exception throwing on Dart #582

Closed
wants to merge 89 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
75be93a
first try
lattice0 Jul 18, 2022
6f5a6fb
try2
lattice0 Jul 18, 2022
34b58ad
rollback
lattice0 Jul 18, 2022
e75094b
error handling
lattice0 Jul 18, 2022
82fde94
parseErrorData
lattice0 Jul 18, 2022
4407912
generates correct code
lattice0 Jul 18, 2022
3d0a427
works
lattice0 Jul 18, 2022
cc78745
works
lattice0 Jul 18, 2022
17c785d
works
lattice0 Jul 18, 2022
99677e4
works
lattice0 Jul 18, 2022
e87dfeb
works!
lattice0 Jul 18, 2022
b4925e5
nested errors work
lattice0 Jul 18, 2022
28b776e
rem dirt
lattice0 Jul 18, 2022
b470a1d
add book
lattice0 Jul 18, 2022
8306ca1
changes
lattice0 Jul 18, 2022
da91bfa
fixes
lattice0 Jul 18, 2022
4b89eaa
Merge branch 'master' of https://github.com/fzyzcjy/flutter_rust_brid…
lattice0 Jul 18, 2022
938fba5
implements exception
lattice0 Jul 19, 2022
6fc4f71
struct exceptions work as well
lattice0 Jul 19, 2022
ce96d39
clean printlns
lattice0 Jul 19, 2022
74ec09e
proper fmt
lattice0 Jul 19, 2022
0b41f65
adding exception backtrace support
lattice0 Jul 20, 2022
b5485c3
exception gen works
lattice0 Jul 24, 2022
17fdfeb
exceptions
lattice0 Jul 24, 2022
e98b820
errors
lattice0 Jul 24, 2022
1edbf98
pass
lattice0 Jul 24, 2022
46802a1
cleanup
lattice0 Jul 24, 2022
94b3e92
Merge branch 'master' of https://github.com/fzyzcjy/flutter_rust_brid…
lattice0 Jul 24, 2022
4bd5820
pass
lattice0 Jul 24, 2022
22f8423
backtrace
lattice0 Jul 24, 2022
9e74c48
clippy
lattice0 Jul 24, 2022
db40975
removes cargo
lattice0 Jul 24, 2022
dcc5d6b
fmt
lattice0 Jul 24, 2022
19d53b6
Update and rename feature_result.md to lang_result.md
fzyzcjy Jul 25, 2022
2eec320
Update SUMMARY.md
fzyzcjy Jul 25, 2022
8721719
Update SUMMARY.md
fzyzcjy Jul 25, 2022
5e5ae9b
adds backtrace
lattice0 Jul 28, 2022
182eadd
Merge branch 'error' of https://github.com/lattice0/flutter_rust_brid…
lattice0 Jul 28, 2022
e53323d
backtrace
lattice0 Jul 29, 2022
006fc03
backtrace
lattice0 Jul 29, 2022
3a3e94d
adds backtrace
lattice0 Jul 29, 2022
424f616
fix
lattice0 Jul 29, 2022
4e7d6a2
backtrace format
lattice0 Jul 29, 2022
2a82f72
disabled backtrace
lattice0 Jul 29, 2022
3d92aa9
multi
lattice0 Jul 30, 2022
50e83dd
tests pass
lattice0 Jul 30, 2022
c2ed509
dart fmt
lattice0 Jul 30, 2022
5abee1d
fmt
lattice0 Jul 30, 2022
cf8ed09
dart fmt
lattice0 Jul 30, 2022
1eab8a9
format
lattice0 Jul 30, 2022
5a665c8
more fmt
lattice0 Jul 30, 2022
44198ff
book
lattice0 Jul 30, 2022
885642f
rm submodule
lattice0 Jul 30, 2022
74ab207
Update lang_result.md
fzyzcjy Jul 30, 2022
ffc7635
checkpoint
lattice0 Jul 31, 2022
6fc3d06
mods
lattice0 Jul 31, 2022
fc04bd1
Merge branch 'error' of https://github.com/lattice0/flutter_rust_brid…
lattice0 Jul 31, 2022
b601ff9
cleaner
lattice0 Jul 31, 2022
ae89007
backtrace contains
lattice0 Jul 31, 2022
a07bd04
cleanup
lattice0 Jul 31, 2022
69e7a83
removes unnecessary files
lattice0 Jul 31, 2022
f1a7ab8
!
lattice0 Jul 31, 2022
bd7ca05
small corrections
lattice0 Jul 31, 2022
468de1d
first functios
lattice0 Jul 31, 2022
cf48221
implements frb
lattice0 Jul 31, 2022
e8dc72e
checkpoint
lattice0 Aug 3, 2022
f409204
box into dart
lattice0 Aug 3, 2022
902c8f3
anyhow
lattice0 Aug 4, 2022
4a80be0
backtrace delegate
lattice0 Aug 4, 2022
9511ba9
anyhow error
lattice0 Aug 4, 2022
2034428
result
lattice0 Aug 5, 2022
73cd4f5
anyhow::Result fixed
lattice0 Aug 5, 2022
74bd096
mods
lattice0 Aug 5, 2022
b86e01d
rm submodule
lattice0 Aug 5, 2022
9e27215
more
lattice0 Aug 5, 2022
0775f00
handler
lattice0 Aug 5, 2022
36b200d
diff
lattice0 Aug 5, 2022
12e794e
removes unused import
lattice0 Aug 5, 2022
973f210
ignore error
lattice0 Aug 6, 2022
db99e61
disables another error
lattice0 Aug 6, 2022
3e08698
removes other error
lattice0 Aug 6, 2022
da22e04
disables
lattice0 Aug 6, 2022
4049d17
one test
lattice0 Aug 6, 2022
d819796
returnCustomStructError
lattice0 Aug 6, 2022
9551f70
valgrind install
lattice0 Aug 6, 2022
06fb443
update
lattice0 Aug 6, 2022
c125477
sudo
lattice0 Aug 6, 2022
51ec4f8
libc6-dbg
lattice0 Aug 6, 2022
bf5829c
rerun
lattice0 Aug 6, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ jobs:
python-version: "3.x"

- name: Install valgrind and llvm
run: sudo apt update && sudo apt install -y valgrind libclang-dev
run: |
sudo apt update && sudo apt install -y libclang-dev libc6-dbg \
&& wget -O valgrind.tar.bz2 https://sourceware.org/pub/valgrind/valgrind-3.19.0.tar.bz2 \
&& mkdir valgrind && tar -xvjf valgrind.tar.bz2 -C valgrind --strip-components=1 \
&& cd valgrind && ./configure && make && sudo make install

- uses: dart-lang/setup-dart@v1

Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- [External types](feature/lang_external.md)
- [Option](feature/lang_option.md)
- [Methods](feature/lang_methods.md)
- [Result](feature/lang_result.md)
- [Return types](feature/lang_return_types.md)
- [Zero copy](feature/zero_copy.md)
- [Stream / Iterator](feature/stream.md)
Expand Down
51 changes: 51 additions & 0 deletions book/src/feature/lang_result.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Result

There is support for Rust's `std::Result`, where you can return either a value or an error.

## `anyhow`

You can use `anyhow::Result` as a return value, and backtraces will be captured automatically.

## Custom errors

Errors with custom fields are also supported, and you can even pass a backtrace.

### Example 1: Without backtrace

```rust,noplayground

pub enum CustomError {
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
Error0(String),
Error1(u32),
}

pub fn return_err_custom_error() -> Result<u32, CustomError> {
Err(CustomError::Error1(3))
}
```

Becomes something that can be used like this:

```Dart
try {
final r = await api.returnErrCustomError();
print("received $r");
} catch (e) {
print('dart catch e: $e');
expect(e, isA<CustomError>());
}
}
```

### Example 2: With backtrace

Errors with custom fields are also supported, and you can even pass a backtrace:

```rust
pub enum CustomStructError {
Error0 { e: String, backtrace: Backtrace },
Error1 { e: u32, backtrace: Backtrace },
}
```

As for how to fill it in or use it, you can refer to `thiserror` crate for some hints.
2 changes: 1 addition & 1 deletion frb_codegen/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::ir::IrFile;
use crate::parser;
use crate::utils::BlockIndex;

#[derive(StructOpt, Debug, PartialEq, Deserialize, Default)]
#[derive(StructOpt, Debug, PartialEq, Eq, Deserialize, Default)]
#[structopt(setting(AppSettings::DeriveDisplayOrder))]
pub struct RawOpts {
/// Path of input Rust code
Expand Down
16 changes: 14 additions & 2 deletions frb_codegen/src/generator/dart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ fn generate_api_func(func: &IrFunc, ir_file: &IrFile) -> GeneratedApiFunc {
};
let parse_sucess_data = if (f.is_static_method()
&& f.struct_name().unwrap() == {
if let IrType::StructRef(IrTypeStructRef { name, freezed: _ }) = &func.output {
if let IrType::StructRef(IrTypeStructRef {
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
name,
..
}) = &func.output
{
name.clone()
} else {
"".to_string()
Expand All @@ -424,6 +428,12 @@ fn generate_api_func(func: &IrFunc, ir_file: &IrFile) -> GeneratedApiFunc {
format!("_wire2api_{}", func.output.safe_ident())
};

let parse_error_data = if let Some(error_output) = &func.error_output {
format!("_wire2api_{},", error_output.safe_ident())
} else {
"null,".to_string()
};

let implementation = match func.mode {
IrFuncMode::Sync => format!(
"{} => {}(FlutterRustBridgeSyncTask(
Expand All @@ -440,13 +450,15 @@ fn generate_api_func(func: &IrFunc, ir_file: &IrFile) -> GeneratedApiFunc {
"{} => {}(FlutterRustBridgeTask(
callFfi: (port_) => inner.{}({}),
parseSuccessData: {},
parseErrorData: {}
{}
));",
partial,
execute_func_name,
func.wire_func_name(),
wire_param_list.join(", "),
parse_sucess_data,
parse_error_data,
task_common_args,
),
};
Expand Down Expand Up @@ -521,7 +533,7 @@ fn generate_api_fill_to_wire_func(ty: &IrType, ir_file: &IrFile) -> String {
}

fn generate_wire2api_func(ty: &IrType, ir_file: &IrFile, dart_api_class_name: &str) -> String {
let extra_argument = if matches!(ty, StructRef(IrTypeStructRef { name, freezed: _ }) if MethodNamingUtil::has_methods(name, ir_file))
let extra_argument = if matches!(ty, StructRef(IrTypeStructRef { name, ..}) if MethodNamingUtil::has_methods(name, ir_file))
{
format!("{} bridge,", dart_api_class_name)
} else {
Expand Down
4 changes: 4 additions & 0 deletions frb_codegen/src/generator/dart/ty_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ impl TypeDartGeneratorTrait for TypeDelegateGenerator<'_> {
IrTypeDelegate::PrimitiveEnum { ref repr, .. } => {
format!("return _api2wire_{}(raw.index);", repr.safe_ident())
}
IrTypeDelegate::Backtrace => unimplemented!(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO(fzyzcjy): Check whether valgrind suppress is ok

(unrelated to this line of code, just a reminder for me)

IrTypeDelegate::Anyhow => unimplemented!(),
})
}

fn wire2api_body(&self) -> String {
match &self.ir {
IrTypeDelegate::String
| IrTypeDelegate::Backtrace
| IrTypeDelegate::SyncReturnVecU8
| IrTypeDelegate::ZeroCopyBufferVecPrimitive(_) => {
gen_wire2api_simple_type_cast(&self.ir.dart_api_type())
Expand All @@ -46,6 +49,7 @@ impl TypeDartGeneratorTrait for TypeDelegateGenerator<'_> {
IrTypeDelegate::PrimitiveEnum { ir, .. } => {
format!("return {}.values[raw];", ir.dart_api_type())
}
IrTypeDelegate::Anyhow => "return FrbAnyhowException(raw as String);".to_string(),
}
}

Expand Down
19 changes: 16 additions & 3 deletions frb_codegen/src/generator/dart/ty_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::generator::dart::dart_comments;
use crate::generator::dart::ty::*;
use crate::ir::*;
use crate::type_dart_generator_struct;
use crate::utils::dart_maybe_implements_exception;
use crate::utils::BlockIndex;

type_dart_generator_struct!(TypeEnumRefGenerator, IrTypeEnumRef);
Expand Down Expand Up @@ -107,6 +108,11 @@ impl TypeDartGeneratorTrait for TypeEnumRefGenerator<'_> {
.variants()
.iter()
.map(|variant| {
let has_backtrace = matches!(&variant.kind, IrVariantKind::Struct(IrStruct {
is_fields_named: true,
fields,
..
}) if fields.iter().any(|field| field.name.raw =="backtrace"));
let args = match &variant.kind {
IrVariantKind::Value => "".to_owned(),
IrVariantKind::Struct(IrStruct {
Expand Down Expand Up @@ -152,8 +158,14 @@ impl TypeDartGeneratorTrait for TypeEnumRefGenerator<'_> {
format!("{{ {} }}", fields.join(""))
}
};
let implements_exception = if self.ir.is_exception && has_backtrace {
"@Implements<FrbBacktracedException>()"
} else {
""
};
format!(
"{}const factory {}.{}({}) = {};",
"{} {}const factory {}.{}({}) = {};",
implements_exception,
dart_comments(&variant.comments),
self.ir.name,
variant.name.dart_style(),
Expand All @@ -164,10 +176,11 @@ impl TypeDartGeneratorTrait for TypeEnumRefGenerator<'_> {
.collect::<Vec<_>>();
format!(
"@freezed
class {0} with _${0} {{
{1}
class {0} with _${0} {1} {{
{2}
}}",
self.ir.name,
dart_maybe_implements_exception(self.ir.is_exception),
variants.join("\n")
)
} else {
Expand Down
21 changes: 11 additions & 10 deletions frb_codegen/src/generator/dart/ty_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::generator::dart::{dart_comments, dart_metadata, GeneratedApiMethod};
use crate::ir::*;
use crate::method_utils::FunctionName;
use crate::type_dart_generator_struct;
use crate::utils::BlockIndex;
use crate::utils::{dart_maybe_implements_exception, BlockIndex};
use convert_case::{Case, Casing};

type_dart_generator_struct!(TypeStructRefGenerator, IrTypeStructRef);
Expand Down Expand Up @@ -57,14 +57,13 @@ impl TypeDartGeneratorTrait for TypeStructRefGenerator<'_> {
inner.insert(0, "bridge: bridge,".to_string());
}
let inner = inner.join("\n");

let cast = "final arr = raw as List<dynamic>;".to_string();
lattice0 marked this conversation as resolved.
Show resolved Hide resolved
let safe_check = format!("if (arr.length != {}) throw Exception('unexpected arr length: expect {} but see ${{arr.length}}');", s.fields.len(), s.fields.len());
format!(
"final arr = raw as List<dynamic>;
if (arr.length != {}) throw Exception('unexpected arr length: expect {} but see ${{arr.length}}');
"{}
{}
return {}({});",
s.fields.len(),
s.fields.len(),
s.name, inner,
cast, safe_check, s.name, inner,
)
}

Expand Down Expand Up @@ -118,20 +117,22 @@ impl TypeDartGeneratorTrait for TypeStructRefGenerator<'_> {
)
})
.collect::<Vec<_>>();

if has_methods {
constructor_params.insert(0, extra_argument);
}
let constructor_params = constructor_params.join("");

format!(
"{}{}class {} with _${} {{
"{}{}class {} with _${} {} {{
const factory {}({{{}}}) = _{};
{}
}}",
comments,
metadata,
self.ir.name,
self.ir.name,
dart_maybe_implements_exception(self.ir.is_exception),
self.ir.name,
constructor_params,
self.ir.name,
Expand All @@ -156,7 +157,6 @@ impl TypeDartGeneratorTrait for TypeStructRefGenerator<'_> {
field_declarations.insert(0, field_bridge);
}
let field_declarations = field_declarations.join("\n");

let mut constructor_params = src
.fields
.iter()
Expand All @@ -175,7 +175,7 @@ impl TypeDartGeneratorTrait for TypeStructRefGenerator<'_> {
let constructor_params = constructor_params.join("");

format!(
"{}{}class {} {{
"{}{}class {} {} {{
{}

{}({{{}}});
Expand All @@ -185,6 +185,7 @@ impl TypeDartGeneratorTrait for TypeStructRefGenerator<'_> {
comments,
metadata,
self.ir.name,
dart_maybe_implements_exception(self.ir.is_exception),
field_declarations,
self.ir.name,
constructor_params,
Expand Down
2 changes: 1 addition & 1 deletion frb_codegen/src/generator/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ impl Generator {
let code_call_inner_func_result = if func.fallible {
code_call_inner_func
} else {
format!("Ok({})", code_call_inner_func)
format!("Result::<_,()>::Ok({})", code_call_inner_func)
};

let (handler_func_name, return_type, code_closure) = match func.mode {
Expand Down
1 change: 1 addition & 0 deletions frb_codegen/src/generator/rust/ty_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl TypeRustGeneratorTrait for TypeDelegateGenerator<'_> {
variants, enu.name
)
}
IrTypeDelegate::Backtrace | IrTypeDelegate::Anyhow => "self.wire2api()".to_owned(),
})
}

Expand Down
3 changes: 3 additions & 0 deletions frb_codegen/src/ir/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ impl IrFile {
}
if include_func_output {
func.output.visit_types(f, self);
if let Some(error_output) = &func.error_output {
error_output.visit_types(f, self);
}
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions frb_codegen/src/ir/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub struct IrFunc {
pub name: String,
pub inputs: Vec<IrField>,
pub output: IrType,
pub error_output: Option<IrType>,
pub fallible: bool,
Comment on lines +8 to 9
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether error_output and fallible kind of duplicated? Or shall we use an enum to represent all states?

e.g.

enum {
  CustomError(IrType),
  AnyhowError,
  Infallible,
}

or

enum {
  CustomError(IrType),
  Infallible,
}

etc

pub mode: IrFuncMode,
pub comments: Vec<IrComment>,
Expand All @@ -19,7 +20,7 @@ impl IrFunc {
/// Represents a function's output type
#[derive(Debug, Clone)]
pub enum IrFuncOutput {
ResultType(IrType),
ResultType { ok: IrType, error: Option<IrType> },
Type(IrType),
}

Expand All @@ -30,7 +31,7 @@ pub enum IrFuncArg {
Type(IrType),
}

#[derive(Debug, Clone, PartialOrd, PartialEq)]
#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
pub enum IrFuncMode {
Normal,
Sync,
Expand Down
2 changes: 1 addition & 1 deletion frb_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn optional_boundary_index(types: &[&IrType]) -> Option<usize> {
.enumerate()
.find(|ty| matches!(ty.1, Optional(_)))
.and_then(|(idx, _)| {
(&types[idx..])
(types[idx..])
.iter()
.all(|ty| matches!(ty, Optional(_)))
.then(|| idx)
Expand Down
10 changes: 10 additions & 0 deletions frb_codegen/src/ir/ty_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub enum IrTypeDelegate {
/// Allows for `#[repr]`'s other than [i32]
repr: IrTypePrimitive,
},
Backtrace,
Anyhow,
}

impl IrTypeDelegate {
Expand All @@ -30,6 +32,8 @@ impl IrTypeDelegate {
}
IrTypeDelegate::StringList => IrType::Delegate(IrTypeDelegate::String),
IrTypeDelegate::PrimitiveEnum { repr, .. } => IrType::Primitive(repr.clone()),
IrTypeDelegate::Backtrace => IrType::Delegate(IrTypeDelegate::String),
IrTypeDelegate::Anyhow => IrType::Delegate(IrTypeDelegate::String),
}
}
}
Expand All @@ -48,6 +52,8 @@ impl IrTypeTrait for IrTypeDelegate {
"ZeroCopyBuffer_".to_owned() + &self.get_delegate().dart_api_type()
}
IrTypeDelegate::PrimitiveEnum { ir, .. } => ir.safe_ident(),
IrTypeDelegate::Backtrace => "String".to_owned(),
IrTypeDelegate::Anyhow => "FrbAnyhowException".to_owned(),
}
}

Expand All @@ -59,6 +65,8 @@ impl IrTypeTrait for IrTypeDelegate {
self.get_delegate().dart_api_type()
}
IrTypeDelegate::PrimitiveEnum { ir, .. } => ir.dart_api_type(),
IrTypeDelegate::Backtrace => "String".to_string(),
IrTypeDelegate::Anyhow => "FrbAnyhowException".to_string(),
}
}

Expand All @@ -78,6 +86,8 @@ impl IrTypeTrait for IrTypeDelegate {
format!("ZeroCopyBuffer<{}>", self.get_delegate().rust_api_type())
}
IrTypeDelegate::PrimitiveEnum { ir, .. } => ir.rust_api_type(),
IrTypeDelegate::Backtrace => "String".to_owned(),
IrTypeDelegate::Anyhow => "String".to_owned(),
}
}

Expand Down
Loading