path-addressing.dhover×518all
#!/usr/bin/env dub
/+ dub.sdl:
    name "property_tree_path_addressing"
    targetPath "build"
    dflags "-preview=in" "-preview=dip1000"
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/
/**
 * The path as the node address (fork D3), in both directions.
 *
 * Grammar:  path := seg ( "." name | "[" digits "]" | "[#" digits "]" )*
 *           seg  := name | '["' quoted '"]'      (backslash-escaped ", \)
 *
 * Under test:
 *   C8.  The SAME path text resolves two ways: at compile time it becomes a
 *        direct field access (`subject.material.stops[1].weight`, no lookup,
 *        `ref`-returning, so writes are ordinary assignments); at run time it
 *        walks a generated dispatch with the same segment semantics.
 *   C9.  The runtime walk is generated from the type, parameterised by TYPE
 *        ONLY ([`open-set-descent.d`](./open-set-descent.d)'s rule), so it terminates on recursive types and needs
 *        no registry.
 *   C10. Both directions agree — verified by differential test over every
 *        path the planner emits.
 *   C11. Index paths are POSITIONAL, and that is a real defect, not a
 *        nitpick: deleting element 0 silently re-points every later element's
 *        expansion, selection and in-progress edit (rjsf's synthetic-key
 *        finding).
 *   C25. The fix is element-provided identity, not an adapter side table: an
 *        element type opting in with `ulong propElementKey() const` makes
 *        `[#7]` resolve BY KEY through the same generated walk, unmoved by
 *        removal or reorder of earlier elements. A duplicate or absent key —
 *        and `[#…]` on a collection that never opted in — is refused, never
 *        resolved positionally. (Added with the spec review; the earlier
 *        revision minted the id in an adapter-owned table, the ambient side
 *        table PRN1/PRN2 argue against.)
 *   C26. Names outside the identifier subset (erased children: JSON keys with
 *        `.`, `[`, spaces, leading digits) use a QUOTED segment `["…"]` with
 *        backslash escapes. The emitter picks bare exactly when the name is
 *        identifier-shaped, so every emitted path re-parses to the same
 *        segments; the quoted and bare spellings of the same member resolve
 *        identically.
 *
 * Run: `dub run --single path-addressing.d`
 */
module 
(module) property_tree_path_addressing

The path as the node address (fork D3), in both directions.

Grammar

