Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
# x.async examples
This folder contains short public examples for the current `x.async` API.
Each file focuses on one idea and uses only local, in-memory work.
Examples are documentation-first programs. They show how the public API is
expected to be used in small readable scenarios. They are executed by the
validation script to avoid bit rot, but the regression guarantees live in the
`tests/` folder.
## Rules
- No external service is required.
- No fixed local path is used.
- No network listener is opened.
- Examples avoid `panic()` as a control-flow pattern.
- Cancellation remains cooperative; examples show jobs checking `ctx.done()`
when they may run for more than a tiny unit of work.
## Examples
- `basic_group.v`: first error propagation and cooperative sibling
cancellation.
- `basic_task.v`: one value-returning task consumed with `wait()`.
- `worker_pool.v`: fixed concurrency and explicit `try_submit()` backpressure.
- `bounded_pool_submit.v`: wait for pool admission with a timeout or context
while jobs keep using the pool context.
- `periodic.v`: a blocking `every()` loop stopped by context cancellation.
- `timeout.v`: one cooperative job bounded by `with_timeout()`.
- `net_http/`: synthetic `net.http` request/response processing with `Pool`.
- `net_websocket/`: in-memory `websocket.Message` processing. It is not an
end-to-end websocket server example.
- `mcp/`: in-memory MCP request/response dispatch with `Task[T]`.
- `veb/`: synthetic `veb.Context` response lifecycle with `Task[T]`.
## Run
From the repository root:
```sh
./v run vlib/x/async/examples/basic_group.v
./v run vlib/x/async/examples/basic_task.v
./v run vlib/x/async/examples/worker_pool.v
./v run vlib/x/async/examples/bounded_pool_submit.v
./v run vlib/x/async/examples/periodic.v
./v run vlib/x/async/examples/timeout.v
./v run vlib/x/async/examples/net_http/request_batch.v
./v run vlib/x/async/examples/net_websocket/message_pipeline.v
./v run vlib/x/async/examples/mcp/tool_dispatch.v
./v run vlib/x/async/examples/veb/app_lifecycle.v
```
Use `tools/validate.sh` for the guarded module validation path. It isolates V
temporary/cache directories and keeps validation runners serialized.
@@ -0,0 +1,30 @@
import context
import time
import x.async as xasync
fn main() {
mut group := xasync.new_group(context.background())
group.go(fn (mut ctx context.Context) ! {
_ = ctx
time.sleep(20 * time.millisecond)
return error('stop group')
})!
group.go(fn (mut ctx context.Context) ! {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
1 * time.second {
return error('worker did not observe cancellation')
}
}
})!
group.wait() or {
println('group failed: ${err.msg()}')
return
}
}
@@ -0,0 +1,12 @@
import context
import x.async as xasync
fn main() {
mut task := xasync.run[int](fn (mut ctx context.Context) !int {
_ = ctx
return 42
})!
value := task.wait()!
println('task result: ${value}')
}
@@ -0,0 +1,77 @@
import context
import time
import x.async as xasync
fn main() {
mut pool := xasync.new_pool(workers: 1, queue_size: 1)!
started := chan bool{cap: 2}
release := chan bool{cap: 2}
accepted := chan bool{cap: 1}
ran := chan bool{cap: 1}
context_ran := chan bool{cap: 1}
blocking_job := fn [started, release] (mut ctx context.Context) ! {
_ = ctx
started <- true
_ := <-release
}
pool.try_submit(blocking_job)!
if !wait_bool(started) {
eprintln('first pool job did not start')
exit(1)
}
pool.try_submit(blocking_job)!
submitter := spawn fn [mut pool, accepted, ran] () {
pool.submit_with_timeout(1 * time.second, fn [ran] (mut ctx context.Context) ! {
_ = ctx
ran <- true
}) or {
eprintln('bounded submit failed: ${err.msg()}')
accepted <- false
return
}
accepted <- true
}()
release <- true
if !wait_bool(accepted) {
eprintln('bounded submit was not accepted after capacity opened')
exit(1)
}
release <- true
if !wait_bool(ran) {
eprintln('bounded submit job did not run')
exit(1)
}
parent_ctx, cancel := xasync.with_cancel()
defer {
cancel()
}
pool.submit_with_context(parent_ctx, fn [context_ran] (mut ctx context.Context) ! {
_ = ctx
context_ran <- true
})!
if !wait_bool(context_ran) {
eprintln('context-bounded submit job did not run')
exit(1)
}
pool.close()!
submitter.wait()
println('timeout and context bounded submits completed')
}
fn wait_bool(ch chan bool) bool {
select {
ok := <-ch {
return ok
}
1 * time.second {
return false
}
}
return false
}
@@ -0,0 +1,18 @@
# mcp integration example
This example uses MCP JSON-RPC values in memory and runs the dispatch step in an
`x.async.Task`. It does not start stdio, HTTP, a process transport, or any
external service.
The goal is to show the integration boundary:
- build an MCP request value;
- decode and validate it inside a task;
- return an MCP response value;
- consume the result with `Task.wait()`.
Run from the repository root:
```sh
./v run vlib/x/async/examples/mcp/tool_dispatch.v
```
@@ -0,0 +1,37 @@
import context
import mcp
import x.async as xasync
struct EchoArgs {
pub:
text string
}
fn dispatch_tool(raw string) !mcp.Response {
req := mcp.decode_request(raw)!
if req.method != 'tools/call' {
return error('unsupported MCP method')
}
args := req.decode_params[EchoArgs]()!
result := mcp.tool_text_result('echo: ${args.text}')
return mcp.new_response(1, result, mcp.ResponseError{})
}
fn main() {
request := mcp.new_request(1, 'tools/call', EchoArgs{
text: 'hello'
})
mut task := xasync.run[mcp.Response](fn [request] (mut ctx context.Context) !mcp.Response {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
else {}
}
return dispatch_tool(request.encode())!
})!
response := task.wait()!
println(response.encode())
}
@@ -0,0 +1,21 @@
# net.http integration example
This example shows how `x.async` can coordinate local `net.http` request and
response handling without opening a network listener.
It is intentionally synthetic: requests are constructed in memory, processed by
a small handler, and drained through a `Pool`. This keeps the example stable
while still showing the lifecycle pattern used by HTTP-facing code:
- construct or receive a `http.Request`;
- submit bounded work to an `x.async.Pool`;
- publish a `http.Response` result;
- close the pool and report the first error if one occurred.
Run from the repository root:
```sh
./v run vlib/x/async/examples/net_http/request_batch.v
```
No external service, fixed port, file path, or real HTTP server is used.
@@ -0,0 +1,47 @@
import context
import net.http
import x.async as xasync
fn synthetic_http_handler(req http.Request) !http.Response {
path := if req.url.contains('?') { req.url.all_before('?') } else { req.url }
match path {
'/health' {
return http.new_response(status: .ok, body: 'healthy')
}
'/ready' {
return http.new_response(status: .ok, body: 'ready')
}
else {
return http.new_response(status: .not_found, body: 'missing')
}
}
}
fn main() {
requests := [
http.new_request(.get, '/health', ''),
http.new_request(.get, '/ready', ''),
http.new_request(.get, '/missing', ''),
]
responses := chan string{cap: requests.len}
mut pool := xasync.new_pool(workers: 2, queue_size: requests.len)!
for req in requests {
pool.try_submit(fn [req, responses] (mut ctx context.Context) ! {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
else {}
}
resp := synthetic_http_handler(req)!
responses <- '${req.url} -> ${resp.status_code} ${resp.body}'
})!
}
pool.close()!
for _ in 0 .. requests.len {
println(<-responses)
}
}
@@ -0,0 +1,19 @@
# net.websocket integration example
This example stays in memory around `websocket.Message` processing. It does not
open a websocket server, does not connect a client, and must not be read as an
end-to-end websocket server validation.
That boundary is deliberate. In this V snapshot, `websocket.Server.close()` is
not a complete, stable server shutdown mechanism suitable for fragile
validation. The public example therefore demonstrates the safe part that
`x.async` can own here: coordinating message/callback-style work and propagating
errors without inventing a websocket runtime.
Run from the repository root:
```sh
./v run vlib/x/async/examples/net_websocket/message_pipeline.v
```
No external service, fixed port, or websocket server lifecycle is used.
@@ -0,0 +1,49 @@
import context
import net.websocket
import x.async as xasync
fn describe_message(msg websocket.Message) !string {
return match msg.opcode {
.text_frame {
'text:${msg.payload.bytestr()}'
}
.ping {
'ping'
}
else {
error('unsupported websocket message opcode')
}
}
}
fn main() {
messages := [
websocket.Message{
opcode: .text_frame
payload: 'hello'.bytes()
},
websocket.Message{
opcode: .ping
},
]
processed := chan string{cap: messages.len}
mut group := xasync.new_group(context.background())
for msg in messages {
group.go(fn [msg, processed] (mut ctx context.Context) ! {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
else {}
}
processed <- describe_message(msg)!
})!
}
group.wait()!
for _ in 0 .. messages.len {
println(<-processed)
}
}
+49
View File
@@ -0,0 +1,49 @@
import context
import time
import x.async as xasync
fn main() {
ctx, cancel := xasync.with_cancel()
ticks := chan int{cap: 4}
done := chan string{cap: 1}
worker := spawn fn [ctx, ticks, done] () {
xasync.every(ctx, 10 * time.millisecond, fn [ticks] (mut ctx context.Context) ! {
_ = ctx
ticks <- 1
}) or {
done <- err.msg()
return
}
done <- 'completed'
}()
if !wait_tick(ticks) || !wait_tick(ticks) {
eprintln('periodic job did not tick')
exit(1)
}
cancel()
select {
msg := <-done {
println('periodic stopped: ${msg}')
}
1 * time.second {
eprintln('periodic job did not stop')
exit(1)
}
}
worker.wait()
}
fn wait_tick(ticks chan int) bool {
select {
_ := <-ticks {
return true
}
1 * time.second {
return false
}
}
return false
}
+23
View File
@@ -0,0 +1,23 @@
import context
import time
import x.async as xasync
fn main() {
xasync.with_timeout(20 * time.millisecond, fn (mut ctx context.Context) ! {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
1 * time.second {
return error('work unexpectedly finished')
}
}
}) or {
println('timeout result: ${err.msg()}')
return
}
eprintln('expected timeout error')
exit(1)
}
@@ -0,0 +1,14 @@
# veb integration example
This example is a compile-time, in-memory `veb.Context` lifecycle sample. It
does not start a `veb` server and does not bind a port.
The example is intentionally small because robust server lifecycle validation
belongs to `veb` itself. Here, `x.async` only coordinates a synthetic handler
step and returns the response body through `Task.wait()`.
Run from the repository root:
```sh
./v run vlib/x/async/examples/veb/app_lifecycle.v
```
@@ -0,0 +1,27 @@
import context
import veb
import x.async as xasync
fn render_health_response() !string {
mut web_ctx := veb.Context{}
_ := web_ctx.text('veb ok')
if web_ctx.res.status_code != 200 {
return error('unexpected veb status')
}
return web_ctx.res.body
}
fn main() {
mut task := xasync.run[string](fn (mut ctx context.Context) !string {
done := ctx.done()
select {
_ := <-done {
return ctx.err()
}
else {}
}
return render_health_response()!
})!
println(task.wait()!)
}
@@ -0,0 +1,45 @@
import context
import time
import x.async as xasync
fn main() {
mut pool := xasync.new_pool(workers: 1, queue_size: 1)!
started := chan int{cap: 2}
release := chan bool{cap: 2}
job := fn [started, release] (mut ctx context.Context) ! {
_ = ctx
started <- 1
_ := <-release
}
pool.try_submit(job)!
if !wait_started(started) {
eprintln('pool job did not start')
exit(1)
}
pool.try_submit(job)!
pool.try_submit(job) or { println('backpressure: ${err.msg()}') }
release <- true
if !wait_started(started) {
eprintln('pool job did not start')
exit(1)
}
release <- true
pool.close()!
println('pool drained')
}
fn wait_started(started chan int) bool {
select {
_ := <-started {
return true
}
1 * time.second {
return false
}
}
return false
}