1 package frost.io
2
3 ====================================================================================================
4 An input stream which allows data to be "pushed back" into it, so that it may be read again. This is
5 useful in situations such as parsing, in which you may wish to read until you encounter a delimiter
6 and then push the delimiter back into the stream so that it can be handled by other code.
7
8 The `PushbackInputStream` "sits on top of" another stream, reading from it when it requires new
9 data. You should not read directly from the underlying stream while reading from a
10 `PushbackInputStream`. Closing the `PushbackInputStream` *does not* directly close the underlying
11 stream, but if the `PushbackInputStream` holds the only remaining reference to the underlying
12 stream, then discarding the `PushbackInputStream` will cause the underlying stream to likewise be
13 discarded and thus closed.
14 ====================================================================================================
15 class PushbackInputStream : InputStream {
16 @private
17 def source:InputStream
18
19 @private
20 def pushbackBuffer := Array<UInt8>()
21
22 ================================================================================================
23 Creates a new `PushbackInputStream`.
24
25 @param raw the underlying stream
26 ================================================================================================
27 init(source:InputStream) {
28 self.source := source
29 super.init()
30 }
31
32 @override
33 method read():UInt8? {
34 if pushbackBuffer.count > 0 {
35 def result := pushbackBuffer[pushbackBuffer.count - 1]
36 pushbackBuffer.removeIndex(pushbackBuffer.count - 1)
37 return result
38 }
39 return source.read()
40 }
41
42 ============================================================================
43 Pushes back a single `UInt8`, so that it will be the next byte read by the
44 stream.
45
46 @param v the `UInt8` to push
47 ============================================================================
48 method pushback(v:UInt8) {
49 pushbackBuffer.add(v)
50 }
51
52 ============================================================================
53 Pushes back a single `Int8`, so that it will be the next byte read by the
54 stream.
55
56 @param v the `Int8` to push
57 ============================================================================
58 method pushback(v:Int8) {
59 pushbackBuffer.add(v.asUInt8)
60 }
61
62 ============================================================================
63 Pushes back a list of `UInt8`s.
64
65 @param v the array to push
66 ============================================================================
67 method pushback(v:ListView<UInt8>) {
68 for i in v.count - 1 ... 0 by -1 {
69 pushback(v[i])
70 }
71 }
72
73 ============================================================================
74 Pushes back a list of `Int8`s.
75
76 @param v the array to push
77 ============================================================================
78 method pushback(v:ListView<Int8>) {
79 for i in v.count - 1 ... 0 by -1 {
80 pushback(v[i])
81 }
82 }
83
84 ============================================================================
85 Pushes back a single `Char8`.
86
87 @param c the character to push
88 ============================================================================
89 method pushback(c:Char8) {
90 pushback(c.asUInt8)
91 }
92
93 ============================================================================
94 Pushes back a list of `Char`s.
95
96 @param c the array to push
97 ============================================================================
98 method pushback(c:ListView<Char8>) {
99 for i in c.count - 1 ... 0 by -1 {
100 pushback(c[i])
101 }
102 }
103
104 ============================================================================
105 Pushes back a `String`.
106
107 @param s the string to push
108 ============================================================================
109 method pushback(s:String) {
110 pushback(s.utf8)
111 }
112 }