path := seg ( "." name | "" digits "" | "#" digits "" )* seg := name | '"' quoted '"' (backslash-escaped ", )

Under test: C8. The SAME path text resolves two ways: at compile time it becomes a direct field access (subject.material.stops[1].weight, no lookup, ref-returning, so writes are ordinary assignments); at run time it walks a generated dispatch with the same segment semantics. C9. The runtime walk is generated from the type, parameterised by TYPE ONLY (open-set-descent.d's rule), so it terminates on recursive types and needs no registry. C10. Both directions agree — verified by differential test over every path the planner emits. C11. Index paths are POSITIONAL, and that is a real defect, not a nitpick: deleting element 0 silently re-points every later element's expansion, selection and in-progress edit (rjsf's synthetic-key finding). C25. The fix is element-provided identity, not an adapter side table: an element type opting in with ulong propElementKey() const makes [#7] resolve BY KEY through the same generated walk, unmoved by removal or reorder of earlier elements. A duplicate or absent key — and [#…] on a collection that never opted in — is refused, never resolved positionally. (Added with the spec review; the earlier revision minted the id in an adapter-owned table, the ambient side table PRN1/PRN2 argue against.) C26. Names outside the identifier subset (erased children: JSON keys with ., [, spaces, leading digits) use a QUOTED segment ["…"] with backslash escapes. The emitter picks bare exactly when the name is identifier-shaped, so every emitted path re-parses to the same segments; the quoted and bare spellings of the same member resolve identically.

Run

dub run --single path-addressing.d

property_tree_path_addressing
;
import
(package) std
std
.
(module) std.conv

A one-stop shop for converting values from one type to another.

Category Functions
Generic asOriginalType castFrom parse to toChars bitCast
Strings text wtext dtext writeText writeWText writeDText hexString
Numeric octal roundTo signed unsigned
Exceptions ConvException ConvOverflowException

Source

std/conv.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe, Kenji Hara
conv
:
(alias template) property_tree_path_addressing.text = std.conv.text(T...)(T args) if (T.length > 0)

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
,
(alias template) property_tree_path_addressing.to = std.conv.to(T)

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

to
;
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_path_addressing.isAggregateType = std.traits.isAggregateType(T)

Detect whether type T is an aggregate type.

isAggregateType
,
(alias template) property_tree_path_addressing.isArray = std.traits.isArray(T)

Detect whether type T is an array (static or dynamic; for associative arrays see isAssociativeArray).

isArray
,
(alias template) property_tree_path_addressing.isDynamicArray = std.traits.isDynamicArray(T)

Detect whether type T is a dynamic array.

isDynamicArray
,
(alias template) property_tree_path_addressing.isSomeString = std.traits.isSomeString(T)

Detect whether T is one of the built-in string types.

The built-in string types are Char[], where Char is any of char, wchar or dchar, with or without qualifiers.

Static arrays of characters (like char[80]) are not considered built-in string types.

isSomeString
;
@safe: // ── path segments ──────────────────────────────────────────────────────────── struct
(struct) property_tree_path_addressing.Seg
Seg
{
(alias) object.string = string
string
(field) string property_tree_path_addressing.Seg.name
name
;
(alias) object.size_t = ulong
size_t
(field) ulong property_tree_path_addressing.Seg.index
index
; bool
(field) bool property_tree_path_addressing.Seg.isIndex
isIndex
; bool
(field) bool property_tree_path_addressing.Seg.isKey
isKey
; ulong
(field) ulong property_tree_path_addressing.Seg.key
key
; }
/// Parses at CTFE and at run time — the same function.
(struct) property_tree_path_addressing.Seg
Seg
[]
property_tree_path_addressing.Seg[] property_tree_path_addressing.segments(const(char)[] path) pure @safe

Parses at CTFE and at run time — the same function.

segments
(const(char)[]
(parameter) const(char)[] path
path
) pure
{
(struct) property_tree_path_addressing.Seg
Seg
[]
(local variable) property_tree_path_addressing.Seg[] segs
segs
;
(alias) object.size_t = ulong
size_t
(local variable) ulong i
i
;
while (
(local variable) ulong i
i
<
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
)
{ if (
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
] == '.') {
(local variable) ulong i
i
++; continue; }
if (
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
] == '[')
{ if (
(local variable) ulong i
i
+ 1 <
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
+ 1] == '#') // [#key] (C25)
{
(alias) object.size_t = ulong
size_t
(local variable) ulong j
j
=
(local variable) ulong i
i
+ 2;
while (
(local variable) ulong j
j
<
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] != ']')
(local variable) ulong j
j
++;
(struct) property_tree_path_addressing.Seg
Seg
(local variable) property_tree_path_addressing.Seg s
s
= { isKey: true, key:
ulong std.conv.to!ulong.to!(const(char)[])(const(char)[] __param_0) pure @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!ulong(
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
+ 2 ..
(local variable) ulong j
j
]) };
(local variable) property_tree_path_addressing.Seg[] segs
segs
~=
(local variable) property_tree_path_addressing.Seg s
s
;
(local variable) ulong i
i
=
(local variable) ulong j
j
+ 1;
} else if (
(local variable) ulong i
i
+ 1 <
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
+ 1] == '"') // ["name"] (C26)
{
(alias) object.size_t = ulong
size_t
(local variable) ulong j
j
=
(local variable) ulong i
i
+ 2;
(alias) object.string = string
string
(local variable) string name
name
;
while (
(local variable) ulong j
j
<
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] != '"')
{ if (
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] == '\\')
(local variable) ulong j
j
++;
(local variable) string name
name
~=
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
];
(local variable) ulong j
j
++;
}
(local variable) property_tree_path_addressing.Seg[] segs
segs
~=
(struct) property_tree_path_addressing.Seg
Seg
(
(local variable) string name
name
, 0, false);
(local variable) ulong i
i
=
(local variable) ulong j
j
+ 2; // past the closing `"` and `]`
} else {
(alias) object.size_t = ulong
size_t
(local variable) ulong j
j
= ++
(local variable) ulong i
i
;
while (
(local variable) ulong j
j
<
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] != ']')
(local variable) ulong j
j
++;
(local variable) property_tree_path_addressing.Seg[] segs
segs
~=
(struct) property_tree_path_addressing.Seg
Seg
(null,
ulong std.conv.to!ulong.to!(const(char)[])(const(char)[] __param_0) pure @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.size_t = ulong
size_t
(
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
..
(local variable) ulong j
j
]), true);
(local variable) ulong i
i
=
(local variable) ulong j
j
+ 1;
} } else {
(alias) object.size_t = ulong
size_t
(local variable) ulong j
j
=
(local variable) ulong i
i
;
while (
(local variable) ulong j
j
<
(parameter) const(char)[] path
path
.
(field) ulong const(char)[].length
length
&&
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] != '.' &&
(parameter) const(char)[] path
path
[
(local variable) ulong j
j
] != '[')
(local variable) ulong j
j
++;
(local variable) property_tree_path_addressing.Seg[] segs
segs
~=
(struct) property_tree_path_addressing.Seg
Seg
(
(parameter) const(char)[] path
path
[
(local variable) ulong i
i
..
(local variable) ulong j
j
].
string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safe

Provide the .idup array property, which creates an immutable duplicate.

idup
, 0, false);
(local variable) ulong i
i
=
(local variable) ulong j
j
;
} } return
(local variable) property_tree_path_addressing.Seg[] segs
segs
;
} /// The inverse: how the walk mints a child's path. A name outside the bare /// identifier subset is emitted as a quoted segment, so every emitted path /// re-parses to the same segments (C26).
(alias) object.string = string
string
string property_tree_path_addressing.childPath(string parent, string member) pure nothrow @safe

The inverse: how the walk mints a child's path. A name outside the bare identifier subset is emitted as a quoted segment, so every emitted path re-parses to the same segments (C26).

