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