eh_callback_tcp_echo.dhover×340 error×2all
#!/usr/bin/env dub
/+ dub.sdl:
    name "eh_callback_tcp_echo"
    dependency "sparkles:event-horizon" path="../../../../.."
    platforms "linux"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
@system:
import 
(package) core
core
.
(module) core.lifetime
lifetime
:
(alias template) eh_callback_tcp_echo.move = core.lifetime.move(T)(ref T source, ref T target)

Moves source into target, via a destructive copy when necessary.

If T is a struct with a destructor or postblit defined, source is reset to its .init value after it is moved into target, otherwise it is left unchanged.

Preconditions

If source has internal pointers that point to itself and doesn't define opPostMove, it cannot be moved, and will trigger an assertion failure.

@paramsource Data to copy.@paramtarget Where to copy into. The destructor, if any, is invoked before the copy is performed.
move
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(package) core.sys.posix.sys
sys
.
(module) core.sys.posix.sys.socket

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly, Alex Rønne Petersen@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
socket
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(package) core.sys.posix.netinet
netinet
.
(module) core.sys.posix.netinet.in_

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
in_
:
(struct) core.sys.posix.netinet.in_.sockaddr_in
sockaddr_in
,
(alias enum value) eh_callback_tcp_echo.INADDR_LOOPBACK = core.sys.posix.netinet.in_.INADDR_LOOPBACK = 2130706433u
INADDR_LOOPBACK
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(package) core.sys.posix.arpa
arpa
.
(module) core.sys.posix.arpa.inet

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
inet
:
(alias) eh_callback_tcp_echo.htonl = uint core.sys.posix.arpa.inet.htonl(uint) pure nothrow @nogc @trusted
htonl
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.unistd

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 8, IEEE Std 1003.1, 2024 Edition
unistd
:
(alias) eh_callback_tcp_echo.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) eh_callback_tcp_echo.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
import
(package) sparkles
sparkles
.
(package) sparkles.event_horizon
event_horizon
.
(module) sparkles.event_horizon.loop

Tier A — the callback completion core (SPEC §5): submit(op, callback, ctx) over one DbI backend. The loop owns the op-slot slab (buffer pinning, kernel-stable operands, the cancellation state machine) and delivers completions only inside runOnce — the DEFER_TASKRUN contract made structural.

The loop is thread-affine and non-copyable: every member must be called from the owning thread — except Waker.wake() (SPEC §5.6), the one off-thread door, obtained via waker().

loop
:
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)
DefaultLoop
;
import
(package) sparkles
sparkles
.
(package) sparkles.event_horizon
event_horizon
.
(module) sparkles.event_horizon.op

Portable operation vocabulary: typed op descriptors, the user_data token discipline, the op-slot slab with its lifetime state machine, and the completion shape (SPEC §4). This module is portable — it imports no backend and never sees an SQE; backend-specific lowering lives in sparkles.event_horizon.backend.*.

op
;
import
(package) sparkles
sparkles
.
(package) sparkles.event_horizon
event_horizon
.
(module) sparkles.event_horizon.buffer

Owned-buffer currency for the completion window (SPEC §6).

Buf is a move-only handle over pinned, stable memory — a pool slab slot, a registered-buffer slot, a provided-ring lease, or vouched-for foreign memory. The kernel holds the pointer from submission to the terminal completion, so the bytes must not move or be freed in that window; that is why SharedBuffer (whose small-buffer optimization relocates the payload on struct moves) is banned as the tier-A transfer currency.

Memory management follows the composable-allocator guidelines: the pool is generic over an Allocator (the §4 recipe — stateSize embed, Mallocator default, attributes inferred) and draws its backing slab through makeArray/dispose. The slot-index structure stays bespoke: slot indices are the buf_index/bid currency for READ_FIXED and provided rings, which a plain FreeList cannot provide. Page-aligned parents (MmapAllocator/AscendingPageAllocator) suit pools destined for buffer registration.

buffer
:
(alias struct) eh_callback_tcp_echo.BufferPool = sparkles.event_horizon.buffer.BufferPool(Allocator = Mallocator)

Fixed pool of same-size buffers carved out of one contiguous slab drawn from Allocator (SPEC §6.3) — the guideline-§4 generic-library shape: monostate allocators cost zero bytes (stateSize idiom), stateful ones are passed to create and embedded. When the backend supports registered buffers the slab is registered once and every Buf carries its slot index; lowering then picks the FIXED opcodes purely from Buf.origin — the user never spells "fixed". (Registration wiring lands in M8; until then every pool Buf has BufOrigin.pool.)

