#!/usr/bin/env dub
/+ dub.sdl:
name "property_tree_erased_subject"
targetPath "build"
dflags "-preview=in" "-preview=dip1000"
buildType "checked" {
buildOptions "optimize" "inline" "debugInfo"
}
+/
/**
* One walk, two worlds (fork D1, as decided): the API is static
* introspection, and a DYNAMIC subject is served by a statically-typed
* erasure — a `JsonValue`-shaped type that supplies its children at run time
* through a capability the walk detects by presence.
*
* Under test:
* C16. `propChildren` (an `opApply` yielding `(name, ref child)`) is enough:
* a type that has it enumerates its own children; a type that does not
* is walked with `__traits`. One walk, no branch in the caller, no
* registry — the toolkit's capability-by-presence idiom.
* C17. A MIXED subject works: a plain struct with a `Dyn` field descends
* from static fields into dynamic ones and back, with one path syntax
* across the seam.
* C18. Arrays are children too, addressed `[i]`, in both worlds.
* C19. The capability also carries what static reflection cannot: the
* dynamic type states its own leaf presentation and whether it is
* expandable, so the row model needs no special case for it.
*
* Run: `dub run --single erased-subject.d`
*/
module (module) property_tree_erased_subjectOne walk, two worlds (fork D1, as decided): the API is static
introspection, and a DYNAMIC subject is served by a statically-typed
erasure — a JsonValue-shaped type that supplies its children at run time
through a capability the walk detects by presence.
Under test:
C16. propChildren (an opApply yielding (name, ref child)) is enough:
a type that has it enumerates its own children; a type that does not
is walked with __traits. One walk, no branch in the caller, no
registry — the toolkit's capability-by-presence idiom.
C17. A MIXED subject works: a plain struct with a Dyn field descends
from static fields into dynamic ones and back, with one path syntax
across the seam.
C18. Arrays are children too, addressed [i], in both worlds.
C19. The capability also carries what static reflection cannot: the
dynamic type states its own leaf presentation and whether it is
expandable, so the row model needs no special case for it.
Run
dub run --single erased-subject.d
property_tree_erased_subject;
import (package) stdstd.(module) std.convA 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
conv : (alias template) property_tree_erased_subject.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_erased_subject.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) stdstd.(module) std.traitsTemplates 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
traits : (alias template) property_tree_erased_subject.isAggregateType = std.traits.isAggregateType(T)Detect whether type T is an aggregate type.
isAggregateType, (alias template) property_tree_erased_subject.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_erased_subject.isAssociativeArray = std.traits.isAssociativeArray(T)Detect whether T is an associative array type
See also: __traits(isAssociativeArray, T)
isAssociativeArray, (alias template) property_tree_erased_subject.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:
// ── the type-erased value (the "JsonValue" position) ─────────────────────────
struct (struct) property_tree_erased_subject.DynDyn
{
enum (enum) property_tree_erased_subject.Dyn.KindKind : ubyte { (enum value) property_tree_erased_subject.Dyn.Kind.nil = cast(ubyte)0unil, (enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1boolean, (enum value) property_tree_erased_subject.Dyn.Kind.number = 2number, (enum value) property_tree_erased_subject.Dyn.Kind.str = 3str, (enum value) property_tree_erased_subject.Dyn.Kind.array = 4array, (enum value) property_tree_erased_subject.Dyn.Kind.object = 5object }
(enum) property_tree_erased_subject.Dyn.KindKind (field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind;
bool (field) bool property_tree_erased_subject.Dyn.bb;
double (field) double property_tree_erased_subject.Dyn.numnum;
(alias) object.string = stringstring (field) string property_tree_erased_subject.Dyn.ss;
(struct) property_tree_erased_subject.DynDyn[] (field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.itemsitems;
(struct) property_tree_erased_subject.Dyn.PairPair[] (field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fieldsfields;
static struct (struct) property_tree_erased_subject.Dyn.PairPair { (alias) object.string = stringstring (field) string property_tree_erased_subject.Dyn.Pair.keykey; (struct) property_tree_erased_subject.DynDyn (field) property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.Pair.valuevalue; }
static (struct) property_tree_erased_subject.DynDyn property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(bool v) @safeof(bool (parameter) bool vv) { (struct) property_tree_erased_subject.DynDyn (local variable) property_tree_erased_subject.Dyn dd; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind = (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1boolean; (local variable) property_tree_erased_subject.Dyn dd.(field) bool property_tree_erased_subject.Dyn.bb = (parameter) bool vv; return (local variable) property_tree_erased_subject.Dyn dd; }
static (struct) property_tree_erased_subject.DynDyn property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safeof(double (parameter) double vv) { (struct) property_tree_erased_subject.DynDyn (local variable) property_tree_erased_subject.Dyn dd; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind = (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.number = 2number; (local variable) property_tree_erased_subject.Dyn dd.(field) double property_tree_erased_subject.Dyn.numnum = (parameter) double vv; return (local variable) property_tree_erased_subject.Dyn dd; }
static (struct) property_tree_erased_subject.DynDyn property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safeof((alias) object.string = stringstring (parameter) string vv) { (struct) property_tree_erased_subject.DynDyn (local variable) property_tree_erased_subject.Dyn dd; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind = (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.str = 3str; (local variable) property_tree_erased_subject.Dyn dd.(field) string property_tree_erased_subject.Dyn.ss = (parameter) string vv; return (local variable) property_tree_erased_subject.Dyn dd; }
static (struct) property_tree_erased_subject.DynDyn property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.arr(property_tree_erased_subject.Dyn[] v) @safearr((struct) property_tree_erased_subject.DynDyn[] (parameter) property_tree_erased_subject.Dyn[] vv) { (struct) property_tree_erased_subject.DynDyn (local variable) property_tree_erased_subject.Dyn dd; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind = (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.array = 4array; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.itemsitems = (parameter) property_tree_erased_subject.Dyn[] vv; return (local variable) property_tree_erased_subject.Dyn dd; }
static (struct) property_tree_erased_subject.DynDyn property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safeobj((struct) property_tree_erased_subject.Dyn.PairPair[] (parameter) property_tree_erased_subject.Dyn.Pair[] vv){ (struct) property_tree_erased_subject.DynDyn (local variable) property_tree_erased_subject.Dyn dd; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind = (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.object = 5object; (local variable) property_tree_erased_subject.Dyn dd.(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fieldsfields = (parameter) property_tree_erased_subject.Dyn.Pair[] vv; return (local variable) property_tree_erased_subject.Dyn dd; }
// ── the capability (C16/C19) ─────────────────────────────────────────────
/// Children, named. `name` is a member name for an object and `null` for
/// an array element (the walk supplies the `[i]` form).
auto property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safeChildren, named. name is a member name for an object and null for
an array element (the walk supplies the [i] form).
propChildren() return
{
static struct (struct) property_tree_erased_subject.Dyn.propChildren.RangeRange
{
(struct) property_tree_erased_subject.DynDyn* (field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.selfself;
int int property_tree_erased_subject.Dyn.propChildren.Range.opApply(scope int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dg) @safeopApply(scope int delegate((alias) object.size_t = ulongsize_t, const(char)[], ref (struct) property_tree_erased_subject.DynDyn) @safe (parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dgdg)
{
if ((field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.selfself.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind == (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.object = 5object)
foreach ((parameter) ulong ii, ref (parameter) property_tree_erased_subject.Dyn.Pair ff; (field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.selfself.(field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fieldsfields)
{
if (auto (local variable) int rr = (parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dgdg((local variable) ulong ii, (local variable) property_tree_erased_subject.Dyn.Pair ff.(field) string property_tree_erased_subject.Dyn.Pair.keykey, (local variable) property_tree_erased_subject.Dyn.Pair ff.(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.Pair.valuevalue)) return (local variable) int rr;
}
else if ((field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.selfself.(field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind == (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.array = 4array)
foreach ((parameter) ulong ii, ref (parameter) property_tree_erased_subject.Dyn vv; (field) property_tree_erased_subject.Dyn* property_tree_erased_subject.Dyn.propChildren.Range.selfself.(field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.itemsitems)
{
if (auto (local variable) int rr = (parameter) int delegate(ulong, const(char)[], ref property_tree_erased_subject.Dyn) @safe dgdg((local variable) ulong ii, null, (local variable) property_tree_erased_subject.Dyn vv)) return (local variable) int rr;
}
return 0;
}
}
return () @trusted { return (struct) property_tree_erased_subject.Dyn.propChildren.RangeRange(&this); }();
}
/// The rest of the capability: is this expandable, and how does it read?
bool bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safeThe rest of the capability: is this expandable, and how does it read?
propExpandable() const pure nothrow @nogc
=> (field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind == (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.object = 5object || (field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind == (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.array = 4array;
(alias) object.string = stringstring string property_tree_erased_subject.Dyn.propText() const pure @safepropText() const pure
{
final switch ((field) property_tree_erased_subject.Dyn.Kind property_tree_erased_subject.Dyn.kindkind)
{
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.nil = cast(ubyte)0unil: return "null";
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.boolean = 1boolean: return (field) bool property_tree_erased_subject.Dyn.bb ? "true" : "false";
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.number = 2number: return (field) double property_tree_erased_subject.Dyn.numnum.string std.conv.to!string.to!(const(double))(const(double) __param_0) pure @safeThe 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.
: 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 = stringstring;
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.str = 3str: return `"` ~ (field) string property_tree_erased_subject.Dyn.ss ~ `"`;
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.array = 4array: return string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text("[", (field) property_tree_erased_subject.Dyn[] property_tree_erased_subject.Dyn.itemsitems.(field) ulong const(property_tree_erased_subject.Dyn[]).lengthlength, " items]");
case (enum) property_tree_erased_subject.Dyn.KindKind.(enum value) property_tree_erased_subject.Dyn.Kind.object = 5object: return string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text("{", (field) property_tree_erased_subject.Dyn.Pair[] property_tree_erased_subject.Dyn.fieldsfields.(field) ulong const(property_tree_erased_subject.Dyn.Pair[]).lengthlength, " keys}");
}
}
}
// ── the one walk ─────────────────────────────────────────────────────────────
struct (struct) property_tree_erased_subject.RowRow { (alias) object.string = stringstring (field) string property_tree_erased_subject.Row.pathpath; (alias) object.string = stringstring (field) string property_tree_erased_subject.Row.labellabel; (alias) object.string = stringstring (field) string property_tree_erased_subject.Row.typetype; (alias) object.string = stringstring (field) string property_tree_erased_subject.Row.valuevalue; bool (field) bool property_tree_erased_subject.Row.expandableexpandable; }
enum bool (constant) bool property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Config) = falsehasPropChildren(T) = __traits(compiles,
(ref (alias) T = property_tree_erased_subject.ConfigT (parameter) property_tree_erased_subject.Config tt) { foreach ((parameter) ii, (parameter) namename, ref (parameter) childchild; (parameter) property_tree_erased_subject.Config tt.property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safeChildren, named. name is a member name for an object and null for
an array element (the walk supplies the [i] form).
propChildren) {} });
void void property_tree_erased_subject.walk!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safewalk(T)(ref (alias) T = property_tree_erased_subject.ConfigT (parameter) property_tree_erased_subject.Config vv, ref (struct) property_tree_erased_subject.RowRow[] (parameter) property_tree_erased_subject.Row[] rowsrows, (alias) object.string = stringstring (parameter) string pathpath, (alias) object.string = stringstring (parameter) string labellabel, int (parameter) int depthdepth,
int (parameter) int maxDepthmaxDepth)
{
static if ((template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Config)hasPropChildren!(alias) T = property_tree_erased_subject.ConfigT) // C16
{
(parameter) property_tree_erased_subject.Row[] rowsrows ~= (struct) property_tree_erased_subject.RowRow((parameter) string pathpath, (parameter) string labellabel, (struct) property_tree_erased_subject.DynT.(constant) string property_tree_erased_subject.Dyn.stringof = "Dyn"stringof, (parameter) property_tree_erased_subject.Dyn vv.string property_tree_erased_subject.Dyn.propText() const pure @safepropText, (parameter) property_tree_erased_subject.Dyn vv.bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safeThe rest of the capability: is this expandable, and how does it read?
propExpandable);
if ((parameter) int depthdepth >= (parameter) int maxDepthmaxDepth || !(parameter) property_tree_erased_subject.Dyn vv.bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safeThe rest of the capability: is this expandable, and how does it read?
propExpandable) return;
foreach ((foreach variable) ulong ii, (foreach variable) const(char)[] namename, ref (foreach variable) property_tree_erased_subject.Dyn childchild; (parameter) property_tree_erased_subject.Dyn vv.property_tree_erased_subject.Dyn.propChildren.Range property_tree_erased_subject.Dyn.propChildren() pure nothrow @nogc return @safeChildren, named. name is a member name for an object and null for
an array element (the walk supplies the [i] form).
propChildren)
{
const (local variable) const(string) pp = (foreach variable) const(char)[] namename is null ? (parameter) string pathpath ~ "[" ~ (foreach variable) ulong ii.string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safeThe 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.
: 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 = stringstring ~ "]"
: ((parameter) string pathpath.(field) ulong string.lengthlength ? (parameter) string pathpath ~ "." ~ (foreach variable) const(char)[] namename.string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup : (foreach variable) const(char)[] namename.string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup);
void property_tree_erased_subject.walk!(property_tree_erased_subject.Dyn)(ref property_tree_erased_subject.Dyn v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safewalk((foreach variable) property_tree_erased_subject.Dyn childchild, (parameter) property_tree_erased_subject.Row[] rowsrows, (local variable) const(string) pp, (foreach variable) const(char)[] namename is null ? "[" ~ (foreach variable) ulong ii.string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safeThe 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.
: 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 = stringstring ~ "]"
: (foreach variable) const(char)[] namename.string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup, (parameter) int depthdepth + 1, (parameter) int maxDepthmaxDepth);
}
}
else static if ((template instance) std.traits.isArray!(property_tree_erased_subject.Config)isArray!(alias) T = property_tree_erased_subject.ConfigT && !(template instance) isSomeString!TisSomeString!(alias) T = string[]T) // C18
{
(parameter) property_tree_erased_subject.Row[] rowsrows ~= (struct) property_tree_erased_subject.RowRow((parameter) string pathpath, (parameter) string labellabel, (darray) string[]T.(constant) string string[].stringof = "string[]"stringof,
string std.conv.text!(string, ulong, string)(string __param_0, ulong __param_1, string __param_2) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text("[", (parameter) string[] vv.(field) ulong string[].lengthlength, " items]"), (parameter) string[] vv.(field) ulong string[].lengthlength > 0);
if ((parameter) int depthdepth >= (parameter) int maxDepthmaxDepth) return;
foreach ((parameter) ulong ii, ref (parameter) string ee; (parameter) string[] vv)
void property_tree_erased_subject.walk!string(ref string v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) pure nothrow @safewalk((local variable) string ee, (parameter) property_tree_erased_subject.Row[] rowsrows, (parameter) string pathpath ~ "[" ~ (local variable) ulong ii.string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safeThe 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.
: 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 = stringstring ~ "]",
"[" ~ (local variable) ulong ii.string std.conv.to!string.to!ulong(ulong __param_0) pure nothrow @safeThe 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.
: 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 = stringstring ~ "]", (parameter) int depthdepth + 1, (parameter) int maxDepthmaxDepth);
}
else static if ((template instance) std.traits.isAggregateType!(property_tree_erased_subject.Config)isAggregateType!(alias) T = property_tree_erased_subject.ConfigT && !(template instance) std.traits.isSomeString!(property_tree_erased_subject.Config)isSomeString!(alias) T = property_tree_erased_subject.ConfigT)
{
(parameter) property_tree_erased_subject.Row[] rowsrows ~= (struct) property_tree_erased_subject.RowRow((parameter) string pathpath, (parameter) string labellabel, (struct) property_tree_erased_subject.ConfigT.(constant) string property_tree_erased_subject.Config.stringof = "Config"stringof, "", true);
if ((parameter) int depthdepth >= (parameter) int maxDepthmaxDepth) return;
static foreach (name; __traits(allMembers, T))
{{
static if (__traits(compiles, typeof(__traits(getMember, T, name)))
&& !is(typeof(__traits(getMember, T, name)) == function))
void property_tree_erased_subject.walk!string(ref string v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) pure nothrow @safewalk(__traits(getMember, v, name), (parameter) property_tree_erased_subject.Row[] rowsrows,
(parameter) string pathpath.(field) ulong string.lengthlength ? (parameter) string pathpath ~ "." ~ name : (constant) string property_tree_erased_subject.walk!(property_tree_erased_subject.Config).name = "name"name, (constant) string property_tree_erased_subject.walk!(property_tree_erased_subject.Config).name = "name"name,
(parameter) int depthdepth + 1, (parameter) int maxDepthmaxDepth);
}}
}
else
(parameter) property_tree_erased_subject.Row[] rowsrows ~= (struct) property_tree_erased_subject.RowRow((parameter) string pathpath, (parameter) string labellabel, (ushort) ushortT.(constant) string ushort.stringof = "ushort"stringof, string std.conv.text!ushort(ushort __param_0) pure nothrow @safeConvenience functions for converting one or more arguments
of any type into text (the three character widths).
text((parameter) ushort vv), false);
}
(struct) property_tree_erased_subject.RowRow[] property_tree_erased_subject.Row[] property_tree_erased_subject.rowsOf!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, int maxDepth = 8) @saferowsOf(T)(ref (alias) T = property_tree_erased_subject.ConfigT (parameter) property_tree_erased_subject.Config vv, int (parameter) int maxDepthmaxDepth = 8)
{
(struct) property_tree_erased_subject.RowRow[] (local variable) property_tree_erased_subject.Row[] rowsrows;
void property_tree_erased_subject.walk!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, ref property_tree_erased_subject.Row[] rows, string path, string label, int depth, int maxDepth) @safewalk((parameter) property_tree_erased_subject.Config vv, (local variable) property_tree_erased_subject.Row[] rowsrows, "", "(root)", 0, (parameter) int maxDepthmaxDepth);
return (local variable) property_tree_erased_subject.Row[] rowsrows;
}
// ── a MIXED subject (C17) ────────────────────────────────────────────────────
struct (struct) property_tree_erased_subject.ServerServer { (alias) object.string = stringstring (field) string property_tree_erased_subject.Server.hosthost = "localhost"; ushort (field) ushort property_tree_erased_subject.Server.portport = 8080; }
struct (struct) property_tree_erased_subject.ConfigConfig
{
(alias) object.string = stringstring (field) string property_tree_erased_subject.Config.namename = "demo";
(struct) property_tree_erased_subject.ServerServer (field) property_tree_erased_subject.Server property_tree_erased_subject.Config.serverserver;
(alias) object.string = stringstring[] (field) string[] property_tree_erased_subject.Config.tagstags;
(struct) property_tree_erased_subject.DynDyn (field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extraextra; // ← the erased hole in an otherwise static type
}
void void D main() @safemain()
{
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) 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_erased_subject.ConfigConfig (local variable) property_tree_erased_subject.Config cc;
(local variable) property_tree_erased_subject.Config cc.(field) string[] property_tree_erased_subject.Config.tagstags = ["a", "b"];
(local variable) property_tree_erased_subject.Config cc.(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extraextra = (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safeobj([
(struct) property_tree_erased_subject.DynDyn.(struct) property_tree_erased_subject.Dyn.PairPair("retries", (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safeof(3.0)),
(struct) property_tree_erased_subject.DynDyn.(struct) property_tree_erased_subject.Dyn.PairPair("hosts", (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.arr(property_tree_erased_subject.Dyn[] v) @safearr([(struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safeof("h1"), (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(string v) @safeof("h2")])),
(struct) property_tree_erased_subject.DynDyn.(struct) property_tree_erased_subject.Dyn.PairPair("tls", (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.obj(property_tree_erased_subject.Dyn.Pair[] v) @safeobj([(struct) property_tree_erased_subject.DynDyn.(struct) property_tree_erased_subject.Dyn.PairPair("verify", (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(bool v) @safeof(true))])),
]);
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("C16/C17/C18 — one walk over a subject that is half static,");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("half type-erased. Nothing in the walk knows which is which.\n");
foreach ((parameter) property_tree_erased_subject.Row rr; property_tree_erased_subject.Row[] property_tree_erased_subject.rowsOf!(property_tree_erased_subject.Config)(ref property_tree_erased_subject.Config v, int maxDepth = 8) @saferowsOf((local variable) property_tree_erased_subject.Config cc))
{
int (local variable) int depthdepth;
foreach ((parameter) immutable(char) chch; (local variable) property_tree_erased_subject.Row rr.(field) string property_tree_erased_subject.Row.pathpath) if ((local variable) immutable(char) chch == '.' || (local variable) immutable(char) chch == '[') (local variable) int depthdepth++;
void std.stdio.writefln!(char, int, string, string, string, string, string)(in char[] fmt, int __param_1, string __param_2, string __param_3, string __param_4, string __param_5, string __param_6) @safeEquivalent to writef(fmt, args, '\n').
writefln("%*s%-10s %-12s %-22s %s", (local variable) int depthdepth * 2, "",
(local variable) property_tree_erased_subject.Row rr.(field) string property_tree_erased_subject.Row.labellabel, (local variable) property_tree_erased_subject.Row rr.(field) bool property_tree_erased_subject.Row.expandableexpandable ? "▾" : " ", (local variable) property_tree_erased_subject.Row rr.(field) string property_tree_erased_subject.Row.typetype, (local variable) property_tree_erased_subject.Row rr.(field) string property_tree_erased_subject.Row.valuevalue);
}
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("\n paths across the seam are one syntax:");
foreach ((parameter) string pp; ["server.port", "tags[1]", "extra.retries",
"extra.hosts[0]", "extra.tls.verify"])
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %s", (local variable) string pp);
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("\nC19 — the dynamic type states its own expandability, so the row");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln(" model has no case for it:");
void std.stdio.writefln!(char, bool, bool)(in char[] fmt, bool __param_1, bool __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" Dyn(object).propExpandable = %s, Dyn(number) = %s",
(local variable) property_tree_erased_subject.Config cc.(field) property_tree_erased_subject.Dyn property_tree_erased_subject.Config.extraextra.bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safeThe rest of the capability: is this expandable, and how does it read?
propExpandable, (struct) property_tree_erased_subject.DynDyn.property_tree_erased_subject.Dyn property_tree_erased_subject.Dyn.of(double v) @safeof(1.0).bool property_tree_erased_subject.Dyn.propExpandable() const pure nothrow @nogc @safeThe rest of the capability: is this expandable, and how does it read?
propExpandable);
void std.stdio.writefln!(char, bool, bool)(in char[] fmt, bool __param_1, bool __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" hasPropChildren!Dyn = %s, hasPropChildren!Server = %s",
(template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Dyn)hasPropChildren!(struct) property_tree_erased_subject.DynDyn, (template instance) property_tree_erased_subject.hasPropChildren!(property_tree_erased_subject.Server)hasPropChildren!(struct) property_tree_erased_subject.ServerServer);
}