-
Notifications
You must be signed in to change notification settings - Fork 181
/
Copy pathIOExtras.jl
119 lines (93 loc) · 2.58 KB
/
IOExtras.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
"""
IOExtras
This module defines extensions to the `Base.IO` interface to support:
- `startwrite`, `closewrite`, `startread` and `closeread` for streams
with transactional semantics.
"""
module IOExtras
using ..Sockets
using MbedTLS: MbedException
export bytes, ByteView, nobytes, CodeUnits, IOError, isioerror,
startwrite, closewrite, startread, closeread,
tcpsocket, localport, safe_getpeername
"""
bytes(s::String)
Get a `Vector{UInt8}`, a vector of bytes of a string.
"""
function bytes end
bytes(s::SubArray{UInt8}) = unsafe_wrap(Array, pointer(s), length(s))
const CodeUnits = Union{Vector{UInt8}, Base.CodeUnits}
bytes(s::Base.CodeUnits) = bytes(String(s))
bytes(s::String) = codeunits(s)
bytes(s::SubString{String}) = codeunits(s)
bytes(s::Vector{UInt8}) = s
"""
isioerror(exception)
Is `exception` caused by a possibly recoverable IO error.
"""
isioerror(e) = false
isioerror(::Base.EOFError) = true
isioerror(::Base.IOError) = true
isioerror(e::ArgumentError) = e.msg == "stream is closed or unusable"
isioerror(::MbedException) = true
"""
IOError <: Exception
The request terminated with due to an IO-related error.
Fields:
- `e`, the error.
"""
struct IOError <: Exception
e
message
end
Base.show(io::IO, e::IOError) = print(io, "IOError(", e.e, " ", e.message, ")\n")
_doc = """
startwrite(::IO)
closewrite(::IO)
startread(::IO)
closeread(::IO)
Signal start/end of write or read operations.
"""
"$_doc"
startwrite(io) = nothing
"$_doc"
closewrite(io) = nothing
"$_doc"
startread(io) = nothing
"$_doc"
closeread(io) = nothing
using MbedTLS: SSLContext
tcpsocket(io::SSLContext)::TCPSocket = io.bio
tcpsocket(io::TCPSocket)::TCPSocket = io
localport(io) = try !isopen(tcpsocket(io)) ? 0 :
Sockets.getsockname(tcpsocket(io))[2]
catch
0
end
function safe_getpeername(io)
try
if isopen(tcpsocket(io))
return Sockets.getpeername(tcpsocket(io))
end
catch
end
return IPv4(0), UInt16(0)
end
const ByteView = typeof(view(UInt8[], 1:0))
const nobytes = view(UInt8[], 1:0)
"""
Read from an `IO` stream until `find_delimiter(bytes)` returns non-zero.
Return view of bytes up to the delimiter.
"""
function Base.readuntil(buf::IOBuffer,
find_delimiter::Function #= Vector{UInt8} -> Int =#
)::ByteView
l = find_delimiter(view(buf.data, buf.ptr:buf.size))
if l == 0
return nobytes
end
bytes = view(buf.data, buf.ptr:buf.ptr + l - 1)
buf.ptr += l
return bytes
end
end