iopipe: Writing output to std.io File
Steven Schveighoffer
schveiguy at gmail.com
Mon Jan 27 18:12:40 UTC 2020
On 1/26/20 11:59 PM, Jesse Phillips wrote:
> On Monday, 27 January 2020 at 01:50:00 UTC, Jesse Phillips wrote:
>> Just as I'm hitting send the part I'm missing clicked:
>>
>> I needed to add the text encoding because my buffer is `char` but File
>> writes `ubyte`
>>
>> ```dlang
>> auto output() {
>> return std.io.File("somefile.txt", mode!"w").refCounted;
>> }
>> auto outputBuffered = bufd!char
>> .encodeText // Missing This part
>> .outputPipe(output());
>> }
>> ```
>
> Unfortunately this did not write a text file as I expected.
This is because output is buffered differently from input. With output
you are writing to the buffer, then flushing the result as needed. But I
constructed iopipe to be able to utilize all mechanisms as both input
and output.
Before I show you what to do, let me explain what the above actually does.
1. You constructed a buffer of characters. Good, this is the first step.
2. You used encodeText to convert the data to ubyte. Note that for char
buffer, this basically is just a cast. Other encodings might do
byteswapping. But you have done this step a bit early. At this point
now, the window type is ubyte[]. You want to put data into the buffer as
char[].
3. You appended an outputPipe, which is a pass through while writing the
data to a file (which is fed a stream of uninitialized data I think, so
you probably got a file with garbage in it). Writing to this pipe's
buffer is kind of pointless because the writing has already happened
(pretty much all effects and actions performed on the buffer happen in
the .extend function).
What you need is to access the buffer for writing BEFORE encoding and
streaming to the file. For this, you need the push [1] mechanism, which
wraps up everything you want to happen to data you have written to the
buffer into a lambda template:
auto outputBuffered = bufd!char
.push!(p => p
.encodeText
.outputPipe(output()));
now, you write to the outputBuffered "buffer" as needed. releasing any
data that is ready to go. As soon as it needs more buffer space and
there is pending data, it will write the data, giving you back the
buffer space. It also auto-flushes on the last reference destructor
(this behavior is configurable).
A simple writeln on such a pipe would look like:
void writeln(Pipe)(ref Pipe sink, string text)
{
enforce(sink.ensureElems(text.size) >= text.length); // make sure
there's enough buffer space to hold the text
sink[0 .. text.length] = text; // write to the buffer
sink.release(text.length); // release to be written
}
I really need to do an article on iopipe. I've been neglecting that...
-Steve
[1] http://schveiguy.github.io/iopipe/iopipe/valve/push.html
More information about the Digitalmars-d-learn
mailing list