childPath
(
(alias) object.string = string
string
(parameter) string parent
parent
,
(alias) object.string = string
string
(parameter) string member
member
) pure nothrow
{ bool
(local variable) bool bare
bare
=
(parameter) string member
member
.
(field) ulong string.length
length
> 0 && !(
(parameter) string member
member
[0] >= '0' &&
(parameter) string member
member
[0] <= '9');
foreach (
(parameter) immutable(char) c
c
;
(parameter) string member
member
)
(local variable) bool bare
bare
&=
(local variable) immutable(char) c
c
== '_' || (
(local variable) immutable(char) c
c
>= 'a' &&
(local variable) immutable(char) c
c
<= 'z') || (
(local variable) immutable(char) c
c
>= 'A' &&
(local variable) immutable(char) c
c
<= 'Z')
|| (
(local variable) immutable(char) c
c
>= '0' &&
(local variable) immutable(char) c
c
<= '9');
if (
(local variable) bool bare
bare
)
return
(parameter) string parent
parent
.
(field) ulong string.length
length
?
(parameter) string parent
parent
~ "." ~
(parameter) string member
member
:
(parameter) string member
member
;
(alias) object.string = string
string
(local variable) string q
q
= `["`;
foreach (
(parameter) immutable(char) c
c
;
(parameter) string member
member
)
{ if (
(local variable) immutable(char) c
c
== '"' ||
(local variable) immutable(char) c
c
== '\\')
(local variable) string q
q
~= '\\';
(local variable) string q
q
~=
(local variable) immutable(char) c
c
;
} return
(parameter) string parent
parent
~
(local variable) string q
q
~ `"]`;
} /// ditto
(alias) object.string = string
string
string property_tree_path_addressing.elementPath(string parent, ulong i) pure @safe

The inverse: how the walk mints a child's path. A name outside the bare identifier subset is emitted as a quoted segment, so every emitted path re-parses to the same segments (C26).

elementPath
(
(alias) object.string = string
string
(parameter) string parent
parent
,
(alias) object.size_t = ulong
size_t
(parameter) ulong i
i
) pure
=>
(parameter) string parent
parent
~ "[" ~
(parameter) ulong i
i
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]";
/// ditto — stable identity for an opted-in element (C25)
(alias) object.string = string
string
string property_tree_path_addressing.keyedPath(string parent, ulong key) pure @safe

ditto — stable identity for an opted-in element (C25)

keyedPath
(
(alias) object.string = string
string
(parameter) string parent
parent
, ulong
(parameter) ulong key
key
) pure
=>
(parameter) string parent
parent
~ "[#" ~
(parameter) ulong key
key
.
string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safe

The to template converts a value from one type to another. The source type is deduced and the target type must be specified, for example the expression to`!int(42.0)` converts the number 42 from `double` to `int`. The conversion is "safe", i.e., it checks for overflow; to!int(4.2e10) would throw the ConvOverflowException exception. Overflow checks are only inserted when necessary, e.g., ``to!double(42) does not do any checking because any int fits in a double.

Conversions from string to numeric types differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion of strings to signed types, the grammar recognized is: Integer: Sign UnsignedInteger UnsignedInteger Sign: + -

For conversion to unsigned types, the grammar recognized is: UnsignedInteger: DecimalDigit DecimalDigit UnsignedInteger

Examples

Converting a value to its own type (useful mostly for generic code) simply returns its argument.

int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14

Converting among numeric types is a safe way to cast them around.

Conversions from floating-point types to integral types allow loss of precision (the fractional part of a floating-point number). The conversion is truncating towards zero, the same way a cast would truncate. (To round a floating point value when casting to an integral, use roundTo.)

import std.exception : assertThrown;

int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));

assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);

When converting strings to numeric types, note that D hexadecimal and binary literals are not handled. Neither the prefixes that indicate the base, nor the horizontal bar used to separate groups of digits are recognized. This also applies to the suffixes that indicate the type.

To work around this, you can specify a radix for conversions involving numbers.

auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);

Conversions from integral types to floating-point types always succeed, but might lose accuracy. The largest integers with a predecessor representable in floating-point format are 2^24-1 for float, 2^53-1 for double, and 2^64-1 for real (when real is 80-bit, e.g. on Intel machines).

// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);

Conversion from string types to char types enforces the input to consist of a single code point, and said code point must fit in the target type. Otherwise, ConvException is thrown.

import std.exception : assertThrown;

assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');

// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');

// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));

Converting an array to another array type works by converting each element in turn. Associative arrays can be converted to associative arrays as long as keys and values can in turn be converted.

import std.string : split;

int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);

Conversions operate transitively, meaning that they work on arrays and associative arrays of any complexity.

This conversion works because to`!short` applies to an `int`, to!wstring applies to a string, to`!string` applies to a `double`, and to!(double[]) applies to an int[]. The conversion might throw an exception because ``to!short might fail the range check.

int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);

Object-to-object conversions by dynamic casting throw exception when the source is non-null and the target is null.

import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));

Stringize conversion from all types is supported.

  • String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

  • Converts array (other than strings) to string. Each element is converted by calling ``to!T.

  • Associative array to string conversion. Each element is converted by calling ``to!T.

  • Object to string conversion calls toString against the object or returns "null" if the object is null.

  • Struct to string conversion calls toString against the struct if it is defined.

  • For structs that do not define toString, the conversion to string produces the list of fields.

  • Enumerated types are converted to strings as their symbolic names.

  • Boolean values are converted to "true" or "false".

  • char, wchar, dchar to a string type.

  • Unsigned or signed integers to strings.

    special case

    : Convert integral value to string in radix radix. radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36 and their case is determined by the letterCase parameter.

  • All floating point types to all string types.

  • Pointer to string conversions convert the pointer to a size_t value. If pointer is char*, treat it as C-style strings. In that case, this function is @system.

See formatValue on how toString should be defined.

// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");

// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
       to!string(associativeArray) == `["1":2, "0":1]`);

// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");

// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);

auto c = to!(wchar[])(b);
assert(c == "abcx");