BufferPool
;
enum
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
= "hello";
struct
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
{
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)
DefaultLoop
*
(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_tcp_echo.Endpoint.loop
loop
;
(struct) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator)

Fixed pool of same-size buffers carved out of one contiguous slab drawn from Allocator (SPEC §6.3) — the guideline-§4 generic-library shape: monostate allocators cost zero bytes (stateSize idiom), stateful ones are passed to create and embedded. When the backend supports registered buffers the slab is registered once and every Buf carries its slot index; lowering then picks the FIXED opcodes purely from Buf.origin — the user never spells "fixed". (Registration wiring lands in M8; until then every pool Buf has BufOrigin.pool.)

BufferPool
!()*
(field) @system sparkles.event_horizon.buffer.BufferPool!(Mallocator)* eh_callback_tcp_echo.Endpoint.pool
pool
;
int
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
= -1;
bool
(field) @system bool eh_callback_tcp_echo.Endpoint.server
server
;
(alias) object.size_t = ulong
size_t
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
,
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
,
(field) @system ulong eh_callback_tcp_echo.Endpoint.pendingSend
pendingSend
;
char[5]
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
;
} void
void eh_callback_tcp_echo.receive(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
receive
(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
) nothrow @nogc
{ auto
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
=
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system sparkles.event_horizon.buffer.BufferPool!(Mallocator)* eh_callback_tcp_echo.Endpoint.pool
pool
.
expected.Expected!(Buf, IoError, NoGcHook) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).acquire() nothrow @nogc @trusted

Hands out one buffer; ENOBUFS when the pool is exhausted.

acquire
();
assert(
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
bool expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
assert(
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_tcp_echo.Endpoint.loop
loop
.
expected.Expected!(OpHandle, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).submit!(sparkles.event_horizon.op.OpRecv)(sparkles.event_horizon.op.OpRecv op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @safe

Submits op with a completion callback (SPEC §5.2). Owned buffers move into the op slot and come back via Completion.buf; on a submission error the buffer is recycled to its origin (it does not come back — there will be no completion).

The ctx lifetime rule: ctx must stay valid until the op's terminal completion is dispatched — cancel alone does not shorten that (the terminal CQE still arrives and still invokes cb). A caller whose ctx dies earlier must detach the handle first: after detach returns, the callback never runs. Handing a stack frame's address to ctx without one of those guarantees is exactly the use-after-free the retired kernel-timer deadline shipped (SPEC §8.3).

Backpressure

on a full submission queue the loop performs one implicit flush retry, then returns EAGAIN; an exhausted slab returns ENOBUFS.

submit
(
(struct) sparkles.event_horizon.op.OpRecv

Socket receive into the buffer's full capacity.

OpRecv
(
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
,
sparkles.event_horizon.buffer.Buf core.lifetime.move!(sparkles.event_horizon.buffer.Buf)(ref return scope sparkles.event_horizon.buffer.Buf source) nothrow @nogc @safe

Examples

Non-copyable structs can still be moved:

struct S
{
    int a = 1;
    @disable this(this);
    ~this() pure nothrow @safe @nogc {}
}
S s1;
s1.a = 2;
S s2 = move(s1);
assert(s1.a == 1);
assert(s2.a == 2);
move
(
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
inout(sparkles.event_horizon.buffer.Buf) expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
)),
`@nogc` function `eh_callback_tcp_echo.receive` cannot call non-@nogc function `sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator).submit!(OpRecv)` which calls `trySubmitWithRetry` which calls `scope @disable this(this);`
&
void eh_callback_tcp_echo.received(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
received
,
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
).
bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
} void
void eh_callback_tcp_echo.send(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
send
(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
) nothrow @nogc
{ auto
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
=
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system sparkles.event_horizon.buffer.BufferPool!(Mallocator)* eh_callback_tcp_echo.Endpoint.pool
pool
.
expected.Expected!(Buf, IoError, NoGcHook) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).acquire() nothrow @nogc @trusted

Hands out one buffer; ENOBUFS when the pool is exhausted.

acquire
();
assert(
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
bool expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
// Two-byte buffers force the five-byte frame through several operations. auto
(local variable) ulong remaining
remaining
=
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
.
(constant) ulong "hello".length = 5LU
length
-
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
;
auto
(local variable) ulong count
count
=
(local variable) ulong remaining
remaining
< 2 ?
(local variable) ulong remaining
remaining
: 2;
const(char)[]
(local variable) const(char)[] outgoing
outgoing
=
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system bool eh_callback_tcp_echo.Endpoint.server
server
?
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
[] :
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
;
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
inout(sparkles.event_horizon.buffer.Buf) expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
.
inout(ubyte)[] sparkles.event_horizon.buffer.Buf.space() inout pure nothrow @nogc return scope @trusted

Full-capacity view for receive paths: the kernel fills it, and the caller sets length from the completion's byte count.

space
()[0 ..
(local variable) ulong count
count
] = cast(const(ubyte)[])
(local variable) const(char)[] outgoing
outgoing
[
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
..
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
+
(local variable) ulong count
count
];
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
inout(sparkles.event_horizon.buffer.Buf) expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
.
void sparkles.event_horizon.buffer.Buf.length(uint n) pure nothrow @nogc @safe

Sets the valid-byte count (e.g. before a send); capped by capacity.

length
= cast(uint)
(local variable) ulong count
count
;
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.pendingSend
pendingSend
=
(local variable) ulong count
count
;
assert(
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_tcp_echo.Endpoint.loop
loop
.
expected.Expected!(OpHandle, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).submit!(sparkles.event_horizon.op.OpSend)(sparkles.event_horizon.op.OpSend op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @safe

Submits op with a completion callback (SPEC §5.2). Owned buffers move into the op slot and come back via Completion.buf; on a submission error the buffer is recycled to its origin (it does not come back — there will be no completion).

The ctx lifetime rule: ctx must stay valid until the op's terminal completion is dispatched — cancel alone does not shorten that (the terminal CQE still arrives and still invokes cb). A caller whose ctx dies earlier must detach the handle first: after detach returns, the callback never runs. Handing a stack frame's address to ctx without one of those guarantees is exactly the use-after-free the retired kernel-timer deadline shipped (SPEC §8.3).

Backpressure

on a full submission queue the loop performs one implicit flush retry, then returns EAGAIN; an exhausted slab returns ENOBUFS.

submit
(
(struct) sparkles.event_horizon.op.OpSend

Socket send of the buffer's valid bytes.

OpSend
(
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
,
sparkles.event_horizon.buffer.Buf core.lifetime.move!(sparkles.event_horizon.buffer.Buf)(ref return scope sparkles.event_horizon.buffer.Buf source) nothrow @nogc @safe

Examples

Non-copyable structs can still be moved:

struct S
{
    int a = 1;
    @disable this(this);
    ~this() pure nothrow @safe @nogc {}
}
S s1;
s1.a = 2;
S s2 = move(s1);
assert(s1.a == 1);
assert(s2.a == 2);
move
(
(local variable) expected.Expected!(Buf, IoError, NoGcHook) buffer
buffer
.
inout(sparkles.event_horizon.buffer.Buf) expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
)),
`@nogc` function `eh_callback_tcp_echo.send` cannot call non-@nogc function `sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator).submit!(OpSend)` which calls `trySubmitWithRetry` which calls `scope @disable this(this);`
&
void eh_callback_tcp_echo.sent(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
sent
,
(parameter) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
).
bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
} void
void eh_callback_tcp_echo.sent(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
sent
(void*
(parameter) void* context
context
, ref
(struct) sparkles.event_horizon.op.Completion

What a tier-A callback receives. Passed by ref: the callback may move(done.buf) to keep the buffer; otherwise the loop recycles it to its origin after the callback returns.

Completion
(parameter) sparkles.event_horizon.op.Completion done
done
) nothrow @nogc
{ auto
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
= cast(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*)
(parameter) void* context
context
;
assert(
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
> 0 &&
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
<=
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.pendingSend
pendingSend
);
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
+=
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
;
if (
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
<
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
.
(constant) ulong "hello".length = 5LU
length
)
void eh_callback_tcp_echo.send(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
send
(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
);
else if (!
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system bool eh_callback_tcp_echo.Endpoint.server
server
)
void eh_callback_tcp_echo.receive(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
receive
(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
);
} void
void eh_callback_tcp_echo.received(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
received
(void*
(parameter) void* context
context
, ref
(struct) sparkles.event_horizon.op.Completion

What a tier-A callback receives. Passed by ref: the callback may move(done.buf) to keep the buffer; otherwise the loop recycles it to its origin after the callback returns.

Completion
(parameter) sparkles.event_horizon.op.Completion done
done
) nothrow @nogc
{ auto
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
= cast(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*)
(parameter) void* context
context
;
assert(
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
> 0 &&
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
+
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
<=
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
.
(constant) ulong "hello".length = 5LU
length
);
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
[
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
..
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
+
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
] = cast(const(char)[])
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) sparkles.event_horizon.buffer.Buf sparkles.event_horizon.op.Completion.buf

the buffer moving back out (may be empty)

buf
[];
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
+=
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
;
if (
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
<
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
.
(constant) ulong "hello".length = 5LU
length
)
void eh_callback_tcp_echo.receive(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
receive
(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
);
else { assert(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
[] ==
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
);
if (
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system bool eh_callback_tcp_echo.Endpoint.server
server
)
void eh_callback_tcp_echo.send(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
send
(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
);
} } void
void eh_callback_tcp_echo.accepted(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
accepted
(void*
(parameter) void* context
context
, ref
(struct) sparkles.event_horizon.op.Completion

What a tier-A callback receives. Passed by ref: the callback may move(done.buf) to keep the buffer; otherwise the loop recycles it to its origin after the callback returns.

Completion
(parameter) sparkles.event_horizon.op.Completion done
done
) nothrow @nogc
{ auto
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
= cast(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*)
(parameter) void* context
context
;
assert(
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
>= 0);
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
.
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
=
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
;
void eh_callback_tcp_echo.receive(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
receive
(
(local variable) eh_callback_tcp_echo.Endpoint* endpoint
endpoint
);
} void
void eh_callback_tcp_echo.connected(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
connected
(void*
(parameter) void* context
context
, ref
(struct) sparkles.event_horizon.op.Completion

What a tier-A callback receives. Passed by ref: the callback may move(done.buf) to keep the buffer; otherwise the loop recycles it to its origin after the callback returns.

Completion
(parameter) sparkles.event_horizon.op.Completion done
done
) nothrow @nogc
{ assert(
(parameter) sparkles.event_horizon.op.Completion done
done
.
(field) int sparkles.event_horizon.op.Completion.res

raw result: >= 0 payload or -errno

res
== 0);
void eh_callback_tcp_echo.send(eh_callback_tcp_echo.Endpoint* endpoint) nothrow @nogc @system
send
(cast(
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
*)
(parameter) void* context
context
);
} void
void D main() @system
main
()
{ auto
(local variable) int listener
listener
=
int core.sys.posix.sys.socket.socket(int, int, int) nothrow @nogc @safe
socket
(
(enum value) core.sys.posix.sys.socket.AF_INET = 2
AF_INET
,
(enum value) core.sys.posix.sys.socket.SOCK_STREAM = 1
SOCK_STREAM
, 0);
assert(
(local variable) int listener
listener
>= 0);
scope(exit)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) int listener
listener
);
(struct) core.sys.posix.netinet.in_.sockaddr_in
sockaddr_in
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
;
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(field) ushort core.sys.posix.netinet.in_.sockaddr_in.sin_family
sin_family
=
(enum value) core.sys.posix.sys.socket.AF_INET = 2
AF_INET
;
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(field) core.sys.posix.arpa.inet.in_addr core.sys.posix.netinet.in_.sockaddr_in.sin_addr
sin_addr
.
(field) uint core.sys.posix.arpa.inet.in_addr.s_addr
s_addr
=
uint core.sys.posix.arpa.inet.htonl(uint) pure nothrow @nogc @trusted
htonl
(
(enum value) core.sys.posix.netinet.in_.INADDR_LOOPBACK = 2130706433u
INADDR_LOOPBACK
);
assert(
int core.sys.posix.sys.socket.bind(int, scope const(core.sys.posix.sys.socket.sockaddr*), uint) nothrow @nogc
bind
(
(local variable) int listener
listener
, cast(
(struct) core.sys.posix.sys.socket.sockaddr
sockaddr
*) &
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
,
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(constant) ulong core.sys.posix.netinet.in_.sockaddr_in.sizeof = 16LU
sizeof
) == 0);
assert(
int core.sys.posix.sys.socket.listen(int, int) nothrow @nogc @safe
listen
(
(local variable) int listener
listener
, 1) == 0);
(alias) core.sys.posix.sys.socket.socklen_t = uint
socklen_t
(local variable) uint length
length
=
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(constant) ulong core.sys.posix.netinet.in_.sockaddr_in.sizeof = 16LU
sizeof
;
assert(
int core.sys.posix.sys.socket.getsockname(int, scope core.sys.posix.sys.socket.sockaddr*, scope uint*) nothrow @nogc
getsockname
(
(local variable) int listener
listener
, cast(
(struct) core.sys.posix.sys.socket.sockaddr
sockaddr
*) &
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
, &
(local variable) uint length
length
) == 0);
auto
(local variable) int clientFd
clientFd
=
int core.sys.posix.sys.socket.socket(int, int, int) nothrow @nogc @safe
socket
(
(enum value) core.sys.posix.sys.socket.AF_INET = 2
AF_INET
,
(enum value) core.sys.posix.sys.socket.SOCK_STREAM = 1
SOCK_STREAM
, 0);
assert(
(local variable) int clientFd
clientFd
>= 0);
scope(exit)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) int clientFd
clientFd
);
(struct) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator)

Fixed pool of same-size buffers carved out of one contiguous slab drawn from Allocator (SPEC §6.3) — the guideline-§4 generic-library shape: monostate allocators cost zero bytes (stateSize idiom), stateful ones are passed to create and embedded. When the backend supports registered buffers the slab is registered once and every Buf carries its slot index; lowering then picks the FIXED opcodes purely from Buf.origin — the user never spells "fixed". (Registration wiring lands in M8; until then every pool Buf has BufOrigin.pool.)

BufferPool
!()
(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool
pool
;
assert(!
(template instance) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator)
BufferPool
!().
expected.Expected!(void, IoError, NoGcHook) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).create(out sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool, uint count, uint bufSize) pure nothrow @nogc @safe

Allocates count` × `bufSize bytes; all-or-nothing.

create
(
(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool
pool
, 4, 2).
bool expected.Expected!(void, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasError!()() const pure nothrow @nogc @property @safe

Checks if Expected has error

hasError
);
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)
DefaultLoop
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
;
assert(!
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)
DefaultLoop
.
expected.Expected!(void, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).create(out sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop, in sparkles.event_horizon.loop.LoopConfig cfg = LoopConfig(BackendConfig(256u, 0u, cast(ubyte)0u, cast(ubyte)0u), 0u, & defaultFatalHook)) nothrow @nogc @safe

Out-parameter factory (SPEC §9.1: IoResult cannot return a non-copyable owner by value): backend setup → capability probe (the hard-error semantics of SPEC §3.4) → slab allocation. All-or-nothing.

create
(
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
).
noreturn sparkles.event_horizon.loop.defaultFatalHook(in sparkles.base.io.errors.IoError why) nothrow @nogc @trusted

The default FatalHook: raw write(2) of a static message plus the errno, then abort().

hasError
, "no completion backend");
scope(exit)
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
.
void sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).destroy() nothrow @nogc @safe

Structured teardown; the scope discipline (M5) guarantees the precondition at higher tiers. An armed waker (SPEC §5.6) is loop infrastructure, not work — destroy disarms it itself. A queued or in-flight cancellation is work: its target is live, so the first precondition already covers the pending set and the reserved slot.

destroy
();
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
(local variable) eh_callback_tcp_echo.Endpoint server
server
=
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
(&
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
, &
(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool
pool
, -1, true);
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
(local variable) eh_callback_tcp_echo.Endpoint client
client
=
(struct) eh_callback_tcp_echo.Endpoint
Endpoint
(&
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
, &
(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool
pool
,
(local variable) int clientFd
clientFd
);
scope(exit) if (
(local variable) eh_callback_tcp_echo.Endpoint server
server
.
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
>= 0)
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) eh_callback_tcp_echo.Endpoint server
server
.
(field) @system int eh_callback_tcp_echo.Endpoint.fd
fd
);
(struct) sparkles.event_horizon.net.SockAddr

A sockaddr_storage-sized POD plus its length — library-owned (SPEC §4.1): peer backends and test doubles use it without any libc coupling.

SockAddr
(local variable) sparkles.event_horizon.net.SockAddr target
target
;
(local variable) sparkles.event_horizon.net.SockAddr target
target
.
(field) ubyte[128] sparkles.event_horizon.net.SockAddr.storage

raw sockaddr bytes (or an opaque test-double key)

storage
[0 ..
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(constant) ulong core.sys.posix.netinet.in_.sockaddr_in.sizeof = 16LU
sizeof
] = (cast(ubyte*) &
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
)[0 ..
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(constant) ulong core.sys.posix.netinet.in_.sockaddr_in.sizeof = 16LU
sizeof
];
(local variable) sparkles.event_horizon.net.SockAddr target
target
.
(field) uint sparkles.event_horizon.net.SockAddr.len

valid length of storage

len
=
(local variable) core.sys.posix.netinet.in_.sockaddr_in address
address
.
(constant) ulong core.sys.posix.netinet.in_.sockaddr_in.sizeof = 16LU
sizeof
;
assert(
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
.
expected.Expected!(OpHandle, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).submit!(sparkles.event_horizon.op.OpAccept)(sparkles.event_horizon.op.OpAccept op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @nogc @safe

Submits op with a completion callback (SPEC §5.2). Owned buffers move into the op slot and come back via Completion.buf; on a submission error the buffer is recycled to its origin (it does not come back — there will be no completion).

The ctx lifetime rule: ctx must stay valid until the op's terminal completion is dispatched — cancel alone does not shorten that (the terminal CQE still arrives and still invokes cb). A caller whose ctx dies earlier must detach the handle first: after detach returns, the callback never runs. Handing a stack frame's address to ctx without one of those guarantees is exactly the use-after-free the retired kernel-timer deadline shipped (SPEC §8.3).

Backpressure

on a full submission queue the loop performs one implicit flush retry, then returns EAGAIN; an exhausted slab returns ENOBUFS.

submit
(
(struct) sparkles.event_horizon.op.OpAccept

Accept one connection; the completion res is the new fd. The peer address is fetched on demand (getpeername), not stored per slot.

OpAccept
(
(local variable) int listener
listener
), &
void eh_callback_tcp_echo.accepted(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
accepted
, &
(local variable) eh_callback_tcp_echo.Endpoint server
server
).
bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
assert(
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
.
expected.Expected!(OpHandle, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).submit!(sparkles.event_horizon.op.OpConnect)(sparkles.event_horizon.op.OpConnect op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @nogc @safe

Submits op with a completion callback (SPEC §5.2). Owned buffers move into the op slot and come back via Completion.buf; on a submission error the buffer is recycled to its origin (it does not come back — there will be no completion).

The ctx lifetime rule: ctx must stay valid until the op's terminal completion is dispatched — cancel alone does not shorten that (the terminal CQE still arrives and still invokes cb). A caller whose ctx dies earlier must detach the handle first: after detach returns, the callback never runs. Handing a stack frame's address to ctx without one of those guarantees is exactly the use-after-free the retired kernel-timer deadline shipped (SPEC §8.3).

Backpressure

on a full submission queue the loop performs one implicit flush retry, then returns EAGAIN; an exhausted slab returns ENOBUFS.

submit
(
(struct) sparkles.event_horizon.op.OpConnect

Outbound connect; the address is copied into the operand store.

OpConnect
(
(local variable) int clientFd
clientFd
,
(local variable) sparkles.event_horizon.net.SockAddr target
target
), &
void eh_callback_tcp_echo.connected(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @system
connected
, &
(local variable) eh_callback_tcp_echo.Endpoint client
client
).
bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safe

Checks if Expected has value

hasValue
);
assert(!
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
.
expected.Expected!(void, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).run() nothrow @nogc @safe

Runs until stop() or until drained (no live user/timer ops — an armed waker alone does not keep ``run() alive; SPEC §5.6).

run
().
bool expected.Expected!(void, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasError!()() const pure nothrow @nogc @property @safe

Checks if Expected has error

hasError
);
assert(
(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) loop
loop
.
uint sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).inFlight() const pure nothrow @nogc @safe

User and timer ops currently in flight (an armed waker is excluded — infrastructure, not work; SPEC §5.6).

inFlight
== 0 &&
(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) pool
pool
.
uint sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).available() const pure nothrow @nogc @safe

Buffers currently available.

available
== 4);
assert(
(local variable) eh_callback_tcp_echo.Endpoint server
server
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
== 5 &&
(local variable) eh_callback_tcp_echo.Endpoint client
client
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.sent
sent
== 5);
assert(
(local variable) eh_callback_tcp_echo.Endpoint server
server
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
== 5 &&
(local variable) eh_callback_tcp_echo.Endpoint client
client
.
(field) @system ulong eh_callback_tcp_echo.Endpoint.received
received
== 5);
assert(
(local variable) eh_callback_tcp_echo.Endpoint client
client
.
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
[] ==
(constant) @system string eh_callback_tcp_echo.payload = "hello"
payload
);
void std.stdio.writeln!(string, char[])(string __param_0, char[] __param_1) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("echoed: ",
(local variable) eh_callback_tcp_echo.Endpoint client
client
.
(field) @system char[5] eh_callback_tcp_echo.Endpoint.bytes
bytes
[]);
}