reflect-descent.dhover×141all
#!/usr/bin/env dub
/+ dub.sdl:
    name "property_tree_reflect_descent"
    targetPath "build"
    dflags "-preview=in" "-preview=dip1000"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
/**
 * What a compile-time descent over `T` actually yields, and where it stops.
 *
 * Backs [../concepts.md](../concepts.md) § _descent decision_ and
 * [../sparkles-baseline.md](../sparkles-baseline.md) § _Recursion_: every
 * surveyed library decides "leaf or subtree?" at **runtime** — from a converter
 * ([../winforms-propertygrid.md](../winforms-propertygrid.md)), a
 * `ReflectRef` discriminant ([../bevy-inspector-egui.md](../bevy-inspector-egui.md)),
 * or a `PropertyInfo.type` ([../godot-inspector.md](../godot-inspector.md)).
 * In D the same decision is a `static if` over `isAggregateType`, and that moves
 * two failure modes from run time to compile time:
 *
 *   1. **A recursive type diverges at compile time, not at expand time.** Godot
 *      lets a reader unfold a self-referencing resource for as long as they keep
 *      clicking; the equivalent D descent never finishes compiling. The visited
 *      *type* set below is not an optimization — without it this program does
 *      not build: both ldc2 2.111 and dmd 2.112 stop with
 *      `Error: template instance ... recursive expansion exceeded allowed
 *      nesting limit` after 500 levels. That is a stronger guarantee than any
 *      surveyed library offers, and a harder constraint.
 *   2. **The whole tree is a value, not a walk.** `describe!T` runs in CTFE and
 *      returns a flat, pre-ordered row array, so the row count of a type is
 *      knowable before a frame is drawn.
 *
 * Run: `dub run --single reflect-descent.d`
 */
module 
(module) property_tree_reflect_descent

What a compile-time descent over T actually yields, and where it stops.

Backs ../concepts.md § descent decision_ and ../sparkles-baseline.md § Recursion_: every surveyed library decides "leaf or subtree?" at runtime — from a converter (../winforms-propertygrid.md), a ReflectRef discriminant (../bevy-inspector-egui.md), or a PropertyInfo.type (../godot-inspector.md). In D the same decision is a static if over isAggregateType, and that moves two failure modes from run time to compile time:

  1. A recursive type diverges at compile time, not at expand time. Godot lets a reader unfold a self-referencing resource for as long as they keep clicking; the equivalent D descent never finishes compiling. The visited type set below is not an optimization — without it this program does not build: both ldc2 2.111 and dmd 2.112 stop with

Error