Strings can be converted to enum types. The enum member with the same name as the input string is returned. The comparison is case-sensitive.

A ConvException is thrown if the enum does not have the specified member.

import std.exception : assertThrown;

enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to
!
(alias) object.string = string
string
~ "]";
// ── C8: compile-time resolution ────────────────────────────────────────────── /// `at!"a.b[2].c"(subject)` — a direct, `ref`-returning field access. The /// mixin is the path text with `[i]` left as-is, so D's own indexing applies; /// a typo is a compile error at the USE site. ref auto
uint property_tree_path_addressing.at!("fill.tint", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
(string P, T)(return ref
(alias) T = property_tree_path_addressing.Layer
T
(parameter) property_tree_path_addressing.Layer subject
subject
)
=> mixin("subject." ~ P); // ── C9: runtime resolution, generated from the type ────────────────────────── /// Resolves `path` against `subject` and calls `sink(leafRef, typeName)`. /// `sink` is an alias, so it is instantiated per leaf type — no `void*`, no /// registry, no virtual call. bool
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!(__lambda_L225_C14, property_tree_path_addressing.Fill)(ref property_tree_path_addressing.Fill subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) pure nothrow @nogc @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
(alias sink, T)(ref
(alias) T = property_tree_path_addressing.Fill
T
(parameter) property_tree_path_addressing.Fill subject
subject
, in
(struct) property_tree_path_addressing.Seg
Seg
[]
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
,
(alias) object.size_t = ulong
size_t
(parameter) ulong at_
at_
= 0)
{ static if (
(template instance) std.traits.isAggregateType!(property_tree_path_addressing.Fill)
isAggregateType
!
(alias) T = property_tree_path_addressing.Fill
T
&& !
(template instance) std.traits.isSomeString!(property_tree_path_addressing.Fill)
isSomeString
!
(alias) T = property_tree_path_addressing.Fill
T
)
{ if (
(parameter) ulong at_
at_
==
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
.
(field) ulong const(property_tree_path_addressing.Seg[]).length
length
) { sink(
(parameter) property_tree_path_addressing.Fill subject
subject
,
(struct) property_tree_path_addressing.Fill
T
.
(constant) string property_tree_path_addressing.Fill.stringof = "Fill"
stringof
); return true; }
if (
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) bool property_tree_path_addressing.Seg.isIndex
isIndex
) return false;
switch (
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) string property_tree_path_addressing.Seg.name
name
)
{ static foreach (name; __traits(allMembers, T)) {{ static if (__traits(compiles, typeof(__traits(getMember, T, name))) && !is(typeof(__traits(getMember, T, name)) == function)) { case
(constant) string property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!(__lambda_L225_C14, property_tree_path_addressing.Fill).name = "stops"
name
:
return
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!(__lambda_L225_C14, property_tree_path_addressing.Stop[])(ref property_tree_path_addressing.Stop[] subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) pure nothrow @nogc @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!sink(__traits(getMember, subject, name),
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
,
(parameter) ulong at_
at_
+ 1);
} }} default: return false; } } else static if (is(
(alias) T = uint
T
== U*, U))
{ // C10a: the ASYMMETRY. `subject.parent.fill` compiles as an implicit // dereference, so the compile-time form crosses a pointer silently and // faults on null. The runtime walk must decide explicitly — here: a // null pointer is "no such path", never a fault. if (
(parameter) ulong at_
at_
==
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
.
(field) ulong const(property_tree_path_addressing.Seg[]).length
length
) { sink(
(parameter) property_tree_path_addressing.Layer* subject
subject
,
void property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).__lambda_L225_C14(__T2)(ref v, string tn)(ref property_tree_path_addressing.Layer* v, string tn) pure nothrow @nogc @safe
T
.
(constant) string property_tree_path_addressing.Layer*.stringof = "Layer*"
stringof
); return true; }
if (
(parameter) property_tree_path_addressing.Layer* subject
subject
is null) return false;
return
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!((ref v, string tn) { static if (__traits(compiles, v = value)) { v = value; ok = true; } } , property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!sink(*
(parameter) property_tree_path_addressing.Layer* subject
subject
,
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
,
(parameter) ulong at_
at_
);
} else static if (
(template instance) std.traits.isArray!uint
isArray
!
(alias) T = uint
T
&& !
(template instance) isSomeString!T
isSomeString
!
(alias) T = property_tree_path_addressing.Stop[]
T
)
{ if (
(parameter) ulong at_
at_
==
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
.
(field) ulong const(property_tree_path_addressing.Seg[]).length
length
) { sink(
(parameter) property_tree_path_addressing.Stop[] subject
subject
,
void property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).__lambda_L225_C14(__T2)(ref v, string tn)(ref property_tree_path_addressing.Stop[] v, string tn) pure nothrow @nogc @safe
T
.
(constant) string property_tree_path_addressing.Stop[].stringof = "Stop[]"
stringof
); return true; }
static if (__traits(hasMember, typeof(subject[0]), "propElementKey")) { // C25: keyed identity — `[#k]` resolves by the element's OWN key. // A duplicate or absent key is refused, never resolved positionally. if (
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) bool property_tree_path_addressing.Seg.isKey
isKey
)
{
(alias) object.size_t = ulong
size_t
(local variable) ulong found
found
,
(local variable) ulong hits
hits
;
foreach (
(local variable) ulong idx
idx
; 0 ..
(parameter) property_tree_path_addressing.KStop[] subject
subject
.
(field) ulong property_tree_path_addressing.KStop[].length
length
)
if (
(parameter) property_tree_path_addressing.KStop[] subject
subject
[
(local variable) ulong idx
idx
].
ulong property_tree_path_addressing.KStop.propElementKey() const pure nothrow @nogc @safe
propElementKey
==
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) ulong property_tree_path_addressing.Seg.key
key
)
{
(local variable) ulong found
found
=
(local variable) ulong idx
idx
;
(local variable) ulong hits
hits
++; }
if (
(local variable) ulong hits
hits
!= 1) return false;
return
bool property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot).resolve!(__lambda_L211_C14, property_tree_path_addressing.KStop)(ref property_tree_path_addressing.KStop subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) pure @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!sink(
(parameter) property_tree_path_addressing.KStop[] subject
subject
[
(local variable) ulong found
found
],
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
,
(parameter) ulong at_
at_
+ 1);
} } if (!
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) bool property_tree_path_addressing.Seg.isIndex
isIndex
||
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) ulong property_tree_path_addressing.Seg.index
index
>=
(parameter) property_tree_path_addressing.Stop[] subject
subject
.
(field) ulong property_tree_path_addressing.Stop[].length
length
) return false;
return
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!(__lambda_L225_C14, property_tree_path_addressing.Stop)(ref property_tree_path_addressing.Stop subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) pure nothrow @nogc @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!sink(
(parameter) property_tree_path_addressing.Stop[] subject
subject
[
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
[
(parameter) ulong at_
at_
].
(field) ulong property_tree_path_addressing.Seg.index
index
],
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
,
(parameter) ulong at_
at_
+ 1);
} else { if (
(parameter) ulong at_
at_
!=
(parameter) const(property_tree_path_addressing.Seg[]) segs
segs
.
(field) ulong const(property_tree_path_addressing.Seg[]).length
length
) return false;
sink(
(parameter) uint subject
subject
,
void property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer).__lambda_L211_C14(__T1)(ref v, string tn)(ref uint v, string tn) pure nothrow @safe
T
.
(constant) string uint.stringof = "uint"
stringof
);
return true; } } /// Read a leaf as text through the runtime path.
(alias) object.string = string
string
string property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, string path) pure @safe

