I am trying to define custom format specifiers (as described here [1]) for the following wrapper struct :

import std.stdio;
import std.format: formattedWrite, FormatSpec;
import std.string: format;

struct wrapper(T) {

        private T val;

        public this(T newVal) pure { val = newVal; }

        public void toString(
                scope void delegate(const(char)[]) sink,
                FormatSpec!char fmt
        ) const
        {
                formattedWrite(sink, /+ Format string +/ , val);
        }
}

unittest {

        immutable uint base = 16;
        auto a = wrapper!uint(base);
        assert(format("%x", a) == format("%x", base));
        assert(format("%08x", a) == format("%08x", base));
}

More precisely, I want to forward the format specifier fmt received by wrapper!T.toString to formattedWrite.

Since formattedWrite expects a const(char)[] "string" as its second argument, I first naively tried to use :

        formattedWrite(sink, to!string(fmt), val);

but to!string(fmt) gives something similar to :
        
        address = 7FFFE91C54C0
        width = 0
        precision = 2147483646
        spec = x
        indexStart = 0
        indexEnd = 0
        flDash = false
        flZero = false
        flSpace = false
        flPlus = false
        flHash = false
        nested =
        trailing =

instead of the original format string, thus causing toString to fail at runtime.

The documentation for std.format [2] mentions a second prototype (among four) for toString :

        const void toString(
                scope void delegate(const(char)[]) sink,
                string fmt
        );

So I tried to modify wrapper!T.toString as follows :

        public void toString(
                scope void delegate(const(char)[]) sink,
                string fmt
        ) const
        {
                formattedWrite(sink, fmt, val);
        }

but this one throws exception at runtime :

std.format.FormatException@/usr/include/dlang/dmd/std/format.d(2537): Expected '%s' format specifier for type 'wrapper!uint'.

I can make it work for simple cases by manually creating the format string using format() with the FormatSpec attributes, but this approach is not generic and will fail for complex format strings.

I've certainly missed something, but I can't figure out what is the right way to do it. What did I do wrong here ?

I remember having seen the "void toString(scope void delegate(/*...*/), /*...*/) const" prototypes being deprecated, but I don't know where it was. Maybe there is a better solution now ?


[1] http://wiki.dlang.org/Defining_custom_print_format_specifiers
[2] http://dlang.org/phobos-prerelease/std_format.html#.formatValue

Reply via email to