1
1
/// Memory buffers for the benefit of `std::rt::io::net` which has slow read/write.
2
2
3
- use std:: rt:: io:: { Reader , Writer } ;
3
+ use std:: rt:: io:: { Reader , Writer , Stream } ;
4
+ use std:: rt:: io:: net:: tcp:: TcpStream ;
4
5
use std:: cast:: transmute_mut;
5
6
use std:: cmp:: min;
6
7
use std:: ptr;
7
8
9
+ pub type BufTcpStream = BufferedStream < TcpStream > ;
10
+
8
11
// 64KB chunks (moderately arbitrary)
9
12
static READ_BUF_SIZE : uint = 0x10000 ;
10
13
static WRITE_BUF_SIZE : uint = 0x10000 ;
11
14
// TODO: consider removing constants and giving a buffer size in the constructor
12
15
13
- struct BufferedReader < ' self , T > {
14
- wrapped : & ' self mut T ,
15
- buffer : [ u8 , ..READ_BUF_SIZE ] ,
16
+ struct BufferedStream < T > {
17
+ wrapped : T ,
18
+ read_buffer : [ u8 , ..READ_BUF_SIZE ] ,
16
19
// The current position in the buffer
17
- pos : uint ,
20
+ read_pos : uint ,
18
21
// The last valid position in the reader
19
- max : uint ,
22
+ read_max : uint ,
23
+ write_buffer : [ u8 , ..WRITE_BUF_SIZE ] ,
24
+ write_len : uint ,
25
+
26
+ /// Some things being written may not like flush() being called yet (e.g. explicitly fail!())
27
+ /// The BufferedReader may need to be flushed for good control, but let it provide for such
28
+ /// cases by not calling the wrapped object's flush method in turn.
29
+ call_wrapped_flush : bool ,
20
30
}
21
31
22
- impl < ' self , T : Reader > BufferedReader < ' self , T > {
23
- pub fn new < ' a > ( reader : & ' a mut T /*, buffer_size: uint*/ ) -> BufferedReader < ' a , T > {
24
- BufferedReader {
25
- wrapped : reader,
26
- buffer : [ 0u8 , ..READ_BUF_SIZE ] , //[0u8, ..buffer_size],
27
- pos : 0 u,
28
- max : 0 u,
32
+ impl < T : Reader + Writer /*Stream*/ > BufferedStream < T > {
33
+ pub fn new ( stream : T , call_wrapped_flush : bool ) -> BufferedStream < T > {
34
+ BufferedStream {
35
+ wrapped : stream,
36
+ read_buffer : [ 0u8 , ..READ_BUF_SIZE ] ,
37
+ read_pos : 0 u,
38
+ read_max : 0 u,
39
+ write_buffer : [ 0u8 , ..WRITE_BUF_SIZE ] ,
40
+ write_len : 0 u,
41
+ call_wrapped_flush : call_wrapped_flush,
29
42
}
30
43
}
44
+ }
45
+
46
+ impl < T : Stream > Stream for BufferedStream < T > ;
31
47
48
+ impl < T : Reader > BufferedStream < T > {
32
49
/// Poke a single byte back so it will be read next. For this to make sense, you must have just
33
50
/// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
34
51
/// filled
35
52
/// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
36
53
pub fn poke_byte ( & mut self , byte : u8 ) {
37
- match ( self . pos , self . max ) {
38
- ( 0 , 0 ) => self . max = 1 ,
54
+ match ( self . read_pos , self . read_max ) {
55
+ ( 0 , 0 ) => self . read_max = 1 ,
39
56
( 0 , _) => fail ! ( "poke called when buffer is full" ) ,
40
- ( _, _) => self . pos -= 1 ,
57
+ ( _, _) => self . read_pos -= 1 ,
41
58
}
42
- self . buffer [ self . pos ] = byte;
59
+ self . read_buffer [ self . read_pos ] = byte;
43
60
}
44
61
45
62
#[ inline]
46
63
fn fill_buffer ( & mut self ) -> bool {
47
- assert_eq ! ( self . pos , self . max ) ;
48
- match self . wrapped . read ( self . buffer ) {
64
+ assert_eq ! ( self . read_pos , self . read_max ) ;
65
+ match self . wrapped . read ( self . read_buffer ) {
49
66
None => {
50
- self . pos = 0 ;
51
- self . max = 0 ;
67
+ self . read_pos = 0 ;
68
+ self . read_max = 0 ;
52
69
false
53
70
} ,
54
71
Some ( i) => {
55
- self . pos = 0 ;
56
- self . max = i;
72
+ self . read_pos = 0 ;
73
+ self . read_max = i;
57
74
true
58
75
} ,
59
76
}
@@ -63,69 +80,46 @@ impl<'self, T: Reader> BufferedReader<'self, T> {
63
80
/// (which just uses `read()`)
64
81
#[ inline]
65
82
pub fn read_byte ( & mut self ) -> Option < u8 > {
66
- if self . pos == self . max && !self . fill_buffer ( ) {
83
+ if self . read_pos == self . read_max && !self . fill_buffer ( ) {
67
84
// Run out of buffered content, no more to come
68
85
return None ;
69
86
}
70
- self . pos += 1 ;
71
- Some ( self . buffer [ self . pos - 1 ] )
87
+ self . read_pos += 1 ;
88
+ Some ( self . read_buffer [ self . read_pos - 1 ] )
72
89
}
73
90
}
74
91
75
- impl < ' self , T : Reader > Reader for ~ BufferedReader < ' self , T > {
92
+ impl < T : Reader > Reader for BufferedStream < T > {
76
93
/// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
77
94
///
78
95
/// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
79
96
/// ask.
80
97
fn read ( & mut self , buf : & mut [ u8 ] ) -> Option < uint > {
81
- if self . pos == self . max && !self . fill_buffer ( ) {
98
+ if self . read_pos == self . read_max && !self . fill_buffer ( ) {
82
99
// Run out of buffered content, no more to come
83
100
return None ;
84
101
}
85
- let size = min ( self . max - self . pos , buf. len ( ) ) ;
102
+ let size = min ( self . read_max - self . read_pos , buf. len ( ) ) ;
86
103
unsafe {
87
104
do buf. as_mut_buf |p_dst, _len_dst| {
88
- do self . buffer . as_imm_buf |p_src, _len_src| {
105
+ do self . read_buffer . as_imm_buf |p_src, _len_src| {
89
106
// Note that copy_memory works on bytes; good, u8 is byte-sized
90
- ptr:: copy_memory ( p_dst, ptr:: offset ( p_src, self . pos as int ) , size)
107
+ ptr:: copy_memory ( p_dst, ptr:: offset ( p_src, self . read_pos as int ) , size)
91
108
}
92
109
}
93
110
}
94
- self . pos += size;
111
+ self . read_pos += size;
95
112
Some ( size)
96
113
}
97
114
98
115
/// Return whether the Reader has reached the end of the stream AND exhausted its buffer.
99
116
fn eof ( & mut self ) -> bool {
100
- self . pos == self . max && self . wrapped . eof ( )
101
- }
102
- }
103
-
104
- struct BufferedWriter < ' self , T > {
105
- wrapped : & ' self mut T ,
106
- buffer : [ u8 , ..WRITE_BUF_SIZE ] ,
107
- buflen : uint ,
108
-
109
- /// Some things being written may not like flush() being called yet (e.g. explicitly fail!())
110
- /// The BufferedReader may need to be flushed for good control, but let it provide for such
111
- /// cases by not calling the wrapped object's flush method in turn.
112
- call_wrapped_flush : bool ,
113
- }
114
-
115
- impl < ' self , T : Writer > BufferedWriter < ' self , T > {
116
- pub fn new < ' a > ( writer : & ' a mut T , call_wrapped_flush : bool /*, buffer_size: uint*/ )
117
- -> BufferedWriter < ' a , T > {
118
- BufferedWriter {
119
- wrapped : writer,
120
- buffer : [ 0u8 , ..WRITE_BUF_SIZE ] , //[0u8, ..buffer_size],
121
- buflen : 0 u,
122
- call_wrapped_flush : call_wrapped_flush,
123
- }
117
+ self . read_pos == self . read_max && self . wrapped . eof ( )
124
118
}
125
119
}
126
120
127
121
#[ unsafe_destructor]
128
- impl < ' self , T : Writer > Drop for BufferedWriter < ' self , T > {
122
+ impl < T : Writer > Drop for BufferedStream < T > {
129
123
fn drop ( & self ) {
130
124
// Clearly wouldn't be a good idea to finish without flushing!
131
125
@@ -135,39 +129,40 @@ impl<'self, T: Writer> Drop for BufferedWriter<'self, T> {
135
129
}
136
130
}
137
131
138
- impl < ' self , T : Writer > Writer for BufferedWriter < ' self , T > {
132
+ impl < T : Writer > Writer for BufferedStream < T > {
139
133
fn write ( & mut self , buf : & [ u8 ] ) {
140
- if buf. len ( ) + self . buflen > self . buffer . len ( ) {
134
+ if buf. len ( ) + self . write_len > self . write_buffer . len ( ) {
141
135
// This is the lazy approach which may involve two writes where it's really not
142
136
// warranted. Maybe deal with that later.
143
- if self . buflen > 0 {
144
- self . wrapped . write ( self . buffer . slice_to ( self . buflen ) ) ;
145
- self . buflen = 0 ;
137
+ if self . write_len > 0 {
138
+ self . wrapped . write ( self . write_buffer . slice_to ( self . write_len ) ) ;
139
+ self . write_len = 0 ;
146
140
}
147
141
self . wrapped . write ( buf) ;
148
- self . buflen = 0 ;
142
+ self . write_len = 0 ;
149
143
} else {
150
144
// Safely copy buf onto the "end" of self.buffer
151
145
unsafe {
152
146
do buf. as_imm_buf |p_src, len_src| {
153
- do self . buffer . as_mut_buf |p_dst, _len_dst| {
147
+ do self . write_buffer . as_mut_buf |p_dst, _len_dst| {
154
148
// Note that copy_memory works on bytes; good, u8 is byte-sized
155
- ptr:: copy_memory ( ptr:: mut_offset ( p_dst, self . buflen as int ) , p_src, len_src)
149
+ ptr:: copy_memory ( ptr:: mut_offset ( p_dst, self . write_len as int ) ,
150
+ p_src, len_src)
156
151
}
157
152
}
158
153
}
159
- self . buflen += buf. len ( ) ;
160
- if self . buflen == self . buffer . len ( ) {
161
- self . wrapped . write ( self . buffer ) ;
162
- self . buflen = 0 ;
154
+ self . write_len += buf. len ( ) ;
155
+ if self . write_len == self . write_buffer . len ( ) {
156
+ self . wrapped . write ( self . write_buffer ) ;
157
+ self . write_len = 0 ;
163
158
}
164
159
}
165
160
}
166
161
167
162
fn flush ( & mut self ) {
168
- if self . buflen > 0 {
169
- self . wrapped . write ( self . buffer . slice_to ( self . buflen ) ) ;
170
- self . buflen = 0 ;
163
+ if self . write_len > 0 {
164
+ self . wrapped . write ( self . write_buffer . slice_to ( self . write_len ) ) ;
165
+ self . write_len = 0 ;
171
166
}
172
167
if self . call_wrapped_flush {
173
168
self . wrapped . flush ( ) ;
0 commit comments