I want to make a type that wraps an IO
stream and measures how much data is read through (or written to) it. Something like this:
mutable struct MeasuredStream <: IO
io::IO
nread::Int
nwritten::Int
MeasuredStream(io) = new(io, 0, 0)
end
function Base.read(s::MeasuredStream, nb=typemax(Int))
x = read(s.io, nb)
s.nread += length(x)
return x
end
function Base.write(s::MeasuredStream, x)
n = write(s.io, x)
s.nwritten += n
return n
end
to be used like this:
function compress_stream(input_stream, output_file)
pipeline(input_stream, `gzip`, output_file) |> run
end
data = IOBuffer(repeat("hello", 1000));
stream = MeasuredStream(data)
compress_stream(stream, "hellos.gz")
print("Input size: $(stream.nread)")
However this fails for a (to me) obscure reason:
ERROR: MethodError: no method matching rawhandle(::MeasuredStream)
Closest candidates are:
rawhandle(::RawFD) at cmd.jl:161
rawhandle(::Base.DevNull) at cmd.jl:160
rawhandle(::Base.Filesystem.File) at filesystem.jl:75
...
Stacktrace:
[1] _spawn_primitive(::String, ::Cmd, ::Array{Any,1}) at ./process.jl:77
[2] #585 at ./process.jl:112 [inlined]
[3] setup_stdios(::Base.var"#585#586"{Cmd}, ::Array{Any,1}) at ./process.jl:196
[4] _spawn at ./process.jl:111 [inlined]
[5] _spawn(::Base.CmdRedirect, ::Array{Any,1}) at ./process.jl:139 (repeats 2 times)
[6] run(::Base.CmdRedirect; wait::Bool) at ./process.jl:439
[7] run at ./process.jl:438 [inlined]
[8] |> at ./operators.jl:834 [inlined]
[9] compress_stream(::MeasuredStream, ::String) at ./REPL[4]:2
I tried forwarding rawhandle
without success:
julia> Base.rawhandle(s::MeasuredStream) = Base.rawhandle(s.io)
julia> compress_stream(stream, "hellos.gz")
ERROR: MethodError: no method matching rawhandle(::Base.GenericIOBuffer{Array{UInt8,1}})
I guess I need to implement a bunch of IO
methods but my random trials failed and I couldn’t find any guidance.
How can I properly wrap an IO stream to add custom functionality?