Skip to content

Commit 0aba903

Browse files
committed
Add size-specific int reading methods to ReaderUtil to match the existing int writing methods in WriterUtil (for issue #2004).
1 parent a42d2d4 commit 0aba903

File tree

1 file changed

+250
-33
lines changed

1 file changed

+250
-33
lines changed

src/libcore/io.rs

Lines changed: 250 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,87 @@ pub trait Reader {
4646
}
4747

4848
// Generic utility functions defined on readers
49-
5049
pub trait ReaderUtil {
5150
fn read_bytes(len: uint) -> ~[u8];
5251
fn read_line() -> ~str;
5352

5453
fn read_chars(n: uint) -> ~[char];
5554
fn read_char() -> char;
5655
fn read_c_str() -> ~str;
57-
fn read_le_uint(size: uint) -> uint;
58-
fn read_le_int(size: uint) -> int;
59-
fn read_be_uint(size: uint) -> uint;
6056
fn read_whole_stream() -> ~[u8];
6157
fn each_byte(it: fn(int) -> bool);
6258
fn each_char(it: fn(char) -> bool);
6359
fn each_line(it: fn((&str)) -> bool);
60+
61+
/// read n (between 1 and 8) little-endian unsigned integer bytes
62+
fn read_le_uint_n(nbytes: uint) -> u64;
63+
64+
/// read n (between 1 and 8) little-endian signed integer bytes
65+
fn read_le_int_n(nbytes: uint) -> i64;
66+
67+
/// read n (between 1 and 8) big-endian unsigned integer bytes
68+
fn read_be_uint_n(nbytes: uint) -> u64;
69+
70+
/// read n (between 1 and 8) big-endian signed integer bytes
71+
fn read_be_int_n(nbytes: uint) -> i64;
72+
73+
/// read a little-endian uint (number of bytes read depends on system)
74+
fn read_le_uint() -> uint;
75+
76+
/// read a little-endian int (number of bytes read depends on system)
77+
fn read_le_int() -> int;
78+
79+
/// read a big-endian uint (number of bytes read depends on system)
80+
fn read_be_uint() -> uint;
81+
82+
/// read a big-endian int (number of bytes read depends on system)
83+
fn read_be_int() -> int;
84+
85+
/// read a big-endian u64 (8 bytes)
86+
fn read_be_u64() -> u64;
87+
88+
/// read a big-endian u32 (4 bytes)
89+
fn read_be_u32() -> u32;
90+
91+
/// read a big-endian u16 (2 bytes)
92+
fn read_be_u16() -> u16;
93+
94+
/// read a big-endian i64 (8 bytes)
95+
fn read_be_i64() -> i64;
96+
97+
/// read a big-endian i32 (4 bytes)
98+
fn read_be_i32() -> i32;
99+
100+
/// read a big-endian i16 (2 bytes)
101+
fn read_be_i16() -> i16;
102+
103+
/// read a little-endian u64 (8 bytes)
104+
fn read_le_u64() -> u64;
105+
106+
/// read a little-endian u32 (4 bytes)
107+
fn read_le_u32() -> u32;
108+
109+
/// read a little-endian u16 (2 bytes)
110+
fn read_le_u16() -> u16;
111+
112+
/// read a litle-endian i64 (8 bytes)
113+
fn read_le_i64() -> i64;
114+
115+
/// read a litle-endian i32 (4 bytes)
116+
fn read_le_i32() -> i32;
117+
118+
/// read a litle-endian i16 (2 bytes)
119+
fn read_le_i16() -> i16;
120+
121+
/// read a u8 (1 byte)
122+
fn read_u8() -> u8;
123+
124+
/// read a i8 (1 byte)
125+
fn read_i8() -> i8;
64126
}
65127

66128
impl<T: Reader> T : ReaderUtil {
129+
67130
fn read_bytes(len: uint) -> ~[u8] {
68131
let mut bytes = vec::with_capacity(len);
69132
unsafe { vec::raw::set_len(&mut bytes, len); }
@@ -73,6 +136,7 @@ impl<T: Reader> T : ReaderUtil {
73136
unsafe { vec::raw::set_len(&mut bytes, count); }
74137
move bytes
75138
}
139+
76140
fn read_line() -> ~str {
77141
let mut bytes = ~[];
78142
loop {
@@ -162,34 +226,6 @@ impl<T: Reader> T : ReaderUtil {
162226
str::from_bytes(bytes)
163227
}
164228

165-
// FIXME deal with eof? // #2004
166-
fn read_le_uint(size: uint) -> uint {
167-
let mut val = 0u, pos = 0u, i = size;
168-
while i > 0u {
169-
val += (self.read_byte() as uint) << pos;
170-
pos += 8u;
171-
i -= 1u;
172-
}
173-
val
174-
}
175-
fn read_le_int(size: uint) -> int {
176-
let mut val = 0u, pos = 0u, i = size;
177-
while i > 0u {
178-
val += (self.read_byte() as uint) << pos;
179-
pos += 8u;
180-
i -= 1u;
181-
}
182-
val as int
183-
}
184-
fn read_be_uint(size: uint) -> uint {
185-
let mut val = 0u, i = size;
186-
while i > 0u {
187-
i -= 1u;
188-
val += (self.read_byte() as uint) << i * 8u;
189-
}
190-
val
191-
}
192-
193229
fn read_whole_stream() -> ~[u8] {
194230
let mut bytes: ~[u8] = ~[];
195231
while !self.eof() { bytes.push_all(self.read_bytes(2048u)); }
@@ -213,6 +249,116 @@ impl<T: Reader> T : ReaderUtil {
213249
if !it(self.read_line()) { break; }
214250
}
215251
}
252+
253+
// FIXME int reading methods need to deal with eof - issue #2004
254+
255+
fn read_le_uint_n(nbytes: uint) -> u64 {
256+
assert nbytes > 0 && nbytes <= 8;
257+
258+
let mut val = 0u64, pos = 0, i = nbytes;
259+
while i > 0 {
260+
val += (self.read_u8() as u64) << pos;
261+
pos += 8;
262+
i -= 1;
263+
}
264+
val
265+
}
266+
267+
fn read_le_int_n(nbytes: uint) -> i64 {
268+
extend_sign(self.read_le_uint_n(nbytes), nbytes)
269+
}
270+
271+
fn read_be_uint_n(nbytes: uint) -> u64 {
272+
assert nbytes > 0 && nbytes <= 8;
273+
274+
let mut val = 0u64, i = nbytes;
275+
while i > 0 {
276+
i -= 1;
277+
val += (self.read_u8() as u64) << i * 8;
278+
}
279+
val
280+
}
281+
282+
fn read_be_int_n(nbytes: uint) -> i64 {
283+
extend_sign(self.read_be_uint_n(nbytes), nbytes)
284+
}
285+
286+
fn read_le_uint() -> uint {
287+
self.read_le_uint_n(uint::bytes) as uint
288+
}
289+
290+
fn read_le_int() -> int {
291+
self.read_le_int_n(int::bytes) as int
292+
}
293+
294+
fn read_be_uint() -> uint {
295+
self.read_be_uint_n(uint::bytes) as uint
296+
}
297+
298+
fn read_be_int() -> int {
299+
self.read_be_int_n(int::bytes) as int
300+
}
301+
302+
fn read_be_u64() -> u64 {
303+
self.read_be_uint_n(8) as u64
304+
}
305+
306+
fn read_be_u32() -> u32 {
307+
self.read_be_uint_n(4) as u32
308+
}
309+
310+
fn read_be_u16() -> u16 {
311+
self.read_be_uint_n(2) as u16
312+
}
313+
314+
fn read_be_i64() -> i64 {
315+
self.read_be_int_n(8) as i64
316+
}
317+
318+
fn read_be_i32() -> i32 {
319+
self.read_be_int_n(4) as i32
320+
}
321+
322+
fn read_be_i16() -> i16 {
323+
self.read_be_int_n(2) as i16
324+
}
325+
326+
fn read_le_u64() -> u64 {
327+
self.read_le_uint_n(8) as u64
328+
}
329+
330+
fn read_le_u32() -> u32 {
331+
self.read_le_uint_n(4) as u32
332+
}
333+
334+
fn read_le_u16() -> u16 {
335+
self.read_le_uint_n(2) as u16
336+
}
337+
338+
fn read_le_i64() -> i64 {
339+
self.read_le_int_n(8) as i64
340+
}
341+
342+
fn read_le_i32() -> i32 {
343+
self.read_le_int_n(4) as i32
344+
}
345+
346+
fn read_le_i16() -> i16 {
347+
self.read_le_int_n(2) as i16
348+
}
349+
350+
fn read_u8() -> u8 {
351+
self.read_byte() as u8
352+
}
353+
354+
fn read_i8() -> i8 {
355+
self.read_byte() as i8
356+
}
357+
}
358+
359+
fn extend_sign(val: u64, nbytes: uint) -> i64 {
360+
let shift = (8 - nbytes) * 8;
361+
(val << shift) as i64 >> shift
216362
}
217363

218364
// Reader implementations
@@ -589,6 +735,7 @@ pub trait WriterUtil {
589735
fn write_le_i32(n: i32);
590736
fn write_le_i16(n: i16);
591737
fn write_u8(n: u8);
738+
fn write_i8(n: i8);
592739
}
593740

594741
impl<T: Writer> T : WriterUtil {
@@ -659,7 +806,8 @@ impl<T: Writer> T : WriterUtil {
659806
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
660807
}
661808

662-
fn write_u8(n: u8) { self.write(&[n]) }
809+
fn write_u8(n: u8) { self.write([n]) }
810+
fn write_i8(n: i8) { self.write([n as u8]) }
663811
}
664812

665813
#[allow(non_implicitly_copyable_typarams)]
@@ -1001,6 +1149,75 @@ mod tests {
10011149
assert wr.bytes.borrow(|bytes| bytes ==
10021150
~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
10031151
}
1152+
1153+
#[test]
1154+
fn test_read_write_le() {
1155+
let path = Path("tmp/lib-io-test-read-write-le.tmp");
1156+
let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
1157+
1158+
// write the ints to the file
1159+
{
1160+
let file = io::file_writer(&path, [io::Create]).get();
1161+
for uints.each |i| {
1162+
file.write_le_u64(*i);
1163+
}
1164+
}
1165+
1166+
// then read them back and check that they are the same
1167+
{
1168+
let file = io::file_reader(&path).get();
1169+
for uints.each |i| {
1170+
assert file.read_le_u64() == *i;
1171+
}
1172+
}
1173+
}
1174+
1175+
#[test]
1176+
fn test_read_write_be() {
1177+
let path = Path("tmp/lib-io-test-read-write-be.tmp");
1178+
let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
1179+
1180+
// write the ints to the file
1181+
{
1182+
let file = io::file_writer(&path, [io::Create]).get();
1183+
for uints.each |i| {
1184+
file.write_be_u64(*i);
1185+
}
1186+
}
1187+
1188+
// then read them back and check that they are the same
1189+
{
1190+
let file = io::file_reader(&path).get();
1191+
for uints.each |i| {
1192+
assert file.read_be_u64() == *i;
1193+
}
1194+
}
1195+
}
1196+
1197+
#[test]
1198+
fn test_read_be_int_n() {
1199+
let path = Path("tmp/lib-io-test-read-be-int-n.tmp");
1200+
let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value];
1201+
1202+
// write the ints to the file
1203+
{
1204+
let file = io::file_writer(&path, [io::Create]).get();
1205+
for ints.each |i| {
1206+
file.write_be_i32(*i);
1207+
}
1208+
}
1209+
1210+
// then read them back and check that they are the same
1211+
{
1212+
let file = io::file_reader(&path).get();
1213+
for ints.each |i| {
1214+
// this tests that the sign extension is working
1215+
// (comparing the values as i32 would not test this)
1216+
assert file.read_be_int_n(4) == *i as i64;
1217+
}
1218+
}
1219+
}
1220+
10041221
}
10051222

10061223
//

0 commit comments

Comments
 (0)