Read a leaf as text through the runtime path.

readPath
(T)(ref
(alias) T = property_tree_path_addressing.KRoot
T
(parameter) property_tree_path_addressing.KRoot subject
subject
,
(alias) object.string = string
string
(parameter) string path
path
)
{
(alias) object.string = string
string
(local variable) string outp
outp
= "<no such path>";
static void
void property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot).nothing() pure nothrow @nogc @safe
nothing
() {}
bool property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot).resolve!((ref v, string tn) { static if (__traits(compiles, text(v))) { outp = text(v); } else { outp = "<" ~ tn ~ ">"; } } , property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) pure @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!((ref v, string tn) {
static if (__traits(compiles, text(v))) outp = text(v); else outp = "<" ~ tn ~ ">"; })(
(parameter) property_tree_path_addressing.KRoot subject
subject
,
property_tree_path_addressing.Seg[] property_tree_path_addressing.segments(const(char)[] path) pure @safe

Parses at CTFE and at run time — the same function.

segments
(
(parameter) string path
path
));
return
(local variable) string outp
outp
;
} /// Write a leaf through the runtime path; fails (returns false) when the /// value's type is not assignable to the addressed field. bool
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string)(ref property_tree_path_addressing.Layer subject, string path, string value) @safe

Write a leaf through the runtime path; fails (returns false) when the value's type is not assignable to the addressed field.

writePath
(T, V)(ref
(alias) T = property_tree_path_addressing.Layer
T
(parameter) property_tree_path_addressing.Layer subject
subject
,
(alias) object.string = string
string
(parameter) string path
path
,
(alias) V = string
V
(parameter) string value
value
)
{ bool
(local variable) bool ok
ok
;
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string).resolve!((ref v, string tn) { static if (__traits(compiles, v = value)) { v = value; ok = true; } } , property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, in property_tree_path_addressing.Seg[] segs, ulong at_ = 0LU) @safe

Resolves path against subject and calls sink(leafRef, typeName). sink is an alias, so it is instantiated per leaf type — no void*, no registry, no virtual call.

