Skip to content

Commit de401c3

Browse files
update doc
1 parent 53143d4 commit de401c3

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

bindings/c/README.md

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,31 +128,64 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
128128

129129
## Async APIs
130130

131-
The C binding also exposes a small asynchronous API surface, mirroring Rust's `async` operator. Each async call returns a future handle that you can await or cancel.
131+
OpenDAL’s C binding mirrors the Rust async operator, but keeps all runtime management on the Rust side so C callers never need to embed Tokio. The design is intentionally future/await centric:
132132

133-
- Create an async operator with `opendal_async_operator_new` (cast the returned `op` field to `opendal_async_operator`).
134-
- Start operations with `opendal_async_operator_stat`, `opendal_async_operator_write`, `opendal_async_operator_read`, and `opendal_async_operator_delete`.
135-
- Await results using the matching `opendal_future_*_await` helpers, or abort early with `opendal_future_*_free`.
136-
- For non-blocking event-loop style, poll with `opendal_future_*_poll` which returns `opendal_future_status` (`PENDING`, `READY`, `ERROR`, `CANCELED`) without blocking the thread; call `*_await` once `READY` to consume the result, or keep polling.
133+
- `opendal_async_operator_new` builds an async operator that internally holds a clone of the core `Operator` plus a handle to OpenDAL’s shared Tokio runtime.
134+
- Each async method (`*_stat`, `*_write`, `*_read`, `*_delete`) immediately returns an opaque `opendal_future_*` handle. Creating the future is non-blocking—the runtime schedules the real work on its thread pool.
135+
- You stay in control of when to pull the result. Call `opendal_future_*_await` to block the current thread until the operation finishes, or `opendal_future_*_poll` to integrate with your own event loop without blocking.
136+
- If you abandon an operation, call `opendal_future_*_free` to cancel it. This aborts the underlying task and drops any pending output safely.
137+
138+
Because futures carry ownership of the eventual metadata/error objects, the `*_await` helpers always transfer heap allocations using the same conventions as the blocking API (free metadata with `opendal_metadata_free`, free errors with `opendal_error_free`, etc.).
139+
140+
### Usage example
141+
142+
Below is a full async stat sequence that starts the request, performs other work, then awaits the result. The same pattern applies to read/write/delete by swapping the function names.
137143

138144
```c
139-
opendal_result_operator_new res = opendal_async_operator_new("memory", NULL);
140-
const opendal_async_operator* op = (const opendal_async_operator*)res.op;
145+
#include "opendal.h"
146+
#include <stdio.h>
147+
#include <unistd.h>
148+
149+
static void sleep_ms(unsigned int ms) { usleep(ms * 1000); }
141150

142-
opendal_bytes data = { .data = (uint8_t*)"hello", .len = 5, .capacity = 5 };
143-
opendal_error* write_err = opendal_future_write_await(
144-
opendal_async_operator_write(op, "hello.txt", &data).future);
151+
int main(void) {
152+
opendal_result_operator_new res = opendal_async_operator_new("memory", NULL);
153+
if (res.error) {
154+
fprintf(stderr, "create async op failed: %d\n", res.error->code);
155+
opendal_error_free(res.error);
156+
return 1;
157+
}
158+
const opendal_async_operator* op = (const opendal_async_operator*)res.op;
159+
160+
opendal_result_future_stat fut = opendal_async_operator_stat(op, "missing.txt");
161+
if (fut.error) {
162+
fprintf(stderr, "stat future failed: %d\n", fut.error->code);
163+
opendal_error_free(fut.error);
164+
opendal_async_operator_free(op);
165+
return 1;
166+
}
145167

146-
opendal_result_read read_out = opendal_future_read_await(
147-
opendal_async_operator_read(op, "hello.txt").future);
148-
printf("read %zu bytes: %.*s\n", read_out.data.len, (int)read_out.data.len, read_out.data.data);
149-
opendal_bytes_free(&read_out.data);
168+
printf("stat scheduled, doing other work...\n");
169+
sleep_ms(500); // keep UI/event loop responsive while I/O runs
170+
171+
opendal_result_stat out = opendal_future_stat_await(fut.future);
172+
if (out.error) {
173+
printf("stat failed as expected: %d\n", out.error->code);
174+
opendal_error_free(out.error);
175+
} else {
176+
printf("stat succeeded, size=%llu\n",
177+
(unsigned long long)opendal_metadata_content_length(out.meta));
178+
opendal_metadata_free(out.meta);
179+
}
150180

151-
opendal_future_delete_await(opendal_async_operator_delete(op, "hello.txt").future);
152-
opendal_async_operator_free(op);
181+
opendal_async_operator_free(op);
182+
return 0;
183+
}
153184
```
154185
155-
See `tests/async_stat_test.cpp` for more complete usage with GoogleTest.
186+
Need non-blocking integration with your own loop? Call `opendal_future_stat_poll(fut.future, &out)` inside your loop. It returns `OPENDAL_FUTURE_PENDING` until the result is ready; once it reports `OPENDAL_FUTURE_READY`, call `opendal_future_stat_await` exactly once to consume the output.
187+
188+
See `examples/async_stat.c` for a narrated walkthrough and `tests/async_stat_test.cpp` for GoogleTest-based assertions that cover both success and error paths.
156189
157190
## Documentation
158191

0 commit comments

Comments
 (0)