I'm doing some work with a REST API, and I wrote a simple utility function that sets an HTTP's onSend callback to send a string:

@property outgoingString(ref HTTP request, const(void)[] sendData)
{
        import std.algorithm : min;

        request.contentLength = sendData.length;
        auto remainingData = sendData;
        request.onSend = delegate size_t(void[] buf)
        {
                size_t minLen = min(buf.length, remainingData.length);
                if (minLen == 0) return 0;
                buf[0..minLen] = remainingData[0..minLen];
                remainingData = remainingData[minLen..$];
                return minLen;
        };
}

I then wrote a function that lazily strips some whitespace from strings I send. To accommodate this change, I need to modify the function above so it takes arbitrary ranges of char elements. I assumed this would be a modest task, but it's been an exercise in frustration. The closest I got was:

@property void outgoingString(T)(ref HTTP request, T sendData)
        if (isInputRange!T) // #1
{
        static if (isArray!T) {
                import std.algorithm : min;

                request.contentLength = sendData.length;
                request.onSend = delegate size_t(void[] buf)
                {
                        size_t minLen = min(buf.length, sendData.length);
                        if (minLen == 0) return 0;
                        buf[0..minLen] = sendData[0..minLen]; // #2
                        sendData = sendData[minLen..$];
                        return minLen;
                };
        }
        else {
                auto bcu = byCodeUnit(sendData); // #3

                static assert(is(ElementType!bcu : char), // #4
                              __FUNCTION__ ~ " only takes char ranges, not "
                      ~ typeof(bcu.front).stringof);

        // Length unknown; chunked transfer
                request.contentLength = ulong.max;
                request.onSend = delegate size_t(void[] buf)
                {
                        for (size_t i = 0; i < buf.length; ++i) {
                                if (bcu.empty) return i;
                                buf[i] = bcu.front; // #5
                                bcu.popFront();
                        }
            return buf.length;
                };
        }
}

To each of the commented lines above,

1. What is the idiomatic way to constrain the function to only take char ranges? One might naïvely add `is(ElementType!T : char)`, but that falls on its face due to strings "auto-decoding" their elements to dchar. (More on that later.)

2. The function fails to compile, issuing, "cannot implicitly convert expression (sendData[0..minLen]) of type string to void[]" on this line. I assume this has to do with the immutability of string elements. Specifying a non-const array of const elements is as simple as `const(void)[]`, but how does one do this here, with a template argument?

3. Is this needed, or is auto-decoding behavior specific to char arrays and not other char ranges?

4. Is this a sane approach to make sure I'm dealing with ranges of chars? Do I need to use `Unqual` to deal with const or immutable elements?

5. This fails, claiming the right hand side can't be converted to type void. Casting to ubyte doesn't help - so how *does* one write to an element of a void array?

Am I making things harder than they have to be? Or is dealing with an arbitrary ranges of chars this complex? I've lost count of times templated code wouldn't compile because dchar was sneaking in somewhere... at least I'm in good company. (http://forum.dlang.org/post/m01r3d$1frl$1...@digitalmars.com)

Reply via email to