resolve
!((ref v, string tn) {
static if (__traits(compiles, v = value)) { v = value; ok = true; } })(
(parameter) property_tree_path_addressing.Layer subject
subject
,
property_tree_path_addressing.Seg[] property_tree_path_addressing.segments(const(char)[] path) pure @safe

Parses at CTFE and at run time — the same function.

segments
(
(parameter) string path
path
));
return
(local variable) bool ok
ok
;
} // ── the subject ────────────────────────────────────────────────────────────── struct
(struct) property_tree_path_addressing.Stop
Stop
{
(alias) object.string = string
string
(field) string property_tree_path_addressing.Stop.name
name
; double
(field) double property_tree_path_addressing.Stop.weight
weight
= 0; }
struct
(struct) property_tree_path_addressing.Fill
Fill
{
(struct) property_tree_path_addressing.Stop
Stop
[]
(field) property_tree_path_addressing.Stop[] property_tree_path_addressing.Fill.stops
stops
; uint
(field) uint property_tree_path_addressing.Fill.tint
tint
; }
struct
(struct) property_tree_path_addressing.Layer
Layer
{
(alias) object.string = string
string
(field) string property_tree_path_addressing.Layer.name
name
;
(struct) property_tree_path_addressing.Fill
Fill
(field) property_tree_path_addressing.Fill property_tree_path_addressing.Layer.fill
fill
;
(struct) property_tree_path_addressing.Layer
Layer
*
(field) property_tree_path_addressing.Layer* property_tree_path_addressing.Layer.parent
parent
; // recursive: proves C9's termination
} /// C25's subject: an element that OWNS its identity by opting in. struct
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
{ ulong
(field) ulong property_tree_path_addressing.KStop.id
id
;
(alias) object.string = string
string
(field) string property_tree_path_addressing.KStop.name
name
;
double
(field) double property_tree_path_addressing.KStop.weight
weight
= 0;
ulong
ulong property_tree_path_addressing.KStop.propElementKey() const pure nothrow @nogc @safe
propElementKey
() const pure nothrow @nogc =>
(field) ulong property_tree_path_addressing.KStop.id
id
;
} struct
(struct) property_tree_path_addressing.KRoot
KRoot
{
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
[]
(field) property_tree_path_addressing.KStop[] property_tree_path_addressing.KRoot.stops
stops
; }
// ── driving ────────────────────────────────────────────────────────────────── void
void D main() @safe
main
()
{ 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) writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

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

writefln
,
(alias template) 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.

Params: args = the items to write to stdout

Throws: In case of an I/O error, throws an $(LREF StdioException). 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
;
(struct) property_tree_path_addressing.Layer
Layer
(local variable) property_tree_path_addressing.Layer l
l
=
(struct) property_tree_path_addressing.Layer
Layer
("root");
(local variable) property_tree_path_addressing.Layer l
l
.
(field) property_tree_path_addressing.Fill property_tree_path_addressing.Layer.fill
fill
.
(field) property_tree_path_addressing.Stop[] property_tree_path_addressing.Fill.stops
stops
= [
(struct) property_tree_path_addressing.Stop
Stop
("a", 0.0),
(struct) property_tree_path_addressing.Stop
Stop
("b", 0.5),
(struct) property_tree_path_addressing.Stop
Stop
("c", 1.0)];
(local variable) property_tree_path_addressing.Layer l
l
.
(field) property_tree_path_addressing.Fill property_tree_path_addressing.Layer.fill
fill
.
(field) uint property_tree_path_addressing.Fill.tint
tint
= 0x336699;
() @trusted {
(local variable) property_tree_path_addressing.Layer l
l
.
(field) property_tree_path_addressing.Layer* property_tree_path_addressing.Layer.parent
parent
= &
(local variable) property_tree_path_addressing.Layer l
l
; }();
void std.stdio.writeln!string(string __param_0) @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
("C8 — compile-time resolution: a direct, ref-returning access");
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" at!\"fill.stops[1].name\" = %s",
string property_tree_path_addressing.at!("fill.stops[1].name", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[1].name"(
(local variable) property_tree_path_addressing.Layer l
l
));
double property_tree_path_addressing.at!("fill.stops[1].weight", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[1].weight"(
(local variable) property_tree_path_addressing.Layer l
l
) = 0.75; // ← an ordinary assignment
void std.stdio.writefln!(char, double)(in char[] fmt, double __param_1) @safe

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

