FUTATIC — is a C3 library with FUTures, that are stATICally typed!
Heavily WIP, currently not intended for production use
futatic.c3l provides a compile-time futures abstraction for C3, enabling asynchronous programming patterns while maintaining static type safety and minimizing runtime overhead.
- Type-safe future/promise implementation
- Compile-time error checking
- Lightweight abstraction with minimal overhead
-
Clone this repository inside your
libfolder:git clone https://github.com/velikoss/futatic.c3l.git -
Include the library in your C3 project by adding the project to your
manifest.json:"dependencies": [ "futatic" ]
WIP, but there are some ways now:
-
Using FutureDyn (Dynamic Future)
fn Result {Type} some_polling_fn (void* arg) { ... } FutureDyn {Type} future = { .poll_fn = &some_polling_fn; .inner = arg; // Pointer to arguments passed into poll function } future.poll();
Also there is
FutureDyn {Type} future = future::wrap_dyn {Type} (&some_struct_var);
Its used for structures with .poll(&self) method. Then when polling, the argument in function would be self
-
Using structs
Example structure for then passing into polling system (always returns FINISHED with value)
struct Ready { Return value; } fn Result {Return} Ready.poll(&self) { return { .state = FINISHED, .value = self.value }; }
-
Future { Struct }
This structure is a wrapper for user-defined struct to add more functionality.
- .then(fn SomeFuture(x){...}) → Future{Then{*}}
Chains an asynchronous operation to execute after this future completes.
x - lambda that returns struct with .poll method
- .then(fn SomeFuture(x){...}) → Future{Then{*}}
-
Then { FirstFuture, SecondFuture }
The
Thenstruct is a future combinator that sequentially chains two asynchronous operations. It is created when you call.then()on aFutureand represents the asynchronous execution of:- The first future (
FirstFuture), followed by - The second future (
SecondFuture), which is produced by applying a callback to the result of the first.
- The first future (
-
Result { Return }
This structure must be used for all futures poll returns.
struct Result { State state; Return value; }
-
macro select(...) (from futatic::select)
This macro returns PairSelect {...} future. Because returning type is complex generic one, the only ways to store right now (as of 0.7.4 C3 version) is to:
- Wrap function call into
wrap_dyn $typeof(select::select {bool} (f1, f2, f3)) foo = select::select {bool} (f1, f2, f3);
Which puts returning type as type on compile-time
These ways are temporary and could be managed better with c3lang/c3c#2336 (proposition in c3's discord)
- Wrap function call into
WIP
import futatic;
alias ReadyBool = Ready {bool};
fn int main()
{
Ready {bool} f1 = {.value = true};
Ready {bool} f2 = {.value = true};
Ready {bool} f3 = {.value = true};
$typeof(select::select {bool} (f1, f2, f3)) boo = select::select {bool} (f1, f2, f3); // WIP
Result {bool} result = boo.poll();
var future = ((Future {ReadyBool}) {.value = false}).then(fn ReadyBool(bool value) { // WIP, var because complex generic
return (ReadyBool) {.value = !value};
});
io::printn($typeof(future).qnameof); // futatic_future$futatic_future_then$futatic$bool$.Ready$futatic$bool$.Ready$.Then$::Future
io::printn(future.poll()); // { state: PENDING, value: false }
io::printn(future.poll()); // { state: FINISHED, value: true }
return 0;
}Contributions are welcome! Please open an issue or pull request for any bugs or feature requests.
This project is licensed under the MIT License - see the LICENSE file for details.