Skip to content

Commit 82f686d

Browse files
committed
add contents
1 parent 9fc4d15 commit 82f686d

File tree

8 files changed

+478
-4
lines changed

8 files changed

+478
-4
lines changed

REQUIRE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
julia 0.5
1+
julia 0.6.0-rc1

src/TranscodingStreams.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
module TranscodingStreams
22

3-
# package code goes here
3+
export TranscodingStream
4+
5+
include("codec.jl")
6+
include("state.jl")
7+
include("stream.jl")
8+
include("io.jl")
9+
include("identity.jl")
410

511
end # module

src/codec.jl

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Codec Interfaces
2+
# ================
3+
4+
abstract type Codec end
5+
6+
abstract type Mode end
7+
struct ReadMode <: Mode end
8+
struct WriteMode <: Mode end
9+
10+
primitive type ProcCode 8 end
11+
const PROC_INIT = reinterpret(ProcCode, 0x00)
12+
const PROC_OK = reinterpret(ProcCode, 0x01)
13+
const PROC_FINISH = reinterpret(ProcCode, 0x02)
14+
15+
16+
# Start
17+
# -----
18+
19+
"""
20+
start(::Type{ReadMode}, codec::Codec, source::IO)::Void
21+
22+
Start transcoding using `codec` with read mode.
23+
24+
This method will be called only once before calling `process` first time.
25+
26+
Implementing this method is optional; there is a default method that does nothing.
27+
"""
28+
function start(::Type{ReadMode}, ::Codec, ::IO)
29+
return nothing
30+
end
31+
32+
"""
33+
start(::Type{WriteMode}, codec::Codec, sink::IO)::Void
34+
35+
Start transcoding using `codec` with write mode.
36+
37+
This method will be called only once before calling `process` first time.
38+
39+
Implementing this method is optional; there is a default method that does nothing.
40+
"""
41+
function start(::Type{WriteMode}, ::Codec, ::IO)
42+
return nothing
43+
end
44+
45+
46+
# Process
47+
# -------
48+
49+
"""
50+
process(::Type{ReadMode}, codec::Codec, source::IO, output::Ptr{UInt8}, nbytes::Int)::Tuple{Int,ProcCode}
51+
52+
Transcode data using `codec` with read mode.
53+
54+
<> >-----(process)-----> [........]
55+
source codec output
56+
57+
This method reads some data from `source` and write the transcoded data to
58+
`output` at most `nbytes`, and then returns the number of written bytes and an
59+
appropriate return code. It will be called repeatedly to incrementally
60+
transcode input data from `source`. It can assume `output` points to a valid
61+
memory position and `nbytes` are positive. The intermediate result of
62+
transcoding is indicated by the return value of it. If processing works
63+
properly and there are still data to write, it must return the number of written
64+
bytes and `PROC_OK`. If processing finishes and there are no remaining data to
65+
write, it must return the number of written bytes and `PROC_FINISH`. Therefore,
66+
after finishing reading data from `source` and all (possibly buffered) data are
67+
written to `output`, it is expected to return `(0, PROC_FINISH)` forever.
68+
69+
This method may throw an exception when transcoding fails. For example, when
70+
`codec` is a decompression algorithm, it may throw an exception if it reads
71+
malfomed data from `source`. However, this method must not throw `EOFError`
72+
when reading data from `source`. Also note that it is responsible for this
73+
method to release resources allocated by `codec` when an exception happens.
74+
"""
75+
function process(::Type{ReadMode}, codec::Codec, stream::IO, data::Ptr{UInt8}, nbytes::Int)
76+
error("codec $(codec) does not implement read mode")
77+
end
78+
79+
"""
80+
process(::Type{WriteMode}, codec::Codec, sink::IO, input::Ptr{UInt8}, nbytes::Int)::Tuple{Int,ProcCode}
81+
82+
Transcode data using `codec` with write mode.
83+
84+
<> <-----(transcode)-----< [.......]
85+
sink codec input
86+
87+
This method reads some data from `input` and write the transcoded bytes to `sink`.
88+
"""
89+
function process(::Type{WriteMode}, codec::Codec, stream::IO, data::Ptr{UInt8}, nbytes::Int)
90+
error("codec $(codec) does not implement write mode")
91+
end
92+
93+
94+
# Finish
95+
# ------
96+
97+
"""
98+
finish(::Type{ReadMode}, codec::Codec, source::IO)::Void
99+
100+
Finish transcoding using `codec` with read mode.
101+
102+
This method will be called only once after calling `process` last time.
103+
104+
Implementing this method is optional; there is a default method that does nothing.
105+
"""
106+
function finish(::Type{ReadMode}, ::Codec, ::IO)
107+
return nothing
108+
end
109+
110+
"""
111+
finish(::Type{WriteMode}, codec::Codec, sink::IO)::Void
112+
113+
Finish transcoding using `codec` with write mode.
114+
115+
This method will be called only once after calling `process` last time.
116+
117+
Implementing this method is optional; there is a default method that does nothing.
118+
"""
119+
function finish(::Type{WriteMode}, ::Codec, ::IO)
120+
return nothing
121+
end