writefln
(" after write, weight = %s",
double property_tree_path_addressing.at!("fill.stops[1].weight", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!`fill.stops[1].weight`(
(local variable) property_tree_path_addressing.Layer l
l
));
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" a typo is a BUILD error: %s",
__traits(compiles,
(template function) property_tree_path_addressing.at(string P, T)(return ref T subject)
at
!"fill.stpos[1].name"(
(local variable) property_tree_path_addressing.Layer l
l
)) ? "no" : "yes");
void std.stdio.writeln!string(string __param_0) @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
("\nC9/C10 — the same paths at run time, differential against C8");
struct
(struct) property_tree_path_addressing.main.Case
Case
{
(alias) object.string = string
string
(field) string property_tree_path_addressing.main.Case.path
path
;
(alias) object.string = string
string
(field) string property_tree_path_addressing.main.Case.ct
ct
; }
const
(local variable) const(property_tree_path_addressing.main.Case[]) cases
cases
= [
(struct) property_tree_path_addressing.main.Case
Case
("name",
string property_tree_path_addressing.at!("name", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"name"(
(local variable) property_tree_path_addressing.Layer l
l
)),
(struct) property_tree_path_addressing.main.Case
Case
("fill.tint",
string std.conv.text!uint(uint __param_0) pure nothrow @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
(
uint property_tree_path_addressing.at!("fill.tint", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.tint"(
(local variable) property_tree_path_addressing.Layer l
l
))),
(struct) property_tree_path_addressing.main.Case
Case
("fill.stops[0].name",
string property_tree_path_addressing.at!("fill.stops[0].name", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[0].name"(
(local variable) property_tree_path_addressing.Layer l
l
)),
(struct) property_tree_path_addressing.main.Case
Case
("fill.stops[1].weight",
string std.conv.text!double(double __param_0) pure @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
(
double property_tree_path_addressing.at!("fill.stops[1].weight", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[1].weight"(
(local variable) property_tree_path_addressing.Layer l
l
))),
(struct) property_tree_path_addressing.main.Case
Case
("fill.stops[2].name",
string property_tree_path_addressing.at!("fill.stops[2].name", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[2].name"(
(local variable) property_tree_path_addressing.Layer l
l
)),
(struct) property_tree_path_addressing.main.Case
Case
("parent.fill.stops[2].weight",
string std.conv.text!double(double __param_0) pure @safe

Convenience functions for converting one or more arguments of any type into text (the three character widths).

text
(
double property_tree_path_addressing.at!("parent.fill.stops[2].weight", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"parent.fill.stops[2].weight"(
(local variable) property_tree_path_addressing.Layer l
l
))),
];
(alias) object.size_t = ulong
size_t
(local variable) ulong agreed
agreed
;
foreach (
(parameter) const(property_tree_path_addressing.main.Case) c
c
;
(local variable) const(property_tree_path_addressing.main.Case[]) cases
cases
)
{ const
(local variable) const(string) rt
rt
=
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
,
(local variable) const(property_tree_path_addressing.main.Case) c
c
.
(field) string property_tree_path_addressing.main.Case.path
path
);
const
(local variable) const(bool) same
same
=
(local variable) const(string) rt
rt
==
(local variable) const(property_tree_path_addressing.main.Case) c
c
.
(field) string property_tree_path_addressing.main.Case.ct
ct
;
(local variable) ulong agreed
agreed
+=
(local variable) const(bool) same
same
;
void std.stdio.writefln!(char, string, string, string, string)(in char[] fmt, string __param_1, string __param_2, string __param_3, string __param_4) @safe

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

writefln
(" %-30s ct=%-8s rt=%-8s %s",
(local variable) const(property_tree_path_addressing.main.Case) c
c
.
(field) string property_tree_path_addressing.main.Case.path
path
,
(local variable) const(property_tree_path_addressing.main.Case) c
c
.
(field) string property_tree_path_addressing.main.Case.ct
ct
,
(local variable) const(string) rt
rt
,
(local variable) const(bool) same
same
? "✓" : "✗ DISAGREE");
}
void std.stdio.writefln!(char, ulong, ulong)(in char[] fmt, ulong __param_1, ulong __param_2) @safe

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

writefln
(" %s/%s agree",
(local variable) ulong agreed
agreed
,
(local variable) const(property_tree_path_addressing.main.Case[]) cases
cases
.
(field) ulong const(property_tree_path_addressing.main.Case[]).length
length
);
void std.stdio.writeln!string(string __param_0) @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 pointer hop needed an explicit branch: `a.b` where `a` is a");
void std.stdio.writeln!string(string __param_0) @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
(" pointer is an IMPLICIT deref at compile time — it faults on null,");
void std.stdio.writeln!string(string __param_0) @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
(" while the runtime walk answers <no such path>.)");
{
(struct) property_tree_path_addressing.Layer
Layer
(local variable) property_tree_path_addressing.Layer orphan
orphan
=
(struct) property_tree_path_addressing.Layer
Layer
("orphan"); // parent is null
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" null pointer, runtime: parent.name → %s",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer orphan
orphan
, "parent.name"));
void std.stdio.writeln!string(string __param_0) @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
(" null pointer, compile-time: at!\"parent.name\"(orphan) would FAULT");
}
void std.stdio.writeln!string(string __param_0) @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
("\n bad paths are refused, not crashed:");
foreach (
(parameter) string bad
bad
; ["fill.nope", "fill.stops[9].name", "fill[0]", "name.x"])
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safe

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

writefln
(" %-22s → %s",
(local variable) string bad
bad
,
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
,
(local variable) string bad
bad
));
void std.stdio.writeln!string(string __param_0) @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
("\n writes through the runtime path:");
void std.stdio.writefln!(char, bool)(in char[] fmt, bool __param_1) @safe

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

writefln
(" writePath(\"fill.stops[0].name\", \"zero\") = %s",
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string)(ref property_tree_path_addressing.Layer subject, string path, string value) @safe

Write a leaf through the runtime path; fails (returns false) when the value's type is not assignable to the addressed field.

writePath
(
(local variable) property_tree_path_addressing.Layer l
l
, "fill.stops[0].name", "zero"));
void std.stdio.writefln!(char, bool)(in char[] fmt, bool __param_1) @safe

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

writefln
(" writePath(\"fill.tint\", \"not a uint\") = %s",
bool property_tree_path_addressing.writePath!(property_tree_path_addressing.Layer, string)(ref property_tree_path_addressing.Layer subject, string path, string value) @safe

Write a leaf through the runtime path; fails (returns false) when the value's type is not assignable to the addressed field.

writePath
(
(local variable) property_tree_path_addressing.Layer l
l
, "fill.tint", "not a uint"));
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" fill.stops[0].name is now %s",
string property_tree_path_addressing.at!("fill.stops[0].name", property_tree_path_addressing.Layer)(return ref property_tree_path_addressing.Layer subject) pure nothrow @nogc ref @safe

``at!"a.b[2].c"(subject) — a direct, ref-returning field access. The mixin is the path text with [i] left as-is, so D's own indexing applies; a typo is a compile error at the USE site.

at
!"fill.stops[0].name"(
(local variable) property_tree_path_addressing.Layer l
l
));
void std.stdio.writeln!string(string __param_0) @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
("\nC11 — index paths are positional. Reader opens fill.stops[1]:");
(alias) object.string = string
string
(local variable) string opened
opened
= "fill.stops[1]";
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safe

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