template instance ... recursive expansion exceeded allowed nesting limit` after 500 levels. That is a stronger guarantee than any surveyed library offers, and a harder constraint.

  1. The whole tree is a value, not a walk. describe!T runs in CTFE and returns a flat, pre-ordered row array, so the row count of a type is knowable before a frame is drawn.

Run

dub run --single reflect-descent.d

property_tree_reflect_descent
;
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) property_tree_reflect_descent.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) property_tree_reflect_descent.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) std
std
.
(module) std.traits

Templates which extract information about types and symbols at compile time.

Category Templates
Symbol Name traits fullyQualifiedName mangledName moduleName packageName
Function traits isFunction arity functionAttributes hasFunctionAttributes functionLinkage FunctionTypeOf isSafe isUnsafe isFinal ParameterDefaults ParameterIdentifierTuple ParameterStorageClassTuple Parameters ReturnType SetFunctionAttributes variadicFunctionStyle
Aggregate Type traits BaseClassesTuple BaseTypeTuple classInstanceAlignment EnumMembers FieldNameTuple Fields hasAliasing hasElaborateAssign hasElaborateCopyConstructor hasElaborateDestructor hasElaborateMove hasIndirections hasMember hasStaticMember hasNested hasUnsharedAliasing InterfacesTuple isInnerClass isNested MemberFunctionsTuple RepresentationTypeTuple TemplateArgsOf TemplateOf TransitiveBaseTypeTuple
Type Conversion CommonType AllImplicitConversionTargets ImplicitConversionTargets CopyTypeQualifiers CopyConstness isAssignable isCovariantWith isImplicitlyConvertible isQualifierConvertible
Type Constructors InoutOf ConstOf SharedOf SharedInoutOf SharedConstOf SharedConstInoutOf ImmutableOf QualifierOf
Categories of types allSameType ifTestable isType isAggregateType isArray isAssociativeArray isAutodecodableString isBasicType isBoolean isBuiltinType isCopyable isDynamicArray isEqualityComparable isFloatingPoint isIntegral isNarrowString isConvertibleToString isNumeric isOrderingComparable isPointer isScalarType isSigned isSIMDVector isSomeChar isSomeString isStaticArray isUnsigned
Type behaviours isAbstractClass isAbstractFunction isCallable isDelegate isExpressions isFinalClass isFinalFunction isFunctionPointer isInstanceOf isIterable isMutable isSomeFunction isTypeTuple
General Types ForeachType KeyType Largest mostNegative OriginalType PointerTarget Signed Unconst Unshared Unqual Unsigned ValueType Promoted
Misc lvalueOf rvalueOf Select select
User-Defined Attributes hasUDA getUDAs getSymbolsByUDA

Source

std/traits.d

@copyrightCopyright The D Language Foundation 2005 - 2009.@licenseBoost License 1.0.@authorsWalter Bright, Tomasz Stachowiak (isExpressions), Andrei Alexandrescu, Shin Fujishiro, Robert Clipsham, David Nadlinger, Kenji Hara, Shoichi Kato
traits
:
(alias template) property_tree_reflect_descent.FieldNameTuple = std.traits.FieldNameTuple(T)

Get as an expression tuple the names of the fields of a struct, class, or union. This consists of the fields that take up memory space, excluding the hidden fields like the virtual function table pointer or a context pointer for nested types. Inherited fields (for classes) are not included. If T isn't a struct, class, interface or union, an expression tuple with an empty string is returned.

@history
  • Returned AliasSeq!"" for interfaces prior to 2.097

FieldNameTuple
,
(alias template) property_tree_reflect_descent.Fields = std.traits.Fields(T)

Get as a tuple the types of the fields of a struct, class, or union. This consists of the fields that take up memory space, excluding the hidden fields like the virtual function table pointer or a context pointer for nested types. If T isn't a struct, class, interface or union returns a tuple with one element T.

@history
  • Returned AliasSeq!(Interface) for interfaces prior to 2.097

Fields
,
(alias template) property_tree_reflect_descent.isAggregateType = std.traits.isAggregateType(T)

Detect whether type T is an aggregate type.

isAggregateType
,
(alias template) property_tree_reflect_descent.isPointer = std.traits.isPointer(T)

Detect whether type T is a pointer.

isPointer
,
(alias template) property_tree_reflect_descent.PointerTarget = std.traits.PointerTarget(T : T*)

Returns the target type of a pointer.

PointerTarget
;
@safe: /// One presented row of a reflected type: what a renderer needs before values. struct
(struct) property_tree_reflect_descent.FieldRow

One presented row of a reflected type: what a renderer needs before values.

FieldRow
{
(alias) object.string = string
string
(field) string property_tree_reflect_descent.FieldRow.path

dotted path from the root

path
; /// dotted path from the root
(alias) object.string = string
string
(field) string property_tree_reflect_descent.FieldRow.type

the field's static type

type
; /// the field's static type
(alias) object.size_t = ulong
size_t
(field) ulong property_tree_reflect_descent.FieldRow.depth

nesting level; 0 is a direct field of the root

depth
; /// nesting level; 0 is a direct field of the root
bool
(field) bool property_tree_reflect_descent.FieldRow.expandable

an aggregate we descended into

expandable
; /// an aggregate we descended into
bool
(field) bool property_tree_reflect_descent.FieldRow.cut

descent stopped here: the type is already on the path

cut
; /// descent stopped here: the type is already on the path
} /// The types a leaf editor exists for. Everything else is a candidate subtree. private enum bool
(constant) bool property_tree_reflect_descent.isLeafType!(property_tree_reflect_descent.Vec2) = false

The types a leaf editor exists for. Everything else is a candidate subtree.

isLeafType
(T) = is(
(alias) T = property_tree_reflect_descent.Vec2
T
== string) || !
(template instance) std.traits.isAggregateType!(property_tree_reflect_descent.Vec2)
isAggregateType
!
(alias) T = property_tree_reflect_descent.Vec2
T
;
/** Flattens `T` into pre-ordered rows at compile time. `Seen` is the set of aggregate types already open on the current path. It is what makes the function total: a type that contains itself (directly or through a pointer) is cut with `cut = true` instead of re-entering. */
(struct) property_tree_reflect_descent.FieldRow

One presented row of a reflected type: what a renderer needs before values.

FieldRow
[]
property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2)() pure nothrow @safe

Flattens T into pre-ordered rows at compile time.

Seen is the set of aggregate types already open on the current path. It is what makes the function total: a type that contains itself (directly or through a pointer) is cut with cut = true instead of re-entering.

describe
(T, size_t depth = 0, string prefix = "", Seen...)() pure nothrow
{
(struct) property_tree_reflect_descent.FieldRow

One presented row of a reflected type: what a renderer needs before values.

FieldRow
[]
(local variable) property_tree_reflect_descent.FieldRow[] rows
rows
;
static foreach (i, name;
(constant) string property_tree_reflect_descent.Vec2.fun!(x).NameOf = "x"
FieldNameTuple
!T)
{{ alias
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).F = float
F
=
(alias) std.traits.Fields!(property_tree_reflect_descent.Vec2) = (float, float)

Get as a tuple the types of the fields of a struct, class, or union. This consists of the fields that take up memory space, excluding the hidden fields like the virtual function table pointer or a context pointer for nested types. If T isn't a struct, class, interface or union returns a tuple with one element T.

Examples

import std.meta : AliasSeq;
struct S { int x; float y; }
static assert(is(Fields!S == AliasSeq!(int, float)));
@history
  • Returned AliasSeq!(Interface) for interfaces prior to 2.097

Fields
!
(alias) T = property_tree_reflect_descent.Vec2
T
[
(constant) ulong property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).i = 0LU
i
];
// A pointer is presented as the type it points at — that is what makes // `Node*` a cycle rather than an opaque address. static if (
(template instance) std.traits.isPointer!float
isPointer
!
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).F = float
F
&&
(template instance) isAggregateType!(PointerTarget!F)
isAggregateType
!(
(alias) T = property_tree_reflect_descent.Node
PointerTarget
!
(unresolved type) F
F
))
alias
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").Target = property_tree_reflect_descent.Node
Target
=
(alias) T = property_tree_reflect_descent.Node
PointerTarget
!
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").F = property_tree_reflect_descent.Node*
F
;
else alias
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).Target = float
Target
=
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).F = float
F
;
enum
(constant) string property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).path = "parent.position.x"
path
=
(constant) string property_tree_reflect_descent.prefix = "parent.position."
prefix
~
(constant) string property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").name = "parent"
name
;
enum bool
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).leaf = true
leaf
=
(template instance) property_tree_reflect_descent.isLeafType!float
isLeafType
!
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).Target = float
Target
;
enum bool
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).seen = false
seen
=
(template instance) property_tree_reflect_descent.anyIs!(float, property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2)
anyIs
!(
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).Target = float
Target
,
Seen
Seen
);
(local variable) property_tree_reflect_descent.FieldRow[] rows
rows
~=
(struct) property_tree_reflect_descent.FieldRow

One presented row of a reflected type: what a renderer needs before values.

FieldRow
(
(constant) string property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).path = "parent.position.x"
path
,
(struct) property_tree_reflect_descent.Vec2
F
.
(constant) string float.stringof = "float"
stringof
,
(constant) ulong property_tree_reflect_descent.depth = 2LU
depth
, !
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).leaf = true
leaf
&& !
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").seen = false
seen
, !
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 2LU, "parent.position.", property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2).leaf = true
leaf
&&
(constant) bool property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").seen = false
seen
);
static if (!leaf && !seen)
(local variable) property_tree_reflect_descent.FieldRow[] rows
rows
~=
property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.describe!(property_tree_reflect_descent.Vec2, 1LU, "position.", property_tree_reflect_descent.Vec2)() pure nothrow @safe

Flattens T into pre-ordered rows at compile time.

Seen is the set of aggregate types already open on the current path. It is what makes the function total: a type that contains itself (directly or through a pointer) is cut with cut = true instead of re-entering.

describe
!(
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "").Target = property_tree_reflect_descent.Vec2
Target
,
(constant) ulong property_tree_reflect_descent.depth = 1LU
depth
+ 1,
(constant) string property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 1LU, "parent.", property_tree_reflect_descent.Node).path = "parent.position"
path
~ ".",
Seen
Seen
,
(alias) property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 1LU, "parent.", property_tree_reflect_descent.Node).Target = property_tree_reflect_descent.Vec2
Target
)();
}} return
(local variable) property_tree_reflect_descent.FieldRow[] rows
rows
;
} private enum bool
(constant) bool property_tree_reflect_descent.anyIs!(float, property_tree_reflect_descent.Node, property_tree_reflect_descent.Vec2) = false
anyIs
(T, Seen...) = ()
{ bool
(local variable) bool found
found
;
static foreach (S; Seen)
(local variable) bool found
found
=
(local variable) bool found
found
|| is(
(alias) T = float
T
== S);
return
(local variable) bool found
found
;
}(); // --------------------------------------------------------------------------- // A subject with the three shapes that matter: a plain leaf, a nested // aggregate, and a type that reaches itself. // --------------------------------------------------------------------------- struct
(struct) property_tree_reflect_descent.Vec2
Vec2
{ float
(field) float property_tree_reflect_descent.Vec2.x
x
= 0,
(field) float property_tree_reflect_descent.Vec2.y
y
= 0;
} struct
(struct) property_tree_reflect_descent.Material
Material
{
(alias) object.string = string
string
(field) string property_tree_reflect_descent.Material.name
name
;
(struct) property_tree_reflect_descent.Vec2
Vec2
(field) property_tree_reflect_descent.Vec2 property_tree_reflect_descent.Material.offset
offset
;
bool
(field) bool property_tree_reflect_descent.Material.twoSided
twoSided
;
} struct
(struct) property_tree_reflect_descent.Node
Node
{
(alias) object.string = string
string
(field) string property_tree_reflect_descent.Node.label
label
;
(struct) property_tree_reflect_descent.Vec2
Vec2
(field) property_tree_reflect_descent.Vec2 property_tree_reflect_descent.Node.position
position
;
(struct) property_tree_reflect_descent.Material
Material
(field) property_tree_reflect_descent.Material property_tree_reflect_descent.Node.material
material
;
(struct) property_tree_reflect_descent.Node
Node
*
(field) property_tree_reflect_descent.Node* property_tree_reflect_descent.Node.parent
parent
; // the cycle
} void
void D main() @safe
main
()
{ // The whole tree is computed at compile time — this is a manifest constant, // not a walk performed while painting. enum
(constant) property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.main.rows = [FieldRow("label", "string", 0LU, false, false), FieldRow("position", "Vec2", 0LU, true, false), FieldRow("position.x", "float", 1LU, false, false), FieldRow("position.y", "float", 1LU, false, false), FieldRow("material", "Material", 0LU, true, false), FieldRow("material.name", "string", 1LU, false, false), FieldRow("material.offset", "Vec2", 1LU, true, false), FieldRow("material.offset.x", "float", 2LU, false, false), FieldRow("material.offset.y", "float", 2LU, false, false), FieldRow("material.twoSided", "bool", 1LU, false, false), FieldRow("parent", "Node*", 0LU, true, false), FieldRow("parent.label", "string", 1LU, false, false), FieldRow("parent.position", "Vec2", 1LU, true, false), FieldRow("parent.position.x", "float", 2LU, false, false), FieldRow("parent.position.y", "float", 2LU, false, false), FieldRow("parent.material", "Material", 1LU, true, false), FieldRow("parent.material.name", "string", 2LU, false, false), FieldRow("parent.material.offset", "Vec2", 2LU, true, false), FieldRow("parent.material.offset.x", "float", 3LU, false, false), FieldRow("parent.material.offset.y", "float", 3LU, false, false), FieldRow("parent.material.twoSided", "bool", 2LU, false, false), FieldRow("parent.parent", "Node*", 1LU, false, true)]
rows
=
property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.describe!(property_tree_reflect_descent.Node, 0LU, "")() pure nothrow @safe

Flattens T into pre-ordered rows at compile time.

Seen is the set of aggregate types already open on the current path. It is what makes the function total: a type that contains itself (directly or through a pointer) is cut with cut = true instead of re-entering.

describe
!
(struct) property_tree_reflect_descent.Node
Node
();
void std.stdio.writefln!(char, ulong)(in char[] fmt, ulong __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("%s rows for Node, all known at compile time",
(constant) property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.main.rows = [FieldRow("label", "string", 0LU, false, false), FieldRow("position", "Vec2", 0LU, true, false), FieldRow("position.x", "float", 1LU, false, false), FieldRow("position.y", "float", 1LU, false, false), FieldRow("material", "Material", 0LU, true, false), FieldRow("material.name", "string", 1LU, false, false), FieldRow("material.offset", "Vec2", 1LU, true, false), FieldRow("material.offset.x", "float", 2LU, false, false), FieldRow("material.offset.y", "float", 2LU, false, false), FieldRow("material.twoSided", "bool", 1LU, false, false), FieldRow("parent", "Node*", 0LU, true, false), FieldRow("parent.label", "string", 1LU, false, false), FieldRow("parent.position", "Vec2", 1LU, true, false), FieldRow("parent.position.x", "float", 2LU, false, false), FieldRow("parent.position.y", "float", 2LU, false, false), FieldRow("parent.material", "Material", 1LU, true, false), FieldRow("parent.material.name", "string", 2LU, false, false), FieldRow("parent.material.offset", "Vec2", 2LU, true, false), FieldRow("parent.material.offset.x", "float", 3LU, false, false), FieldRow("parent.material.offset.y", "float", 3LU, false, false), FieldRow("parent.material.twoSided", "bool", 2LU, false, false), FieldRow("parent.parent", "Node*", 1LU, false, true)]
rows
.
(field) ulong [FieldRow("label", "string", 0LU, false, false), FieldRow("position", "Vec2", 0LU, true, false), FieldRow("position.x", "float", 1LU, false, false), FieldRow("position.y", "float", 1LU, false, false), FieldRow("material", "Material", 0LU, true, false), FieldRow("material.name", "string", 1LU, false, false), FieldRow("material.offset", "Vec2", 1LU, true, false), FieldRow("material.offset.x", "float", 2LU, false, false), FieldRow("material.offset.y", "float", 2LU, false, false), FieldRow("material.twoSided", "bool", 1LU, false, false), FieldRow("parent", "Node*", 0LU, true, false), FieldRow("parent.label", "string", 1LU, false, false), FieldRow("parent.position", "Vec2", 1LU, true, false), FieldRow("parent.position.x", "float", 2LU, false, false), FieldRow("parent.position.y", "float", 2LU, false, false), FieldRow("parent.material", "Material", 1LU, true, false), FieldRow("parent.material.name", "string", 2LU, false, false), FieldRow("parent.material.offset", "Vec2", 2LU, true, false), FieldRow("parent.material.offset.x", "float", 3LU, false, false), FieldRow("parent.material.offset.y", "float", 3LU, false, false), FieldRow("parent.material.twoSided", "bool", 2LU, false, false), FieldRow("parent.parent", "Node*", 1LU, false, true)].length
length
);
void std.stdio.writeln!()() @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
();
foreach (
(parameter) property_tree_reflect_descent.FieldRow r
r
;
(constant) property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.main.rows = [FieldRow("label", "string", 0LU, false, false), FieldRow("position", "Vec2", 0LU, true, false), FieldRow("position.x", "float", 1LU, false, false), FieldRow("position.y", "float", 1LU, false, false), FieldRow("material", "Material", 0LU, true, false), FieldRow("material.name", "string", 1LU, false, false), FieldRow("material.offset", "Vec2", 1LU, true, false), FieldRow("material.offset.x", "float", 2LU, false, false), FieldRow("material.offset.y", "float", 2LU, false, false), FieldRow("material.twoSided", "bool", 1LU, false, false), FieldRow("parent", "Node*", 0LU, true, false), FieldRow("parent.label", "string", 1LU, false, false), FieldRow("parent.position", "Vec2", 1LU, true, false), FieldRow("parent.position.x", "float", 2LU, false, false), FieldRow("parent.position.y", "float", 2LU, false, false), FieldRow("parent.material", "Material", 1LU, true, false), FieldRow("parent.material.name", "string", 2LU, false, false), FieldRow("parent.material.offset", "Vec2", 2LU, true, false), FieldRow("parent.material.offset.x", "float", 3LU, false, false), FieldRow("parent.material.offset.y", "float", 3LU, false, false), FieldRow("parent.material.twoSided", "bool", 2LU, false, false), FieldRow("parent.parent", "Node*", 1LU, false, true)]
rows
)
{ char[]
(local variable) char[] indent
indent
;
foreach (
(local variable) ulong _
_
; 0 ..
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) ulong property_tree_reflect_descent.FieldRow.depth

nesting level; 0 is a direct field of the root

depth
)
(local variable) char[] indent
indent
~= " ";
const
(local variable) const(string) mark
mark
=
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) bool property_tree_reflect_descent.FieldRow.cut

descent stopped here: the type is already on the path

cut
? " [cut: type already on path]"
:
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) bool property_tree_reflect_descent.FieldRow.expandable

an aggregate we descended into

expandable
? " [subtree]" : "";
void std.stdio.writefln!(char, char[], string, string, string)(in char[] fmt, char[] __param_1, string __param_2, string __param_3, string __param_4) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("%s%s : %s%s",
(local variable) char[] indent
indent
,
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) string property_tree_reflect_descent.FieldRow.path

dotted path from the root

path
,
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) string property_tree_reflect_descent.FieldRow.type

the field's static type

type
,
(local variable) const(string) mark
mark
);
}
void std.stdio.writeln!()() @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
();
// The counts are compile-time facts too, which is what makes a static row // budget possible at all.
(alias) object.size_t = ulong
size_t
(local variable) ulong leaves
leaves
,
(local variable) ulong subtrees
subtrees
,
(local variable) ulong cuts
cuts
;
foreach (
(parameter) property_tree_reflect_descent.FieldRow r
r
;
(constant) property_tree_reflect_descent.FieldRow[] property_tree_reflect_descent.main.rows = [FieldRow("label", "string", 0LU, false, false), FieldRow("position", "Vec2", 0LU, true, false), FieldRow("position.x", "float", 1LU, false, false), FieldRow("position.y", "float", 1LU, false, false), FieldRow("material", "Material", 0LU, true, false), FieldRow("material.name", "string", 1LU, false, false), FieldRow("material.offset", "Vec2", 1LU, true, false), FieldRow("material.offset.x", "float", 2LU, false, false), FieldRow("material.offset.y", "float", 2LU, false, false), FieldRow("material.twoSided", "bool", 1LU, false, false), FieldRow("parent", "Node*", 0LU, true, false), FieldRow("parent.label", "string", 1LU, false, false), FieldRow("parent.position", "Vec2", 1LU, true, false), FieldRow("parent.position.x", "float", 2LU, false, false), FieldRow("parent.position.y", "float", 2LU, false, false), FieldRow("parent.material", "Material", 1LU, true, false), FieldRow("parent.material.name", "string", 2LU, false, false), FieldRow("parent.material.offset", "Vec2", 2LU, true, false), FieldRow("parent.material.offset.x", "float", 3LU, false, false), FieldRow("parent.material.offset.y", "float", 3LU, false, false), FieldRow("parent.material.twoSided", "bool", 2LU, false, false), FieldRow("parent.parent", "Node*", 1LU, false, true)]
rows
)
{ if (
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) bool property_tree_reflect_descent.FieldRow.cut

descent stopped here: the type is already on the path

cut
)
(local variable) ulong cuts
cuts
++;
else if (
(local variable) property_tree_reflect_descent.FieldRow r
r
.
(field) bool property_tree_reflect_descent.FieldRow.expandable

an aggregate we descended into

expandable
)
(local variable) ulong subtrees
subtrees
++;
else
(local variable) ulong leaves
leaves
++;
}
void std.stdio.writefln!(char, ulong, ulong, ulong)(in char[] fmt, ulong __param_1, ulong __param_2, ulong __param_3) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("leaves=%s subtrees=%s cuts=%s",
(local variable) ulong leaves
leaves
,
(local variable) ulong subtrees
subtrees
,
(local variable) ulong cuts
cuts
);
}