#!/usr/bin/env dub
/+ dub.sdl:
name "eh_callback_file_read"
dependency "sparkles:event-horizon" path="../../../../.."
platforms "linux"
buildType "checked" {
buildOptions "optimize" "inline" "debugInfo"
}
+/
@system:
import (package) corecore.(module) core.lifetimelifetime : (alias template) eh_callback_file_read.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.
move;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.errnoD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/errno.h.html, errno.h
Source
core/stdc/errno.d
errno : (alias constant) eh_callback_file_read.ENOENT = int core.stdc.errno.ENOENT = 2ENOENT;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.fcntlD header file for POSIX.
fcntl : (alias constant) eh_callback_file_read.AT_FDCWD = int core.sys.posix.fcntl.AT_FDCWD = -100AT_FDCWD, (alias constant) eh_callback_file_read.O_RDONLY = int core.sys.posix.fcntl.O_RDONLY = 0O_RDONLY;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.stdlibD header file for POSIX.
stdlib : (alias) eh_callback_file_read.mkdtemp = char* core.sys.posix.stdlib.mkdtemp(char*) nothrow @nogcmkdtemp;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias) eh_callback_file_read.tempDir = string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
tempDir, (alias template) eh_callback_file_read.write = std.file.write(R)(R name, const void[] buffer) if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)Write buffer to file name.
Creates the file if it does not already exist.
write, (alias template) eh_callback_file_read.remove = std.file.remove(R)(R name) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Delete file name.
remove, (alias template) eh_callback_file_read.rmdir = std.file.rmdir(R)(R pathname) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Remove directory pathname.
rmdir;
import (package) stdstd.(module) std.pathThis module is used to manipulate path strings.
All functions, with the exception of expandTilde (and in some
cases absolutePath and relativePath), are pure
string manipulation functions; they don't depend on any state outside
the program, nor do they perform any actual file system actions.
This has the consequence that the module does not make any distinction
between a path that points to a directory and a path that points to a
file, and it does not know whether or not the object pointed to by the
path actually exists in the file system.
To differentiate between these cases, use isDir and
exists.
Note that on Windows, both the backslash (\) and the slash (/)
are in principle valid directory separators. This module treats them
both on equal footing, but in cases where a new separator is
added, a backslash will be used. Furthermore, the buildNormalizedPath
function will replace all slashes with backslashes on that platform.
In general, the functions in this module assume that the input paths
are well-formed. (That is, they should not contain invalid characters,
they should follow the file system's path format, etc.) The result
of calling a function on an ill-formed path is undefined. When there
is a chance that a path or a file name is invalid (for instance, when it
has been input by the user), it may sometimes be desirable to use the
isValidFilename and isValidPath functions to check
this.
Most functions do not perform any memory allocations, and if a string is
returned, it is usually a slice of an input string. If a function
allocates, this is explicitly mentioned in the documentation.
Category Functions Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension Other filenameCharCmp filenameCmp globMatch CaseSensitive
Source
std/path.d
path : (alias template) eh_callback_file_read.buildPath = std.path.buildPath(Range)(scope Range segments) if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))Combines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
buildPath;
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias) eh_callback_file_read.toStringz = immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trustedtoStringz, (alias template) eh_callback_file_read.fromStringz = std.string.fromStringz(Char)(return scope inout(Char)* cString) if (isSomeChar!Char)fromStringz;
import (package) stdstd.(module) std.stdioCategory 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:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) eh_callback_file_read.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);
}
}
writeln;
import (package) sparklessparkles.(package) sparkles.event_horizonevent_horizon.(module) sparkles.event_horizon.loopTier 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) sparklessparkles.(package) sparkles.event_horizonevent_horizon.(module) sparkles.event_horizon.opPortable 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) sparklessparkles.(package) sparkles.event_horizonevent_horizon.(module) sparkles.event_horizon.bufferOwned-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_file_read.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;
struct (struct) eh_callback_file_read.StateState
{
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)DefaultLoop* (field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop;
(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_file_read.State.poolpool;
const(char)* (field) @system const(char)* eh_callback_file_read.State.pathpath;
int (field) @system int eh_callback_file_read.State.fdfd = -1;
char[18] (field) @system char[18] eh_callback_file_read.State.contentscontents;
(alias) object.size_t = ulongsize_t (field) @system ulong eh_callback_file_read.State.usedused;
bool (field) @system bool eh_callback_file_read.State.missingSeenmissingSeen, (field) @system bool eh_callback_file_read.State.eofeof, (field) @system bool eh_callback_file_read.State.closedclosed;
}
void void eh_callback_file_read.closed(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemclosed(void* (parameter) void* contextcontext, ref (struct) sparkles.event_horizon.op.CompletionWhat 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 donedone) nothrow @nogc
{
auto (local variable) eh_callback_file_read.State* statestate = cast((struct) eh_callback_file_read.StateState*) (parameter) void* contextcontext;
assert((parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res == 0 && (local variable) eh_callback_file_read.State* statestate.(field) @system bool eh_callback_file_read.State.eofeof);
(local variable) eh_callback_file_read.State* statestate.(field) @system int eh_callback_file_read.State.fdfd = -1;
(local variable) eh_callback_file_read.State* statestate.(field) @system bool eh_callback_file_read.State.closedclosed = true;
}
void void eh_callback_file_read.readNext(eh_callback_file_read.State* state) nothrow @nogc @systemreadNext((struct) eh_callback_file_read.StateState* (parameter) eh_callback_file_read.State* statestate) nothrow @nogc
{
auto (local variable) expected.Expected!(Buf, IoError, NoGcHook) bufferbuffer = (parameter) eh_callback_file_read.State* statestate.(field) @system sparkles.event_horizon.buffer.BufferPool!(Mallocator)* eh_callback_file_read.State.poolpool.expected.Expected!(Buf, IoError, NoGcHook) sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).acquire() nothrow @nogc @trustedHands out one buffer; ENOBUFS when the pool is exhausted.
acquire();
assert((local variable) expected.Expected!(Buf, IoError, NoGcHook) bufferbuffer.bool expected.Expected!(sparkles.event_horizon.buffer.Buf, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
assert((parameter) eh_callback_file_read.State* statestate.(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop.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.OpRead)(sparkles.event_horizon.op.OpRead op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @safeSubmits 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.OpReadPositioned read into an owned buffer (the buffer's full capacity).
OpRead((parameter) eh_callback_file_read.State* statestate.(field) @system int eh_callback_file_read.State.fdfd, sparkles.event_horizon.buffer.Buf core.lifetime.move!(sparkles.event_horizon.buffer.Buf)(ref return scope sparkles.event_horizon.buffer.Buf source) nothrow @nogc @safeExamples
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) bufferbuffer.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 @safeReturns 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), (parameter) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused),
&void eh_callback_file_read.readDone(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemreadDone, (parameter) eh_callback_file_read.State* statestate).bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
}
void void eh_callback_file_read.readDone(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemreadDone(void* (parameter) void* contextcontext, ref (struct) sparkles.event_horizon.op.CompletionWhat 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 donedone) nothrow @nogc
{
auto (local variable) eh_callback_file_read.State* statestate = cast((struct) eh_callback_file_read.StateState*) (parameter) void* contextcontext;
assert((parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res >= 0, "a read error is not EOF");
if ((parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res == 0)
{
(local variable) eh_callback_file_read.State* statestate.(field) @system bool eh_callback_file_read.State.eofeof = true;
assert((local variable) eh_callback_file_read.State* statestate.(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop.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.OpClose)(sparkles.event_horizon.op.OpClose op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @nogc @safeSubmits 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.OpCloseCloses a descriptor through the ring.
OpClose((local variable) eh_callback_file_read.State* statestate.(field) @system int eh_callback_file_read.State.fdfd), &void eh_callback_file_read.closed(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemclosed, (parameter) void* contextcontext).bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
return;
}
assert((local variable) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused + (parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res <= (local variable) eh_callback_file_read.State* statestate.(field) @system char[18] eh_callback_file_read.State.contentscontents.(constant) ulong char[18].length = 18LUlength);
(local variable) eh_callback_file_read.State* statestate.(field) @system char[18] eh_callback_file_read.State.contentscontents[(local variable) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused .. (local variable) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused + (parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res] = cast(const(char)[]) (parameter) sparkles.event_horizon.op.Completion donedone.(field) sparkles.event_horizon.buffer.Buf sparkles.event_horizon.op.Completion.bufthe buffer moving back out (may be empty)
buf[];
(local variable) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused += (parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res;
// Reuse the returned owner instead of borrowing its slice after return.
assert((local variable) eh_callback_file_read.State* statestate.(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop.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.OpRead)(sparkles.event_horizon.op.OpRead op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @safeSubmits 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.OpReadPositioned read into an owned buffer (the buffer's full capacity).
OpRead((local variable) eh_callback_file_read.State* statestate.(field) @system int eh_callback_file_read.State.fdfd, sparkles.event_horizon.buffer.Buf core.lifetime.move!(sparkles.event_horizon.buffer.Buf)(ref return scope sparkles.event_horizon.buffer.Buf source) nothrow @nogc @safeExamples
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((parameter) sparkles.event_horizon.op.Completion donedone.(field) sparkles.event_horizon.buffer.Buf sparkles.event_horizon.op.Completion.bufthe buffer moving back out (may be empty)
buf), (local variable) eh_callback_file_read.State* statestate.(field) @system ulong eh_callback_file_read.State.usedused),
&void eh_callback_file_read.readDone(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemreadDone, (parameter) void* contextcontext).bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
}
void void eh_callback_file_read.opened(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemopened(void* (parameter) void* contextcontext, ref (struct) sparkles.event_horizon.op.CompletionWhat 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 donedone) nothrow @nogc
{
auto (local variable) eh_callback_file_read.State* statestate = cast((struct) eh_callback_file_read.StateState*) (parameter) void* contextcontext;
assert((parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res >= 0);
(local variable) eh_callback_file_read.State* statestate.(field) @system int eh_callback_file_read.State.fdfd = (parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res;
void eh_callback_file_read.readNext(eh_callback_file_read.State* state) nothrow @nogc @systemreadNext((local variable) eh_callback_file_read.State* statestate);
}
void void eh_callback_file_read.missing(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemmissing(void* (parameter) void* contextcontext, ref (struct) sparkles.event_horizon.op.CompletionWhat 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 donedone) nothrow @nogc
{
auto (local variable) eh_callback_file_read.State* statestate = cast((struct) eh_callback_file_read.StateState*) (parameter) void* contextcontext;
assert((parameter) sparkles.event_horizon.op.Completion donedone.(field) int sparkles.event_horizon.op.Completion.resraw result: >= 0 payload or -errno
res == -(constant) int core.stdc.errno.ENOENT = 2ENOENT);
(local variable) eh_callback_file_read.State* statestate.(field) @system bool eh_callback_file_read.State.missingSeenmissingSeen = true;
assert((local variable) eh_callback_file_read.State* statestate.(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop.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.OpOpenAt)(sparkles.event_horizon.op.OpOpenAt op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @nogc @safeSubmits 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.OpOpenAtOpens a file relative to dirFd (AT_FDCWD for absolute/cwd paths);
the completion res is the new fd. path is NUL-terminated.
OpOpenAt((constant) int core.sys.posix.fcntl.AT_FDCWD = -100AT_FDCWD, (local variable) eh_callback_file_read.State* statestate.(field) @system const(char)* eh_callback_file_read.State.pathpath, (constant) int core.sys.posix.fcntl.O_RDONLY = 0O_RDONLY), &void eh_callback_file_read.opened(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemopened, (parameter) void* contextcontext).bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
}
void void D main() @systemmain()
{
auto (local variable) char[] patternpattern = (string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath(string std.file.tempDir() @trustedReturns the path to a directory for temporary files.
On POSIX platforms, it searches through the following list of directories
and returns the first one which is found to exist:
The directory given by the TMPDIR environment variable.
The directory given by the TEMP environment variable.
The directory given by the TMP environment variable.
/tmp/
/var/tmp/
/usr/tmp/
On all platforms, tempDir returns the current working directory on failure.
The return value of the function is cached, so the procedures described
below will only be performed the first time the function is called. All
subsequent runs will return the same string, regardless of whether
environment variables and directory structures have changed in the
meantime.
The POSIX tempDir algorithm is inspired by Python's
tempfile.tempdir.
Examples
import std.ascii : letters;
import std.conv : to;
import std.path : buildPath;
import std.random : randomSample;
import std.utf : byCodeUnit;
// random id with 20 letters
auto id = letters.byCodeUnit.randomSample(20).to!string;
auto myFile = tempDir.buildPath(id ~ "my_tmp_file");
scope(exit) myFile.remove;
myFile.write("hello");
assert(myFile.readText == "hello");
tempDir(), "eh-callback-file-XXXXXX") ~ '\0').char[] object.dup!char(const(char)[] a) pure nothrow @property @safedup;
assert(char* core.sys.posix.stdlib.mkdtemp(char*) nothrow @nogcmkdtemp((local variable) char[] patternpattern.(field) char* char[].ptrptr) !is null);
auto (local variable) string directorydirectory = inout(char)[] std.string.fromStringz!char(return scope inout(char)* cString) pure nothrow @nogc @systemfromStringz((local variable) char[] patternpattern.(field) char* char[].ptrptr).string object.idup!char(char[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
scope(exit) void std.file.rmdir!string(string pathname) @safeRemove directory pathname.
rmdir((local variable) string directorydirectory);
auto (local variable) string pathpath = string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string directorydirectory, "input");
void std.file.write!string(string name, const(void[]) buffer) @safeWrite buffer to file name.
Creates the file if it does not already exist.
Examples
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
write(deleteme, a); // deleteme is the name of a temporary file
const bytes = read(deleteme);
const fileInts = () @trusted { return cast(int[]) bytes; }();
assert(fileInts == a);
write((local variable) string pathpath, "hello from a file\n");
scope(exit) void std.file.remove!string(string name) @safeDelete file name.
remove((local variable) string pathpath);
// Both NUL-terminated paths outlive their terminal open completions.
auto (local variable) immutable(char)* namename = (local variable) string pathpath.immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trustedExamples
import core.stdc.string : strlen;
import std.conv : to;
auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);
string test = "";
p = toStringz(test);
assert(*p == 0);
test = "\0";
p = toStringz(test);
assert(*p == 0);
test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);
const string test2 = "";
p = toStringz(test2);
assert(*p == 0);
assert(toStringz([]) is toStringz(""));
toStringz;
auto (local variable) immutable(char)* absentabsent = string std.path.buildPath!char(const(char)[][] paths...) pure nothrow @safeCombines one or more path segments.
This function takes a set of path segments, given as an input
range of string elements or as a set of string arguments,
and concatenates them with each other. Directory separators
are inserted between segments if necessary. If any of the
path segments are absolute (as defined by isAbsolute), the
preceding segments will be dropped.
On Windows, if one of the path segments are rooted, but not absolute
(e.g. \foo), all preceding path segments down to the previous
root will be dropped. (See below for an example.)
This function always allocates memory to hold the resulting path.
The variadic overload is guaranteed to only perform a single
allocation, as is the range version if paths is a forward
range.
Examples
version (Posix)
{
assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
assert(buildPath("/foo", "/bar") == "/bar");
}
version (Windows)
{
assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
assert(buildPath("foo", `d:\bar`) == `d:\bar`);
assert(buildPath("foo", `\bar`) == `\bar`);
assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
}
buildPath((local variable) string directorydirectory, "missing").immutable(char)* std.string.toStringz(scope const(char)[] s) pure nothrow @trustedExamples
import core.stdc.string : strlen;
import std.conv : to;
auto p = toStringz("foo");
assert(strlen(p) == 3);
const(char)[] foo = "abbzxyzzy";
p = toStringz(foo[3 .. 5]);
assert(strlen(p) == 2);
string test = "";
p = toStringz(test);
assert(*p == 0);
test = "\0";
p = toStringz(test);
assert(*p == 0);
test = "foo\0";
p = toStringz(test);
assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0);
const string test2 = "";
p = toStringz(test2);
assert(*p == 0);
assert(toStringz([]) is toStringz(""));
toStringz;
(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) poolpool;
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 @safeAllocates count` × `bufSize bytes; all-or-nothing.
create((local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) poolpool, 1, 8).bool expected.Expected!(void, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasError!()() const pure nothrow @nogc @property @safeChecks if Expected has error
hasError);
(struct) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)DefaultLoop (local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) looploop;
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 @safeOut-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) looploop).noreturn sparkles.event_horizon.loop.defaultFatalHook(in sparkles.base.io.errors.IoError why) nothrow @nogc @trustedThe 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) looploop.void sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).destroy() nothrow @nogc @safeStructured 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_file_read.StateState (local variable) eh_callback_file_read.State statestate;
(local variable) eh_callback_file_read.State statestate.(field) @system sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator)* eh_callback_file_read.State.looploop = &(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) looploop;
(local variable) eh_callback_file_read.State statestate.(field) @system sparkles.event_horizon.buffer.BufferPool!(Mallocator)* eh_callback_file_read.State.poolpool = &(local variable) sparkles.event_horizon.buffer.BufferPool!(Mallocator) poolpool;
(local variable) eh_callback_file_read.State statestate.(field) @system const(char)* eh_callback_file_read.State.pathpath = (local variable) immutable(char)* namename;
assert((local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) looploop.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.OpOpenAt)(sparkles.event_horizon.op.OpOpenAt op, void function(void* ctx, ref sparkles.event_horizon.op.Completion done) nothrow @nogc cb, void* ctx = null) nothrow @nogc @safeSubmits 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.OpOpenAtOpens a file relative to dirFd (AT_FDCWD for absolute/cwd paths);
the completion res is the new fd. path is NUL-terminated.
OpOpenAt((constant) int core.sys.posix.fcntl.AT_FDCWD = -100AT_FDCWD, (local variable) immutable(char)* absentabsent, (constant) int core.sys.posix.fcntl.O_RDONLY = 0O_RDONLY), &void eh_callback_file_read.missing(void* context, ref sparkles.event_horizon.op.Completion done) nothrow @nogc @systemmissing, &(local variable) eh_callback_file_read.State statestate).bool expected.Expected!(sparkles.event_horizon.op.OpHandle, sparkles.base.io.errors.IoError, sparkles.base.text.errors.NoGcHook).hasValue!()() const pure nothrow @nogc @property @safeChecks if Expected has value
hasValue);
assert(!(local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) looploop.expected.Expected!(void, IoError, NoGcHook) sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).run() nothrow @nogc @safeRuns 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 @safeChecks if Expected has error
hasError);
assert((local variable) sparkles.event_horizon.loop.EventLoop!(UringBackend, Mallocator) looploop.uint sparkles.event_horizon.loop.EventLoop!(sparkles.event_horizon.backend.uring.UringBackend, std.experimental.allocator.mallocator.Mallocator).inFlight() const pure nothrow @nogc @safeUser 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) poolpool.uint sparkles.event_horizon.buffer.BufferPool!(std.experimental.allocator.mallocator.Mallocator).available() const pure nothrow @nogc @safeBuffers currently available.
available == 1);
assert((local variable) eh_callback_file_read.State statestate.(field) @system bool eh_callback_file_read.State.missingSeenmissingSeen && (local variable) eh_callback_file_read.State statestate.(field) @system bool eh_callback_file_read.State.eofeof && (local variable) eh_callback_file_read.State statestate.(field) @system bool eh_callback_file_read.State.closedclosed && (local variable) eh_callback_file_read.State statestate.(field) @system int eh_callback_file_read.State.fdfd == -1);
assert((local variable) eh_callback_file_read.State statestate.(field) @system ulong eh_callback_file_read.State.usedused == 18 && (local variable) eh_callback_file_read.State statestate.(field) @system char[18] eh_callback_file_read.State.contentscontents[] == "hello from a file\n");
void std.stdio.writeln!(string, ulong, string, char[])(string __param_0, ulong __param_1, string __param_2, char[] __param_3) @safeEquivalent 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);
}
}
writeln("read ", (local variable) eh_callback_file_read.State statestate.(field) @system ulong eh_callback_file_read.State.usedused, " bytes: ", (local variable) eh_callback_file_read.State statestate.(field) @system char[18] eh_callback_file_read.State.contentscontents[]);
}