writefln
(" opened %s → element %s",
(local variable) string opened
opened
,
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
,
(local variable) string opened
opened
~ ".name"));
(local variable) property_tree_path_addressing.Layer l
l
.
(field) property_tree_path_addressing.Fill property_tree_path_addressing.Layer.fill
fill
.
(field) property_tree_path_addressing.Stop[] property_tree_path_addressing.Fill.stops
stops
=
(local variable) property_tree_path_addressing.Layer l
l
.
(field) property_tree_path_addressing.Fill property_tree_path_addressing.Layer.fill
fill
.
(field) property_tree_path_addressing.Stop[] property_tree_path_addressing.Fill.stops
stops
[1 .. $]; // element 0 removed elsewhere
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" after removing element 0, the SAME key now points at %s",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
,
(local variable) string opened
opened
~ ".name"));
void std.stdio.writeln!string(string __param_0) @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
(" → expansion, selection and in-progress edits silently move.");
void std.stdio.writeln!string(string __param_0) @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
("\nC25 — the fix is element-provided identity: `[#key]` resolves");
void std.stdio.writeln!string(string __param_0) @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
(" by `propElementKey`, through the same generated walk:");
(struct) property_tree_path_addressing.KRoot
KRoot
(local variable) property_tree_path_addressing.KRoot k
k
;
(local variable) property_tree_path_addressing.KRoot k
k
.
(field) property_tree_path_addressing.KStop[] property_tree_path_addressing.KRoot.stops
stops
= [
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
(7, "b", 0.5),
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
(9, "c", 1.0)];
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" stops[#9].name → %s",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, string path) pure @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.KRoot k
k
, "stops[#9].name"));
(local variable) property_tree_path_addressing.KRoot k
k
.
(field) property_tree_path_addressing.KStop[] property_tree_path_addressing.KRoot.stops
stops
=
(local variable) property_tree_path_addressing.KRoot k
k
.
(field) property_tree_path_addressing.KStop[] property_tree_path_addressing.KRoot.stops
stops
[1 .. $]; // element 0 removed elsewhere
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" after removing [#7] → %s (address unmoved)",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, string path) pure @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.KRoot k
k
, "stops[#9].name"));
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" absent key stops[#3] → %s",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, string path) pure @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.KRoot k
k
, "stops[#3].name"));
(local variable) property_tree_path_addressing.KRoot k
k
.
(field) property_tree_path_addressing.KStop[] property_tree_path_addressing.KRoot.stops
stops
= [
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
(7, "x"),
(struct) property_tree_path_addressing.KStop

C25's subject: an element that OWNS its identity by opting in.

KStop
(7, "y")]; // a duplicate key
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" duplicate key stops[#7] → %s (refused, never positional)",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.KRoot)(ref property_tree_path_addressing.KRoot subject, string path) pure @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.KRoot k
k
, "stops[#7].name"));
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" unkeyed fill.stops[#7] → %s (identity is opt-in)",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
, "fill.stops[#7].name"));
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" the emitter mints it: keyedPath(\"stops\", 9) = %s",
string property_tree_path_addressing.keyedPath(string parent, ulong key) pure @safe

ditto — stable identity for an opted-in element (C25)

keyedPath
("stops", 9));
void std.stdio.writeln!string(string __param_0) @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
("\nC26 — quoted segments carry names the bare grammar cannot:");
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safe

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

writefln
(" [\"fill\"].tint ≡ fill.tint → %s ≡ %s",
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
, `["fill"].tint`),
string property_tree_path_addressing.readPath!(property_tree_path_addressing.Layer)(ref property_tree_path_addressing.Layer subject, string path) @safe

Read a leaf as text through the runtime path.

readPath
(
(local variable) property_tree_path_addressing.Layer l
l
, "fill.tint"));
const
(local variable) const(string) weird
weird
= `a.b [x] "q"`;
const
(local variable) const(string) minted
minted
=
string property_tree_path_addressing.childPath(string parent, string member) pure nothrow @safe

The inverse: how the walk mints a child's path. A name outside the bare identifier subset is emitted as a quoted segment, so every emitted path re-parses to the same segments (C26).

childPath
("",
(local variable) const(string) weird
weird
);
const
(local variable) const(property_tree_path_addressing.Seg[]) back
back
=
property_tree_path_addressing.Seg[] property_tree_path_addressing.segments(const(char)[] path) pure @safe

Parses at CTFE and at run time — the same function.

segments
(
(local variable) const(string) minted
minted
);
void std.stdio.writefln!(char, const(string)[], string)(in char[] fmt, const(string)[] __param_1, string __param_2) @safe

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

writefln
(" childPath of %(%s%) mints %s", [
(local variable) const(string) weird
weird
],
(local variable) const(string) minted
minted
);
void std.stdio.writefln!(char, bool)(in char[] fmt, bool __param_1) @safe

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

writefln
(" …which re-parses to one name segment (round-trip: %s)",
(local variable) const(property_tree_path_addressing.Seg[]) back
back
.
(field) ulong const(property_tree_path_addressing.Seg[]).length
length
== 1 &&
(local variable) const(property_tree_path_addressing.Seg[]) back
back
[0].
(field) string property_tree_path_addressing.Seg.name
name
==
(local variable) const(string) weird
weird
);
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safe

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

writefln
(" identifier-shaped names stay bare: childPath(\"fill\", \"tint\") = %s",
string property_tree_path_addressing.childPath(string parent, string member) pure nothrow @safe

The inverse: how the walk mints a child's path. A name outside the bare identifier subset is emitted as a quoted segment, so every emitted path re-parses to the same segments (C26).

childPath
("fill", "tint"));
}