src/identity.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Identity Codec
2+
# ==============
3+
4+
struct Identity <: Codec end
5+
6+
function process(::Type{ReadMode}, ::Identity, stream::IO, data::Ptr{UInt8}, nbytes::Int)::Tuple{Int,ProcCode}
7+
n = unsafe_read(stream, data, nbytes)
8+
if eof(stream)
9+
return n, PROC_FINISH
10+
else
11+
return n, PROC_OK
12+
end
13+
end
14+
15+
function process(::Type{WriteMode}, ::Identity, stream::IO, data::Ptr{UInt8}, nbytes::Int)::Tuple{Int,ProcCode}
16+
n = unsafe_write(stream, data, nbytes)
17+
return Int(n), PROC_OK
18+
end

src/io.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function unsafe_read(stream::IO, ptr::Ptr{UInt8}, nbytes::Int)::Int
2+
nread = 0
3+
navail = nb_available(stream)
4+
if navail == 0 && nbytes > 0 && !eof(stream)
5+
b = read(stream, UInt8)
6+
unsafe_store!(ptr, b)
7+
ptr += 1
8+
nbytes -= 1
9+
nread += 1
10+
navail = nb_available(stream)
11+
end
12+
n = min(navail, nbytes)
13+
Base.unsafe_read(stream, ptr, n)
14+
nread += n
15+
return nread
16+
end

src/state.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Transcoding State
2+
# =================
3+
4+
mutable struct State
5+
# current mode (:init, :read, :write, or :closed)
6+
mode::Symbol
7+
8+
# buffered data
9+
data::Vector{UInt8}
10+
11+
# the starting position of the buffered data
12+
position::Int
13+
14+
# the ending position + 1 of the buffered data
15+
fposition::Int
16+
17+
# the last return code of `process`
18+
proc::ProcCode
19+
20+
function State(size::Integer)
21+
@assert size > 0
22+
return new(:init, Vector{UInt8}(size), 1, 1, PROC_INIT)
23+
end
24+
end
25+
26+
function bufferptr(state::State)
27+
return pointer(state.data, state.position)
28+
end
29+
30+
function buffersize(state::State)
31+
return state.fposition - state.position
32+
end
33+
34+
function isemptybuf(state::State)
35+
return buffersize(state) == 0
36+
end
37+
38+
function marginptr(state::State)
39+
return pointer(state.data, state.fposition)
40+
end
41+
42+
function marginsize(state::State)
43+
return endof(state.data) - state.fposition + 1
44+
end
45+
46+
function isfullbuf(state::State)
47+
return marginsize(state) == 0
48+
end
49+
50+
function makemargin!(state::State, minsize::Int)::Int
51+
if buffersize(state) == 0
52+
state.position = state.fposition = 1
53+
end
54+
if marginsize(state) < minsize && state.position > 0
55+
bufsize = buffersize(state)
56+
copy!(state.data, 1, state.data, state.position, bufsize)
57+
state.position = 1
58+
state.fposition = 1 + bufsize
59+
end
60+
if marginsize(state) < minsize
61+
resize!(state.data, state.fposition + minsize - 1)
62+
end
63+
@assert marginsize(state) minsize
64+
return marginsize(state)
65+
end

0 commit comments

Comments
 (0)