feat(bindings/dart): add File.read and File.write with error mapping (#7473)
Add read/write async and sync methods to the Dart File class,
mirroring Rust Operator::read and Operator::write.
Changes:
- rust/src/api/opendal_api.rs: add read/read_sync/write/write_sync
returning anyhow::Result so Rust errors surface as Dart exceptions
- rust/Cargo.toml: add anyhow = "1.0" dependency
- lib/opendal.dart: add File.read()/readSync()/write()/writeSync()
- tests/opendal_test.dart: add round-trip, missing-file throws, and
overwrite semantics tests
- Regenerate FRB bindings for new methods
Depends on FRB 2.12.0 upgrade (PR A).
Scope: bindings/dart only.
AI-assisted: od-kimi-scout-050121.
Co-authored-by: tianyizhuang <tianyizhuang@tianyizhuangs-Mac-mini.local>
diff --git a/bindings/dart/lib/opendal.dart b/bindings/dart/lib/opendal.dart
index 1c7d730..47c6999 100644
--- a/bindings/dart/lib/opendal.dart
+++ b/bindings/dart/lib/opendal.dart
@@ -16,6 +16,7 @@
// under the License.
import 'dart:io' as io;
+import 'dart:typed_data';
import 'package:system_info2/system_info2.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
import 'src/rust/frb_generated.dart';
@@ -148,6 +149,22 @@
void deleteSync() {
_operator.deleteSync(path: path);
}
+
+ Future<Uint8List> read() {
+ return _operator.read(path: path);
+ }
+
+ Uint8List readSync() {
+ return _operator.readSync(path: path);
+ }
+
+ Future<void> write(Uint8List data) {
+ return _operator.write(path: path, data: data);
+ }
+
+ void writeSync(Uint8List data) {
+ _operator.writeSync(path: path, data: data);
+ }
}
class Directory {
diff --git a/bindings/dart/lib/src/rust/api/opendal_api.dart b/bindings/dart/lib/src/rust/api/opendal_api.dart
index 9040eb5..640f033 100644
--- a/bindings/dart/lib/src/rust/api/opendal_api.dart
+++ b/bindings/dart/lib/src/rust/api/opendal_api.dart
@@ -56,6 +56,10 @@
RustLib.instance.api
.crateApiOpendalApiOperatorNew(scheme: scheme, map: map);
+ Future<Uint8List> read({required String path});
+
+ Uint8List readSync({required String path});
+
Future<void> rename({required String from, required String to});
void renameSync({required String from, required String to});
@@ -63,4 +67,8 @@
Future<Metadata> stat({required String path});
Metadata statSync({required String path});
+
+ Future<void> write({required String path, required List<int> data});
+
+ void writeSync({required String path, required List<int> data});
}
diff --git a/bindings/dart/lib/src/rust/frb_generated.dart b/bindings/dart/lib/src/rust/frb_generated.dart
index 2936c2a..c34acb2 100644
--- a/bindings/dart/lib/src/rust/frb_generated.dart
+++ b/bindings/dart/lib/src/rust/frb_generated.dart
@@ -68,7 +68,7 @@
String get codegenVersion => '2.12.0';
@override
- int get rustContentHash => 775125233;
+ int get rustContentHash => 798133092;
static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
@@ -120,6 +120,12 @@
Operator crateApiOpendalApiOperatorNew(
{required String scheme, required Map<String, String> map});
+ Future<Uint8List> crateApiOpendalApiOperatorRead(
+ {required Operator that, required String path});
+
+ Uint8List crateApiOpendalApiOperatorReadSync(
+ {required Operator that, required String path});
+
Future<void> crateApiOpendalApiOperatorRename(
{required Operator that, required String from, required String to});
@@ -132,6 +138,12 @@
Metadata crateApiOpendalApiOperatorStatSync(
{required Operator that, required String path});
+ Future<void> crateApiOpendalApiOperatorWrite(
+ {required Operator that, required String path, required List<int> data});
+
+ void crateApiOpendalApiOperatorWriteSync(
+ {required Operator that, required String path, required List<int> data});
+
RustArcIncrementStrongCountFnType
get rust_arc_increment_strong_count_Metadata;
@@ -577,6 +589,61 @@
);
@override
+ Future<Uint8List> crateApiOpendalApiOperatorRead(
+ {required Operator that, required String path}) {
+ return handler.executeNormal(NormalTask(
+ callFfi: (port_) {
+ final serializer = SseSerializer(generalizedFrbRustBinding);
+ sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator(
+ that, serializer);
+ sse_encode_String(path, serializer);
+ pdeCallFfi(generalizedFrbRustBinding, serializer,
+ funcId: 17, port: port_);
+ },
+ codec: SseCodec(
+ decodeSuccessData: sse_decode_list_prim_u_8_strict,
+ decodeErrorData: sse_decode_AnyhowException,
+ ),
+ constMeta: kCrateApiOpendalApiOperatorReadConstMeta,
+ argValues: [that, path],
+ apiImpl: this,
+ ));
+ }
+
+ TaskConstMeta get kCrateApiOpendalApiOperatorReadConstMeta =>
+ const TaskConstMeta(
+ debugName: "Operator_read",
+ argNames: ["that", "path"],
+ );
+
+ @override
+ Uint8List crateApiOpendalApiOperatorReadSync(
+ {required Operator that, required String path}) {
+ return handler.executeSync(SyncTask(
+ callFfi: () {
+ final serializer = SseSerializer(generalizedFrbRustBinding);
+ sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator(
+ that, serializer);
+ sse_encode_String(path, serializer);
+ return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 18)!;
+ },
+ codec: SseCodec(
+ decodeSuccessData: sse_decode_list_prim_u_8_strict,
+ decodeErrorData: sse_decode_AnyhowException,
+ ),
+ constMeta: kCrateApiOpendalApiOperatorReadSyncConstMeta,
+ argValues: [that, path],
+ apiImpl: this,
+ ));
+ }
+
+ TaskConstMeta get kCrateApiOpendalApiOperatorReadSyncConstMeta =>
+ const TaskConstMeta(
+ debugName: "Operator_read_sync",
+ argNames: ["that", "path"],
+ );
+
+ @override
Future<void> crateApiOpendalApiOperatorRename(
{required Operator that, required String from, required String to}) {
return handler.executeNormal(NormalTask(
@@ -587,7 +654,7 @@
sse_encode_String(from, serializer);
sse_encode_String(to, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
- funcId: 17, port: port_);
+ funcId: 19, port: port_);
},
codec: SseCodec(
decodeSuccessData: sse_decode_unit,
@@ -615,7 +682,7 @@
that, serializer);
sse_encode_String(from, serializer);
sse_encode_String(to, serializer);
- return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 18)!;
+ return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 20)!;
},
codec: SseCodec(
decodeSuccessData: sse_decode_unit,
@@ -643,7 +710,7 @@
that, serializer);
sse_encode_String(path, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
- funcId: 19, port: port_);
+ funcId: 21, port: port_);
},
codec: SseCodec(
decodeSuccessData:
@@ -671,7 +738,7 @@
sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator(
that, serializer);
sse_encode_String(path, serializer);
- return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 20)!;
+ return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 22)!;
},
codec: SseCodec(
decodeSuccessData:
@@ -690,6 +757,63 @@
argNames: ["that", "path"],
);
+ @override
+ Future<void> crateApiOpendalApiOperatorWrite(
+ {required Operator that, required String path, required List<int> data}) {
+ return handler.executeNormal(NormalTask(
+ callFfi: (port_) {
+ final serializer = SseSerializer(generalizedFrbRustBinding);
+ sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator(
+ that, serializer);
+ sse_encode_String(path, serializer);
+ sse_encode_list_prim_u_8_loose(data, serializer);
+ pdeCallFfi(generalizedFrbRustBinding, serializer,
+ funcId: 23, port: port_);
+ },
+ codec: SseCodec(
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_AnyhowException,
+ ),
+ constMeta: kCrateApiOpendalApiOperatorWriteConstMeta,
+ argValues: [that, path, data],
+ apiImpl: this,
+ ));
+ }
+
+ TaskConstMeta get kCrateApiOpendalApiOperatorWriteConstMeta =>
+ const TaskConstMeta(
+ debugName: "Operator_write",
+ argNames: ["that", "path", "data"],
+ );
+
+ @override
+ void crateApiOpendalApiOperatorWriteSync(
+ {required Operator that, required String path, required List<int> data}) {
+ return handler.executeSync(SyncTask(
+ callFfi: () {
+ final serializer = SseSerializer(generalizedFrbRustBinding);
+ sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator(
+ that, serializer);
+ sse_encode_String(path, serializer);
+ sse_encode_list_prim_u_8_loose(data, serializer);
+ return pdeCallFfi(generalizedFrbRustBinding, serializer, funcId: 24)!;
+ },
+ codec: SseCodec(
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_AnyhowException,
+ ),
+ constMeta: kCrateApiOpendalApiOperatorWriteSyncConstMeta,
+ argValues: [that, path, data],
+ apiImpl: this,
+ ));
+ }
+
+ TaskConstMeta get kCrateApiOpendalApiOperatorWriteSyncConstMeta =>
+ const TaskConstMeta(
+ debugName: "Operator_write_sync",
+ argNames: ["that", "path", "data"],
+ );
+
RustArcIncrementStrongCountFnType
get rust_arc_increment_strong_count_Metadata => wire
.rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata;
@@ -707,6 +831,12 @@
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator;
@protected
+ AnyhowException dco_decode_AnyhowException(dynamic raw) {
+ // Codec=Dco (DartCObject based), see doc to use other codecs
+ return AnyhowException(raw as String);
+ }
+
+ @protected
Metadata
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
dynamic raw) {
@@ -780,6 +910,12 @@
}
@protected
+ List<int> dco_decode_list_prim_u_8_loose(dynamic raw) {
+ // Codec=Dco (DartCObject based), see doc to use other codecs
+ return raw as List<int>;
+ }
+
+ @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return raw as Uint8List;
@@ -841,6 +977,13 @@
}
@protected
+ AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ var inner = sse_decode_String(deserializer);
+ return AnyhowException(inner);
+ }
+
+ @protected
Metadata
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
SseDeserializer deserializer) {
@@ -922,6 +1065,13 @@
}
@protected
+ List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ var len_ = sse_decode_i_32(deserializer);
+ return deserializer.buffer.getUint8List(len_);
+ }
+
+ @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var len_ = sse_decode_i_32(deserializer);
@@ -1002,6 +1152,13 @@
}
@protected
+ void sse_encode_AnyhowException(
+ AnyhowException self, SseSerializer serializer) {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ sse_encode_String(self.message, serializer);
+ }
+
+ @protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
Metadata self, SseSerializer serializer) {
@@ -1082,6 +1239,15 @@
}
@protected
+ void sse_encode_list_prim_u_8_loose(
+ List<int> self, SseSerializer serializer) {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ sse_encode_i_32(self.length, serializer);
+ serializer.buffer
+ .putUint8List(self is Uint8List ? self : Uint8List.fromList(self));
+ }
+
+ @protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -1266,6 +1432,12 @@
bool existsSync({required String path}) => RustLib.instance.api
.crateApiOpendalApiOperatorExistsSync(that: this, path: path);
+ Future<Uint8List> read({required String path}) => RustLib.instance.api
+ .crateApiOpendalApiOperatorRead(that: this, path: path);
+
+ Uint8List readSync({required String path}) => RustLib.instance.api
+ .crateApiOpendalApiOperatorReadSync(that: this, path: path);
+
Future<void> rename({required String from, required String to}) =>
RustLib.instance.api
.crateApiOpendalApiOperatorRename(that: this, from: from, to: to);
@@ -1279,4 +1451,12 @@
Metadata statSync({required String path}) => RustLib.instance.api
.crateApiOpendalApiOperatorStatSync(that: this, path: path);
+
+ Future<void> write({required String path, required List<int> data}) =>
+ RustLib.instance.api
+ .crateApiOpendalApiOperatorWrite(that: this, path: path, data: data);
+
+ void writeSync({required String path, required List<int> data}) => RustLib
+ .instance.api
+ .crateApiOpendalApiOperatorWriteSync(that: this, path: path, data: data);
}
diff --git a/bindings/dart/lib/src/rust/frb_generated.io.dart b/bindings/dart/lib/src/rust/frb_generated.io.dart
index ea65c86..18f21f3 100644
--- a/bindings/dart/lib/src/rust/frb_generated.io.dart
+++ b/bindings/dart/lib/src/rust/frb_generated.io.dart
@@ -25,6 +25,9 @@
._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperatorPtr;
@protected
+ AnyhowException dco_decode_AnyhowException(dynamic raw);
+
+ @protected
Metadata
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
dynamic raw);
@@ -67,6 +70,9 @@
BigInt dco_decode_box_autoadd_u_64(dynamic raw);
@protected
+ List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
+
+ @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
@@ -94,6 +100,9 @@
BigInt dco_decode_usize(dynamic raw);
@protected
+ AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
+
+ @protected
Metadata
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
SseDeserializer deserializer);
@@ -137,6 +146,9 @@
BigInt sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
@protected
+ List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
+
+ @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
@@ -169,6 +181,10 @@
int sse_decode_i_32(SseDeserializer deserializer);
@protected
+ void sse_encode_AnyhowException(
+ AnyhowException self, SseSerializer serializer);
+
+ @protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
Metadata self, SseSerializer serializer);
@@ -212,6 +228,9 @@
void sse_encode_box_autoadd_u_64(BigInt self, SseSerializer serializer);
@protected
+ void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
+
+ @protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
diff --git a/bindings/dart/lib/src/rust/frb_generated.web.dart b/bindings/dart/lib/src/rust/frb_generated.web.dart
index c2a3b5c..c08ea8a 100644
--- a/bindings/dart/lib/src/rust/frb_generated.web.dart
+++ b/bindings/dart/lib/src/rust/frb_generated.web.dart
@@ -27,6 +27,9 @@
.rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerOperator;
@protected
+ AnyhowException dco_decode_AnyhowException(dynamic raw);
+
+ @protected
Metadata
dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
dynamic raw);
@@ -69,6 +72,9 @@
BigInt dco_decode_box_autoadd_u_64(dynamic raw);
@protected
+ List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
+
+ @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected
@@ -96,6 +102,9 @@
BigInt dco_decode_usize(dynamic raw);
@protected
+ AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
+
+ @protected
Metadata
sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
SseDeserializer deserializer);
@@ -139,6 +148,9 @@
BigInt sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
@protected
+ List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
+
+ @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected
@@ -171,6 +183,10 @@
int sse_decode_i_32(SseDeserializer deserializer);
@protected
+ void sse_encode_AnyhowException(
+ AnyhowException self, SseSerializer serializer);
+
+ @protected
void
sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMetadata(
Metadata self, SseSerializer serializer);
@@ -214,6 +230,9 @@
void sse_encode_box_autoadd_u_64(BigInt self, SseSerializer serializer);
@protected
+ void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
+
+ @protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
diff --git a/bindings/dart/rust/Cargo.toml b/bindings/dart/rust/Cargo.toml
index 176221a..84c15d5 100644
--- a/bindings/dart/rust/Cargo.toml
+++ b/bindings/dart/rust/Cargo.toml
@@ -21,6 +21,7 @@
version = "0.1.0"
[dependencies]
+anyhow = "1.0"
flutter_rust_bridge = "=2.12.0"
opendal = { path = "../../../core", features = [
"blocking",
diff --git a/bindings/dart/rust/src/api/opendal_api.rs b/bindings/dart/rust/src/api/opendal_api.rs
index 70add34..1f3b155 100644
--- a/bindings/dart/rust/src/api/opendal_api.rs
+++ b/bindings/dart/rust/src/api/opendal_api.rs
@@ -90,6 +90,28 @@
pub fn rename_sync(&self, from: String, to: String) -> () {
self.blocking_op.rename(&from, &to).unwrap()
}
+
+ pub async fn read(&self, path: String) -> anyhow::Result<Vec<u8>> {
+ let buf = self.async_op.read(&path).await.map_err(|e| anyhow::anyhow!(e))?;
+ Ok(buf.to_vec())
+ }
+
+ #[frb(sync)]
+ pub fn read_sync(&self, path: String) -> anyhow::Result<Vec<u8>> {
+ let buf = self.blocking_op.read(&path).map_err(|e| anyhow::anyhow!(e))?;
+ Ok(buf.to_vec())
+ }
+
+ pub async fn write(&self, path: String, data: Vec<u8>) -> anyhow::Result<()> {
+ self.async_op.write(&path, data).await.map_err(|e| anyhow::anyhow!(e))?;
+ Ok(())
+ }
+
+ #[frb(sync)]
+ pub fn write_sync(&self, path: String, data: Vec<u8>) -> anyhow::Result<()> {
+ self.blocking_op.write(&path, data).map_err(|e| anyhow::anyhow!(e))?;
+ Ok(())
+ }
}
#[frb(opaque)]
diff --git a/bindings/dart/rust/src/frb_generated.rs b/bindings/dart/rust/src/frb_generated.rs
index d26fd8f..e3e5639 100644
--- a/bindings/dart/rust/src/frb_generated.rs
+++ b/bindings/dart/rust/src/frb_generated.rs
@@ -39,7 +39,7 @@
default_rust_auto_opaque = RustAutoOpaqueMoi,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
-pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 775125233;
+pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 798133092;
// Section: executor
@@ -848,6 +848,114 @@
},
)
}
+fn wire__crate__api__opendal_api__Operator_read_impl(
+ port_: flutter_rust_bridge::for_generated::MessagePort,
+ ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
+ rust_vec_len_: i32,
+ data_len_: i32,
+) {
+ FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
+ flutter_rust_bridge::for_generated::TaskInfo {
+ debug_name: "Operator_read",
+ port: Some(port_),
+ mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
+ },
+ move || {
+ let message = unsafe {
+ flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
+ ptr_,
+ rust_vec_len_,
+ data_len_,
+ )
+ };
+ let mut deserializer =
+ flutter_rust_bridge::for_generated::SseDeserializer::new(message);
+ let api_that = <RustOpaqueMoi<
+ flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Operator>,
+ >>::sse_decode(&mut deserializer);
+ let api_path = <String>::sse_decode(&mut deserializer);
+ deserializer.end();
+ move |context| async move {
+ transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
+ (move || async move {
+ let mut api_that_guard = None;
+ let decode_indices_ =
+ flutter_rust_bridge::for_generated::lockable_compute_decode_order(
+ vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
+ &api_that, 0, false,
+ )],
+ );
+ for i in decode_indices_ {
+ match i {
+ 0 => {
+ api_that_guard =
+ Some(api_that.lockable_decode_async_ref().await)
+ }
+ _ => unreachable!(),
+ }
+ }
+ let api_that_guard = api_that_guard.unwrap();
+ let output_ok =
+ crate::api::opendal_api::Operator::read(&*api_that_guard, api_path)
+ .await?;
+ Ok(output_ok)
+ })()
+ .await,
+ )
+ }
+ },
+ )
+}
+fn wire__crate__api__opendal_api__Operator_read_sync_impl(
+ ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
+ rust_vec_len_: i32,
+ data_len_: i32,
+) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
+ FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(
+ flutter_rust_bridge::for_generated::TaskInfo {
+ debug_name: "Operator_read_sync",
+ port: None,
+ mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
+ },
+ move || {
+ let message = unsafe {
+ flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
+ ptr_,
+ rust_vec_len_,
+ data_len_,
+ )
+ };
+ let mut deserializer =
+ flutter_rust_bridge::for_generated::SseDeserializer::new(message);
+ let api_that = <RustOpaqueMoi<
+ flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Operator>,
+ >>::sse_decode(&mut deserializer);
+ let api_path = <String>::sse_decode(&mut deserializer);
+ deserializer.end();
+ transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
+ (move || {
+ let mut api_that_guard = None;
+ let decode_indices_ =
+ flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![
+ flutter_rust_bridge::for_generated::LockableOrderInfo::new(
+ &api_that, 0, false,
+ ),
+ ]);
+ for i in decode_indices_ {
+ match i {
+ 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()),
+ _ => unreachable!(),
+ }
+ }
+ let api_that_guard = api_that_guard.unwrap();
+ let output_ok =
+ crate::api::opendal_api::Operator::read_sync(&*api_that_guard, api_path)?;
+ Ok(output_ok)
+ })(),
+ )
+ },
+ )
+}
fn wire__crate__api__opendal_api__Operator_rename_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
@@ -1075,6 +1183,122 @@
},
)
}
+fn wire__crate__api__opendal_api__Operator_write_impl(
+ port_: flutter_rust_bridge::for_generated::MessagePort,
+ ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
+ rust_vec_len_: i32,
+ data_len_: i32,
+) {
+ FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
+ flutter_rust_bridge::for_generated::TaskInfo {
+ debug_name: "Operator_write",
+ port: Some(port_),
+ mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
+ },
+ move || {
+ let message = unsafe {
+ flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
+ ptr_,
+ rust_vec_len_,
+ data_len_,
+ )
+ };
+ let mut deserializer =
+ flutter_rust_bridge::for_generated::SseDeserializer::new(message);
+ let api_that = <RustOpaqueMoi<
+ flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Operator>,
+ >>::sse_decode(&mut deserializer);
+ let api_path = <String>::sse_decode(&mut deserializer);
+ let api_data = <Vec<u8>>::sse_decode(&mut deserializer);
+ deserializer.end();
+ move |context| async move {
+ transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
+ (move || async move {
+ let mut api_that_guard = None;
+ let decode_indices_ =
+ flutter_rust_bridge::for_generated::lockable_compute_decode_order(
+ vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
+ &api_that, 0, false,
+ )],
+ );
+ for i in decode_indices_ {
+ match i {
+ 0 => {
+ api_that_guard =
+ Some(api_that.lockable_decode_async_ref().await)
+ }
+ _ => unreachable!(),
+ }
+ }
+ let api_that_guard = api_that_guard.unwrap();
+ let output_ok = crate::api::opendal_api::Operator::write(
+ &*api_that_guard,
+ api_path,
+ api_data,
+ )
+ .await?;
+ Ok(output_ok)
+ })()
+ .await,
+ )
+ }
+ },
+ )
+}
+fn wire__crate__api__opendal_api__Operator_write_sync_impl(
+ ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
+ rust_vec_len_: i32,
+ data_len_: i32,
+) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse {
+ FLUTTER_RUST_BRIDGE_HANDLER.wrap_sync::<flutter_rust_bridge::for_generated::SseCodec, _>(
+ flutter_rust_bridge::for_generated::TaskInfo {
+ debug_name: "Operator_write_sync",
+ port: None,
+ mode: flutter_rust_bridge::for_generated::FfiCallMode::Sync,
+ },
+ move || {
+ let message = unsafe {
+ flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
+ ptr_,
+ rust_vec_len_,
+ data_len_,
+ )
+ };
+ let mut deserializer =
+ flutter_rust_bridge::for_generated::SseDeserializer::new(message);
+ let api_that = <RustOpaqueMoi<
+ flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Operator>,
+ >>::sse_decode(&mut deserializer);
+ let api_path = <String>::sse_decode(&mut deserializer);
+ let api_data = <Vec<u8>>::sse_decode(&mut deserializer);
+ deserializer.end();
+ transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
+ (move || {
+ let mut api_that_guard = None;
+ let decode_indices_ =
+ flutter_rust_bridge::for_generated::lockable_compute_decode_order(vec![
+ flutter_rust_bridge::for_generated::LockableOrderInfo::new(
+ &api_that, 0, false,
+ ),
+ ]);
+ for i in decode_indices_ {
+ match i {
+ 0 => api_that_guard = Some(api_that.lockable_decode_sync_ref()),
+ _ => unreachable!(),
+ }
+ }
+ let api_that_guard = api_that_guard.unwrap();
+ let output_ok = crate::api::opendal_api::Operator::write_sync(
+ &*api_that_guard,
+ api_path,
+ api_data,
+ )?;
+ Ok(output_ok)
+ })(),
+ )
+ },
+ )
+}
// Section: related_funcs
@@ -1087,6 +1311,14 @@
// Section: dart2rust
+impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
+ let mut inner = <String>::sse_decode(deserializer);
+ return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);
+ }
+}
+
impl SseDecode for Metadata {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -1260,10 +1492,12 @@
14 => {
wire__crate__api__opendal_api__Operator_exists_impl(port, ptr, rust_vec_len, data_len)
}
- 17 => {
+ 17 => wire__crate__api__opendal_api__Operator_read_impl(port, ptr, rust_vec_len, data_len),
+ 19 => {
wire__crate__api__opendal_api__Operator_rename_impl(port, ptr, rust_vec_len, data_len)
}
- 19 => wire__crate__api__opendal_api__Operator_stat_impl(port, ptr, rust_vec_len, data_len),
+ 21 => wire__crate__api__opendal_api__Operator_stat_impl(port, ptr, rust_vec_len, data_len),
+ 23 => wire__crate__api__opendal_api__Operator_write_impl(port, ptr, rust_vec_len, data_len),
_ => unreachable!(),
}
}
@@ -1300,8 +1534,10 @@
13 => wire__crate__api__opendal_api__Operator_delete_sync_impl(ptr, rust_vec_len, data_len),
15 => wire__crate__api__opendal_api__Operator_exists_sync_impl(ptr, rust_vec_len, data_len),
16 => wire__crate__api__opendal_api__Operator_new_impl(ptr, rust_vec_len, data_len),
- 18 => wire__crate__api__opendal_api__Operator_rename_sync_impl(ptr, rust_vec_len, data_len),
- 20 => wire__crate__api__opendal_api__Operator_stat_sync_impl(ptr, rust_vec_len, data_len),
+ 18 => wire__crate__api__opendal_api__Operator_read_sync_impl(ptr, rust_vec_len, data_len),
+ 20 => wire__crate__api__opendal_api__Operator_rename_sync_impl(ptr, rust_vec_len, data_len),
+ 22 => wire__crate__api__opendal_api__Operator_stat_sync_impl(ptr, rust_vec_len, data_len),
+ 24 => wire__crate__api__opendal_api__Operator_write_sync_impl(ptr, rust_vec_len, data_len),
_ => unreachable!(),
}
}
@@ -1338,6 +1574,13 @@
}
}
+impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
+ // Codec=Sse (Serialization based), see doc to use other codecs
+ fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+ <String>::sse_encode(format!("{:?}", self), serializer);
+ }
+}
+
impl SseEncode for Metadata {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
diff --git a/bindings/dart/tests/opendal_test.dart b/bindings/dart/tests/opendal_test.dart
index 693b08a..516167d 100644
--- a/bindings/dart/tests/opendal_test.dart
+++ b/bindings/dart/tests/opendal_test.dart
@@ -1,4 +1,5 @@
import 'package:test/test.dart';
+import 'dart:typed_data';
import '../lib/opendal.dart';
void main() {
@@ -36,6 +37,39 @@
expect(meta.isFile, false);
expect(meta.isDirectory, true);
});
+
+ test('File read/write round-trip', () async {
+ final storage = await Storage.init(schemeStr: "memory", map: {"root": "/tmp"});
+ final File = storage.initFile();
+ var testFile = File("roundtrip.txt");
+ final data = Uint8List.fromList([1, 2, 3, 4, 5]);
+
+ await testFile.write(data);
+ expect(await testFile.exists(), true);
+
+ final readData = await testFile.read();
+ expect(readData, equals(data));
+ });
+
+ test('File read from missing path throws', () async {
+ final storage = await Storage.init(schemeStr: "memory", map: {"root": "/tmp"});
+ final File = storage.initFile();
+ var missingFile = File("nonexistent.txt");
+
+ expect(() async => await missingFile.read(), throwsA(anything));
+ });
+
+ test('File overwrite semantics', () async {
+ final storage = await Storage.init(schemeStr: "memory", map: {"root": "/tmp"});
+ final File = storage.initFile();
+ var testFile = File("overwrite.txt");
+
+ await testFile.write(Uint8List.fromList([1, 2, 3]));
+ await testFile.write(Uint8List.fromList([4, 5]));
+
+ final readData = await testFile.read();
+ expect(readData, equals(Uint8List.fromList([4, 5])));
+ });
});
});
}