io.rs 52.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
/*!
B
Brian Anderson 已提交
12

13 14 15 16 17 18
The `io` module contains basic input and output routines.

A quick summary:

## `Reader` and `Writer` traits

S
Steve Klabnik 已提交
19
These traits define the minimal set of methods that anything that can do
20 21 22 23 24
input and output should implement.

## `ReaderUtil` and `WriterUtil` traits

Richer methods that allow you to do more. `Reader` only lets you read a certain
S
Steve Klabnik 已提交
25
number of bytes into a buffer, while `ReaderUtil` allows you to read a whole
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
line, for example.

Generally, these richer methods are probably the ones you want to actually
use in day-to-day Rust.

Furthermore, because there is an implementation of `ReaderUtil` for
`<T: Reader>`, when your input or output code implements `Reader`, you get
all of these methods for free.

## `print` and `println`

These very useful functions are defined here. You generally don't need to
import them, though, as the prelude already does.

## `stdin`, `stdout`, and `stderr`

These functions return references to the classic three file descriptors. They
implement `Reader` and `Writer`, where appropriate.
44

B
Brian Anderson 已提交
45 46
*/

P
Patrick Walton 已提交
47
use result::Result;
48

49
use container::Container;
50 51
use int;
use libc;
A
Alex Crichton 已提交
52
use libc::{c_int, c_long, c_void, size_t, ssize_t};
P
Patrick Walton 已提交
53
use libc::consts::os::posix88::*;
54
use os;
55 56 57
use cast;
use path::Path;
use ops::Drop;
58
use old_iter::{BaseIter, CopyableIter};
59 60 61
use ptr;
use result;
use str;
62 63
use str::StrSlice;
use to_str::ToStr;
64 65
use uint;
use vec;
66
use vec::{OwnedVector, OwnedCopyableVector};
67

68
#[allow(non_camel_case_types)] // not sure what to do about this
69
pub type fd_t = c_int;
70

71 72 73 74 75 76 77 78 79 80
pub mod rustrt {
    use libc;

    #[abi = "cdecl"]
    #[link_name = "rustrt"]
    pub extern {
        unsafe fn rust_get_stdin() -> *libc::FILE;
        unsafe fn rust_get_stdout() -> *libc::FILE;
        unsafe fn rust_get_stderr() -> *libc::FILE;
    }
81 82 83 84
}

// Reading

85 86
// FIXME (#2004): This is all buffered. We might need an unbuffered variant
// as well
87 88 89 90 91 92
/**
* The SeekStyle enum describes the relationship between the position
* we'd like to seek to from our current position. It's used as an argument
* to the `seek` method defined on the `Reader` trait.
*
* There are three seek styles:
S
Steve Klabnik 已提交
93
*
94 95 96 97 98
* 1. `SeekSet` means that the new position should become our position.
* 2. `SeekCur` means that we should seek from the current position.
* 3. `SeekEnd` means that we should seek from the end.
*
* # Examples
S
Steve Klabnik 已提交
99 100
*
* None right now.
101
*/
102
pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, }
103 104


105 106 107 108
/**
* The core Reader trait. All readers must implement this trait.
*
* # Examples
S
Steve Klabnik 已提交
109 110
*
* None right now.
111
*/
112
pub trait Reader {
113
    // FIXME (#2004): Seekable really should be orthogonal.
114 115

    // FIXME (#2982): This should probably return an error.
116 117 118 119
    /**
    * Reads bytes and puts them into `bytes`. Returns the number of
    * bytes read.
    *
S
Steve Klabnik 已提交
120
    * The number of bytes to be read is `len` or the end of the file,
121 122 123 124 125
    * whichever comes first.
    *
    * The buffer must be at least `len` bytes long.
    *
    * # Examples
S
Steve Klabnik 已提交
126 127
    *
    * None right now.
128
    */
B
Ben Striegel 已提交
129
    fn read(&self, bytes: &mut [u8], len: uint) -> uint;
130

131 132 133 134 135 136
    /**
    * Reads a single byte.
    *
    * In the case of an EOF or an error, returns a negative value.
    *
    * # Examples
S
Steve Klabnik 已提交
137 138
    *
    * None right now.
139
    */
140
    fn read_byte(&self) -> int;
141

142 143 144 145
    /**
    * Returns a boolean value: are we currently at EOF?
    *
    * # Examples
S
Steve Klabnik 已提交
146 147
    *
    * None right now.
148
    */
149
    fn eof(&self) -> bool;
150

151 152
    /**
    * Seek to a given `position` in the stream.
S
Steve Klabnik 已提交
153
    *
154 155 156 157
    * Takes an optional SeekStyle, which affects how we seek from the
    * position. See `SeekStyle` docs for more details.
    *
    * # Examples
S
Steve Klabnik 已提交
158 159
    *
    * None right now.
160
    */
161
    fn seek(&self, position: int, style: SeekStyle);
162

163 164 165 166
    /**
    * Returns the current position within the stream.
    *
    * # Examples
S
Steve Klabnik 已提交
167 168
    *
    * None right now.
169
    */
170
    fn tell(&self) -> uint;
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
impl Reader for @Reader {
    fn read(&self, bytes: &mut [u8], len: uint) -> uint {
        self.read(bytes, len)
    }
    fn read_byte(&self) -> int {
        self.read_byte()
    }
    fn eof(&self) -> bool {
        self.eof()
    }
    fn seek(&self, position: int, style: SeekStyle) {
        self.seek(position, style)
    }
    fn tell(&self) -> uint {
        self.tell()
    }
}

191 192 193
/**
* The `ReaderUtil` trait is a home for many of the utility functions
* a particular Reader should implement.
194
*
195 196
* The default `Reader` trait is focused entirely on bytes. `ReaderUtil` is based
* on higher-level concepts like 'chars' and 'lines.'
197
*
198 199 200 201
* # Examples:
*
* None right now.
*/
202
pub trait ReaderUtil {
203

204 205 206 207 208 209 210
    /**
    * Reads `len` number of bytes, and gives you a new vector back.
    *
    * # Examples
    *
    * None right now.
    */
211
    fn read_bytes(&self, len: uint) -> ~[u8];
212

213
    /**
214
    * Reads up until a specific byte is seen or EOF.
215
    *
216 217 218 219 220 221 222
    * The `include` parameter specifies if the character should be included
    * in the returned string.
    *
    * # Examples
    *
    * None right now.
    */
223
    fn read_until(&self, c: u8, include: bool) -> ~str;
224

225 226
    /**
    * Reads up until the first '\n' or EOF.
227
    *
228 229 230 231 232 233
    * The '\n' is not included in the result.
    *
    * # Examples
    *
    * None right now.
    */
234
    fn read_line(&self) -> ~str;
235

236 237
    /**
    * Reads `n` chars.
238
    *
239
    * Assumes that those chars are UTF-8 encoded.
240
    *
241 242 243 244 245 246
    * The '\n' is not included in the result.
    *
    * # Examples
    *
    * None right now.
    */
247
    fn read_chars(&self, n: uint) -> ~[char];
248

249 250 251 252 253 254 255
    /**
    * Reads a single UTF-8 encoded char.
    *
    * # Examples
    *
    * None right now.
    */
256
    fn read_char(&self) -> char;
257

258 259 260 261 262 263 264 265 266
    /**
    * Reads up until the first null byte or EOF.
    *
    * The null byte is not returned.
    *
    * # Examples
    *
    * None right now.
    */
267
    fn read_c_str(&self) -> ~str;
268

269 270 271 272 273 274 275
    /**
    * Reads all remaining data in the stream.
    *
    * # Examples
    *
    * None right now.
    */
276
    fn read_whole_stream(&self) -> ~[u8];
277

278 279 280 281 282 283 284
    /**
    * Iterate over every byte until EOF or the iterator breaks.
    *
    * # Examples
    *
    * None right now.
    */
A
Alex Crichton 已提交
285
    #[cfg(stage0)]
286
    fn each_byte(&self, it: &fn(int) -> bool);
A
Alex Crichton 已提交
287 288
    #[cfg(not(stage0))]
    fn each_byte(&self, it: &fn(int) -> bool) -> bool;
289

290 291 292 293 294 295 296
    /**
    * Iterate over every char until EOF or the iterator breaks.
    *
    * # Examples
    *
    * None right now.
    */
A
Alex Crichton 已提交
297
    #[cfg(stage0)]
298
    fn each_char(&self, it: &fn(char) -> bool);
A
Alex Crichton 已提交
299 300
    #[cfg(not(stage0))]
    fn each_char(&self, it: &fn(char) -> bool) -> bool;
301

302 303 304 305 306 307 308
    /**
    * Iterate over every line until EOF or the iterator breaks.
    *
    * # Examples
    *
    * None right now.
    */
A
Alex Crichton 已提交
309
    #[cfg(stage0)]
310
    fn each_line(&self, it: &fn(&str) -> bool);
A
Alex Crichton 已提交
311 312
    #[cfg(not(stage0))]
    fn each_line(&self, it: &fn(&str) -> bool) -> bool;
313

314 315
    /**
    * Reads all of the lines in the stream.
316
    *
317 318 319 320 321 322
    * Returns a vector of those lines.
    *
    * # Examples
    *
    * None right now.
    */
323 324
    fn read_lines(&self) -> ~[~str];

325 326
    /**
    * Reads `n` little-endian unsigned integer bytes.
327
    *
328
    * `n` must be between 1 and 8, inclusive.
329
    *
330 331 332 333
    * # Examples
    *
    * None right now.
    */
334
    fn read_le_uint_n(&self, nbytes: uint) -> u64;
335

336 337
    /**
    * Reads `n` little-endian signed integer bytes.
338
    *
339
    * `n` must be between 1 and 8, inclusive.
340
    *
341 342 343 344
    * # Examples
    *
    * None right now.
    */
345
    fn read_le_int_n(&self, nbytes: uint) -> i64;
346

347 348
    /**
    * Reads `n` big-endian unsigned integer bytes.
349
    *
350
    * `n` must be between 1 and 8, inclusive.
351
    *
352 353 354 355
    * # Examples
    *
    * None right now.
    */
356
    fn read_be_uint_n(&self, nbytes: uint) -> u64;
357

358 359
    /**
    * Reads `n` big-endian signed integer bytes.
360
    *
361
    * `n` must be between 1 and 8, inclusive.
362
    *
363 364 365 366
    * # Examples
    *
    * None right now.
    */
367
    fn read_be_int_n(&self, nbytes: uint) -> i64;
368

369 370
    /**
    * Reads a little-endian unsigned integer.
371
    *
372
    * The number of bytes returned is system-dependant.
373
    *
374 375 376 377
    * # Examples
    *
    * None right now.
    */
378
    fn read_le_uint(&self) -> uint;
379

380 381
    /**
    * Reads a little-endian integer.
382
    *
383
    * The number of bytes returned is system-dependant.
384
    *
385 386 387 388
    * # Examples
    *
    * None right now.
    */
389
    fn read_le_int(&self) -> int;
390

391 392
    /**
    * Reads a big-endian unsigned integer.
393
    *
394
    * The number of bytes returned is system-dependant.
395
    *
396 397 398 399
    * # Examples
    *
    * None right now.
    */
400
    fn read_be_uint(&self) -> uint;
401

402 403
    /**
    * Reads a big-endian integer.
404
    *
405
    * The number of bytes returned is system-dependant.
406
    *
407 408 409 410
    * # Examples
    *
    * None right now.
    */
411
    fn read_be_int(&self) -> int;
412

413 414
    /**
    * Reads a big-endian `u64`.
415
    *
416
    * `u64`s are 8 bytes long.
417
    *
418 419 420 421
    * # Examples
    *
    * None right now.
    */
422
    fn read_be_u64(&self) -> u64;
423

424 425
    /**
    * Reads a big-endian `u32`.
426
    *
427
    * `u32`s are 4 bytes long.
428
    *
429 430 431 432
    * # Examples
    *
    * None right now.
    */
433
    fn read_be_u32(&self) -> u32;
434

435 436
    /**
    * Reads a big-endian `u16`.
437
    *
438
    * `u16`s are 2 bytes long.
439
    *
440 441 442 443
    * # Examples
    *
    * None right now.
    */
444
    fn read_be_u16(&self) -> u16;
445

446 447
    /**
    * Reads a big-endian `i64`.
448
    *
449
    * `i64`s are 8 bytes long.
450
    *
451 452 453 454
    * # Examples
    *
    * None right now.
    */
455
    fn read_be_i64(&self) -> i64;
456

457 458
    /**
    * Reads a big-endian `i32`.
459
    *
460
    * `i32`s are 4 bytes long.
461
    *
462 463 464 465
    * # Examples
    *
    * None right now.
    */
466
    fn read_be_i32(&self) -> i32;
467

468 469
    /**
    * Reads a big-endian `i16`.
470
    *
471
    * `i16`s are 2 bytes long.
472
    *
473 474 475 476
    * # Examples
    *
    * None right now.
    */
477
    fn read_be_i16(&self) -> i16;
478

479 480
    /**
    * Reads a big-endian `f64`.
481
    *
482
    * `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
483
    *
484 485 486 487
    * # Examples
    *
    * None right now.
    */
488 489
    fn read_be_f64(&self) -> f64;

490 491
    /**
    * Reads a big-endian `f32`.
492
    *
493
    * `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
494
    *
495 496 497 498
    * # Examples
    *
    * None right now.
    */
499 500
    fn read_be_f32(&self) -> f32;

501 502
    /**
    * Reads a little-endian `u64`.
503
    *
504
    * `u64`s are 8 bytes long.
505
    *
506 507 508 509
    * # Examples
    *
    * None right now.
    */
510
    fn read_le_u64(&self) -> u64;
511

512 513
    /**
    * Reads a little-endian `u32`.
514
    *
515
    * `u32`s are 4 bytes long.
516
    *
517 518 519 520
    * # Examples
    *
    * None right now.
    */
521
    fn read_le_u32(&self) -> u32;
522

523 524
    /**
    * Reads a little-endian `u16`.
525
    *
526
    * `u16`s are 2 bytes long.
527
    *
528 529 530 531
    * # Examples
    *
    * None right now.
    */
532
    fn read_le_u16(&self) -> u16;
533

534 535
    /**
    * Reads a little-endian `i64`.
536
    *
537
    * `i64`s are 8 bytes long.
538
    *
539 540 541 542
    * # Examples
    *
    * None right now.
    */
543
    fn read_le_i64(&self) -> i64;
544

545 546
    /**
    * Reads a little-endian `i32`.
547
    *
548
    * `i32`s are 4 bytes long.
549
    *
550 551 552 553
    * # Examples
    *
    * None right now.
    */
554
    fn read_le_i32(&self) -> i32;
555

556 557
    /**
    * Reads a little-endian `i16`.
558
    *
559
    * `i16`s are 2 bytes long.
560
    *
561 562 563 564
    * # Examples
    *
    * None right now.
    */
565
    fn read_le_i16(&self) -> i16;
566

567 568
    /**
    * Reads a little-endian `f64`.
569
    *
570
    * `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
571
    *
572 573 574 575
    * # Examples
    *
    * None right now.
    */
576 577
    fn read_le_f64(&self) -> f64;

578 579
    /**
    * Reads a little-endian `f32`.
580
    *
581
    * `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
582
    *
583 584 585 586
    * # Examples
    *
    * None right now.
    */
587 588
    fn read_le_f32(&self) -> f32;

589
    /**
590 591
    * Read a u8.
    *
592
    * `u8`s are 1 byte.
593
    *
594 595 596 597
    * # Examples
    *
    * None right now.
    */
598
    fn read_u8(&self) -> u8;
599

600
    /**
601 602
    * Read an i8.
    *
S
Steve Klabnik 已提交
603
    * `i8`s are 1 byte.
604
    *
605 606 607 608
    * # Examples
    *
    * None right now.
    */
609
    fn read_i8(&self) -> i8;
610 611
}

612
impl<T:Reader> ReaderUtil for T {
613

614
    fn read_bytes(&self,len: uint) -> ~[u8] {
615 616
        let mut bytes = vec::with_capacity(len);
        unsafe { vec::raw::set_len(&mut bytes, len); }
617

618
        let count = self.read(bytes, len);
619

620
        unsafe { vec::raw::set_len(&mut bytes, count); }
L
Luqman Aden 已提交
621
        bytes
622
    }
623

624
    fn read_until(&self, c: u8, include: bool) -> ~str {
625
        let mut bytes = ~[];
626 627
        loop {
            let ch = self.read_byte();
628
            if ch == -1 || ch == c as int {
629 630 631
                if include && ch == c as int {
                    bytes.push(ch as u8);
                }
632 633
                break;
            }
634
            bytes.push(ch as u8);
635
        }
636
        str::from_bytes(bytes)
637 638
    }

639
    fn read_line(&self) -> ~str {
640
        self.read_until('\n' as u8, false)
641 642
    }

643
    fn read_chars(&self, n: uint) -> ~[char] {
644
        // returns the (consumed offset, n_req), appends characters to &chars
645
        fn chars_from_bytes<T:Reader>(bytes: &~[u8], chars: &mut ~[char])
T
Tim Chevalier 已提交
646 647
            -> (uint, uint) {
            let mut i = 0;
648 649 650
            let bytes_len = bytes.len();
            while i < bytes_len {
                let b0 = bytes[i];
651 652
                let w = str::utf8_char_width(b0);
                let end = i + w;
T
Tim Chevalier 已提交
653
                i += 1;
P
Patrick Walton 已提交
654
                assert!((w > 0));
T
Tim Chevalier 已提交
655
                if w == 1 {
656
                    chars.push(b0 as char);
657
                    loop;
658 659
                }
                // can't satisfy this char with the existing data
660 661
                if end > bytes_len {
                    return (i - 1, end - bytes_len);
662
                }
T
Tim Chevalier 已提交
663
                let mut val = 0;
664
                while i < end {
665
                    let next = bytes[i] as int;
T
Tim Chevalier 已提交
666
                    i += 1;
P
Patrick Walton 已提交
667
                    assert!((next > -1));
668
                    assert_eq!(next & 192, 128);
T
Tim Chevalier 已提交
669
                    val <<= 6;
670
                    val += (next & 63) as uint;
671 672
                }
                // See str::char_at
T
Tim Chevalier 已提交
673 674
                val += ((b0 << ((w + 1) as u8)) as uint)
                    << (w - 1) * 6 - w - 1u;
675
                chars.push(val as char);
676
            }
T
Tim Chevalier 已提交
677
            return (i, 0);
678
        }
E
Erick Tryzelaar 已提交
679 680
        let mut bytes = ~[];
        let mut chars = ~[];
681
        // might need more bytes, but reading n will never over-read
682
        let mut nbread = n;
T
Tim Chevalier 已提交
683
        while nbread > 0 {
684
            let data = self.read_bytes(nbread);
T
Tim Chevalier 已提交
685
            if data.is_empty() {
686 687
                // eof - FIXME (#2004): should we do something if
                // we're split in a unicode char?
688 689
                break;
            }
690 691
            bytes.push_all(data);
            let (offset, nbreq) = chars_from_bytes::<T>(&bytes, &mut chars);
T
Tim Chevalier 已提交
692
            let ncreq = n - chars.len();
693 694 695
            // again we either know we need a certain number of bytes
            // to complete a character, or we make sure we don't
            // over-read by reading 1-byte per char needed
696
            nbread = if ncreq > nbreq { ncreq } else { nbreq };
T
Tim Chevalier 已提交
697
            if nbread > 0 {
698
                bytes = vec::slice(bytes, offset, bytes.len()).to_vec();
699 700
            }
        }
L
Luqman Aden 已提交
701
        chars
702
    }
M
Marijn Haverbeke 已提交
703

704
    fn read_char(&self) -> char {
T
Tim Chevalier 已提交
705
        let c = self.read_chars(1);
Y
Youngmin Yoo 已提交
706
        if c.len() == 0 {
B
Brian Anderson 已提交
707
            return -1 as char; // FIXME will this stay valid? // #2004
708
        }
709
        assert_eq!(c.len(), 1);
B
Brian Anderson 已提交
710
        return c[0];
711
    }
M
Marijn Haverbeke 已提交
712

713
    fn read_c_str(&self) -> ~str {
714
        self.read_until(0u8, false)
715 716
    }

717
    fn read_whole_stream(&self) -> ~[u8] {
718 719
        let mut bytes: ~[u8] = ~[];
        while !self.eof() { bytes.push_all(self.read_bytes(2048u)); }
L
Luqman Aden 已提交
720
        bytes
M
Marijn Haverbeke 已提交
721
    }
722

A
Alex Crichton 已提交
723
    #[cfg(stage0)]
724
    fn each_byte(&self, it: &fn(int) -> bool) {
725 726 727 728
        while !self.eof() {
            if !it(self.read_byte()) { break; }
        }
    }
A
Alex Crichton 已提交
729 730 731 732 733 734 735
    #[cfg(not(stage0))]
    fn each_byte(&self, it: &fn(int) -> bool) -> bool {
        while !self.eof() {
            if !it(self.read_byte()) { return false; }
        }
        return true;
    }
736

A
Alex Crichton 已提交
737
    #[cfg(stage0)]
738
    fn each_char(&self, it: &fn(char) -> bool) {
739 740 741 742
        while !self.eof() {
            if !it(self.read_char()) { break; }
        }
    }
A
Alex Crichton 已提交
743 744 745 746 747 748 749
    #[cfg(not(stage0))]
    fn each_char(&self, it: &fn(char) -> bool) -> bool {
        while !self.eof() {
            if !it(self.read_char()) { return false; }
        }
        return true;
    }
750

A
Alex Crichton 已提交
751
    #[cfg(stage0)]
752
    fn each_line(&self, it: &fn(s: &str) -> bool) {
753
        while !self.eof() {
754 755 756
            // include the \n, so that we can distinguish an entirely empty
            // line read after "...\n", and the trailing empty line in
            // "...\n\n".
757
            let mut line = self.read_until('\n' as u8, true);
758 759 760 761 762 763 764 765 766 767 768 769 770

            // blank line at the end of the reader is ignored
            if self.eof() && line.is_empty() { break; }

            // trim the \n, so that each_line is consistent with read_line
            let n = str::len(line);
            if line[n-1] == '\n' as u8 {
                unsafe { str::raw::set_len(&mut line, n-1); }
            }

            if !it(line) { break; }
        }
    }
A
Alex Crichton 已提交
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
    #[cfg(not(stage0))]
    fn each_line(&self, it: &fn(s: &str) -> bool) -> bool {
        while !self.eof() {
            // include the \n, so that we can distinguish an entirely empty
            // line read after "...\n", and the trailing empty line in
            // "...\n\n".
            let mut line = self.read_until('\n' as u8, true);

            // blank line at the end of the reader is ignored
            if self.eof() && line.is_empty() { break; }

            // trim the \n, so that each_line is consistent with read_line
            let n = str::len(line);
            if line[n-1] == '\n' as u8 {
                unsafe { str::raw::set_len(&mut line, n-1); }
            }

            if !it(line) { return false; }
        }
        return true;
    }
792 793 794 795

    fn read_lines(&self) -> ~[~str] {
        do vec::build |push| {
            for self.each_line |line| {
796
                push(str::to_owned(line));
797
            }
798 799
        }
    }
800 801 802

    // FIXME int reading methods need to deal with eof - issue #2004

803
    fn read_le_uint_n(&self, nbytes: uint) -> u64 {
P
Patrick Walton 已提交
804
        assert!(nbytes > 0 && nbytes <= 8);
805 806 807 808 809 810 811 812 813 814

        let mut val = 0u64, pos = 0, i = nbytes;
        while i > 0 {
            val += (self.read_u8() as u64) << pos;
            pos += 8;
            i -= 1;
        }
        val
    }

815
    fn read_le_int_n(&self, nbytes: uint) -> i64 {
816 817 818
        extend_sign(self.read_le_uint_n(nbytes), nbytes)
    }

819
    fn read_be_uint_n(&self, nbytes: uint) -> u64 {
P
Patrick Walton 已提交
820
        assert!(nbytes > 0 && nbytes <= 8);
821 822 823 824 825 826 827 828 829

        let mut val = 0u64, i = nbytes;
        while i > 0 {
            i -= 1;
            val += (self.read_u8() as u64) << i * 8;
        }
        val
    }

830
    fn read_be_int_n(&self, nbytes: uint) -> i64 {
831 832 833
        extend_sign(self.read_be_uint_n(nbytes), nbytes)
    }

834
    fn read_le_uint(&self) -> uint {
835 836 837
        self.read_le_uint_n(uint::bytes) as uint
    }

838
    fn read_le_int(&self) -> int {
839 840 841
        self.read_le_int_n(int::bytes) as int
    }

842
    fn read_be_uint(&self) -> uint {
843 844 845
        self.read_be_uint_n(uint::bytes) as uint
    }

846
    fn read_be_int(&self) -> int {
847 848 849
        self.read_be_int_n(int::bytes) as int
    }

850
    fn read_be_u64(&self) -> u64 {
851 852 853
        self.read_be_uint_n(8) as u64
    }

854
    fn read_be_u32(&self) -> u32 {
855 856 857
        self.read_be_uint_n(4) as u32
    }

858
    fn read_be_u16(&self) -> u16 {
859 860 861
        self.read_be_uint_n(2) as u16
    }

862
    fn read_be_i64(&self) -> i64 {
863 864 865
        self.read_be_int_n(8) as i64
    }

866
    fn read_be_i32(&self) -> i32 {
867 868 869
        self.read_be_int_n(4) as i32
    }

870
    fn read_be_i16(&self) -> i16 {
871 872 873
        self.read_be_int_n(2) as i16
    }

874 875 876 877 878 879 880 881 882 883 884 885
    fn read_be_f64(&self) -> f64 {
        unsafe {
            cast::transmute::<u64, f64>(self.read_be_u64())
        }
    }

    fn read_be_f32(&self) -> f32 {
        unsafe {
            cast::transmute::<u32, f32>(self.read_be_u32())
        }
    }

886
    fn read_le_u64(&self) -> u64 {
887 888 889
        self.read_le_uint_n(8) as u64
    }

890
    fn read_le_u32(&self) -> u32 {
891 892 893
        self.read_le_uint_n(4) as u32
    }

894
    fn read_le_u16(&self) -> u16 {
895 896 897
        self.read_le_uint_n(2) as u16
    }

898
    fn read_le_i64(&self) -> i64 {
899 900 901
        self.read_le_int_n(8) as i64
    }

902
    fn read_le_i32(&self) -> i32 {
903 904 905
        self.read_le_int_n(4) as i32
    }

906
    fn read_le_i16(&self) -> i16 {
907 908 909
        self.read_le_int_n(2) as i16
    }

910 911 912 913 914 915 916 917 918 919 920 921
    fn read_le_f64(&self) -> f64 {
        unsafe {
            cast::transmute::<u64, f64>(self.read_le_u64())
        }
    }

    fn read_le_f32(&self) -> f32 {
        unsafe {
            cast::transmute::<u32, f32>(self.read_le_u32())
        }
    }

922
    fn read_u8(&self) -> u8 {
923 924 925
        self.read_byte() as u8
    }

926
    fn read_i8(&self) -> i8 {
927 928 929 930 931 932 933
        self.read_byte() as i8
    }
}

fn extend_sign(val: u64, nbytes: uint) -> i64 {
    let shift = (8 - nbytes) * 8;
    (val << shift) as i64 >> shift
M
Marijn Haverbeke 已提交
934 935 936 937
}

// Reader implementations

938
fn convert_whence(whence: SeekStyle) -> i32 {
939
    return match whence {
940 941 942
      SeekSet => 0i32,
      SeekCur => 1i32,
      SeekEnd => 2i32
M
Marijn Haverbeke 已提交
943 944 945
    };
}

946
impl Reader for *libc::FILE {
B
Ben Striegel 已提交
947
    fn read(&self, bytes: &mut [u8], len: uint) -> uint {
948 949
        unsafe {
            do vec::as_mut_buf(bytes) |buf_p, buf_len| {
P
Patrick Walton 已提交
950
                assert!(buf_len >= len);
951

952
                let count = libc::fread(buf_p as *mut c_void, 1u as size_t,
F
Fedor Indutny 已提交
953 954 955 956 957 958 959 960 961 962 963
                                        len as size_t, *self) as uint;
                if count < len {
                  match libc::ferror(*self) {
                    0 => (),
                    _ => {
                      error!("error reading buffer");
                      error!("%s", os::last_os_error());
                      fail!();
                    }
                  }
                }
964

F
Fedor Indutny 已提交
965
                count
966 967 968 969 970 971 972 973 974 975 976
            }
        }
    }
    fn read_byte(&self) -> int {
        unsafe {
            libc::fgetc(*self) as int
        }
    }
    fn eof(&self) -> bool {
        unsafe {
            return libc::feof(*self) != 0 as c_int;
977
        }
978
    }
979
    fn seek(&self, offset: int, whence: SeekStyle) {
980
        unsafe {
P
Patrick Walton 已提交
981
            assert!(libc::fseek(*self,
982 983
                                     offset as c_long,
                                     convert_whence(whence)) == 0 as c_int);
984 985 986 987 988 989
        }
    }
    fn tell(&self) -> uint {
        unsafe {
            return libc::ftell(*self) as uint;
        }
M
Marijn Haverbeke 已提交
990
    }
991 992
}

993 994 995 996 997
struct Wrapper<T, C> {
    base: T,
    cleanup: C,
}

M
Marijn Haverbeke 已提交
998 999
// A forwarding impl of reader that also holds on to a resource for the
// duration of its lifetime.
1000
// FIXME there really should be a better way to do this // #2004
1001
impl<R:Reader,C> Reader for Wrapper<R, C> {
B
Ben Striegel 已提交
1002
    fn read(&self, bytes: &mut [u8], len: uint) -> uint {
1003 1004
        self.base.read(bytes, len)
    }
1005 1006 1007 1008 1009 1010
    fn read_byte(&self) -> int { self.base.read_byte() }
    fn eof(&self) -> bool { self.base.eof() }
    fn seek(&self, off: int, whence: SeekStyle) {
        self.base.seek(off, whence)
    }
    fn tell(&self) -> uint { self.base.tell() }
1011 1012
}

1013
pub struct FILERes {
1014
    f: *libc::FILE,
1015 1016 1017 1018
}

impl Drop for FILERes {
    fn finalize(&self) {
1019 1020 1021 1022
        unsafe {
            libc::fclose(self.f);
        }
    }
1023
}
M
Marijn Haverbeke 已提交
1024

1025
pub fn FILERes(f: *libc::FILE) -> FILERes {
B
Brian Anderson 已提交
1026 1027 1028 1029 1030
    FILERes {
        f: f
    }
}

P
Patrick Walton 已提交
1031
pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader {
M
Marijn Haverbeke 已提交
1032
    if cleanup {
P
Patrick Walton 已提交
1033
        @Wrapper { base: f, cleanup: FILERes(f) } as @Reader
M
Marijn Haverbeke 已提交
1034
    } else {
P
Patrick Walton 已提交
1035
        @f as @Reader
M
Marijn Haverbeke 已提交
1036 1037 1038
    }
}

1039
// FIXME (#2004): this should either be an trait-less impl, a set of
1040 1041
// top-level functions that take a reader, or a set of default methods on
// reader (which can then be called reader)
M
Marijn Haverbeke 已提交
1042

S
Steve Klabnik 已提交
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
/**
* Gives a `Reader` that allows you to read values from standard input.
*
* # Examples
* ~~~
* let stdin = core::io::stdin();
* let line = stdin.read_line();
* core::io::print(line);
* ~~~
*/
P
Patrick Walton 已提交
1053
pub fn stdin() -> @Reader {
1054
    unsafe {
1055
        @rustrt::rust_get_stdin() as @Reader
1056 1057
    }
}
M
Marijn Haverbeke 已提交
1058

P
Patrick Walton 已提交
1059
pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    unsafe {
        let f = os::as_c_charp(path.to_str(), |pathbuf| {
            os::as_c_charp("r", |modebuf|
                libc::fopen(pathbuf, modebuf)
            )
        });
        return if f as uint == 0u { result::Err(~"error opening "
                                                + path.to_str()) }
        else {
            result::Ok(FILE_reader(f, true))
        }
1071
    }
1072 1073 1074
}


1075
// Byte readers
1076
pub struct BytesReader<'self> {
1077
    bytes: &'self [u8],
1078
    pos: @mut uint
1079
}
M
Marijn Haverbeke 已提交
1080

1081
impl<'self> Reader for BytesReader<'self> {
B
Ben Striegel 已提交
1082
    fn read(&self, bytes: &mut [u8], len: uint) -> uint {
1083
        let count = uint::min(len, self.bytes.len() - *self.pos);
1084

1085
        let view = vec::slice(self.bytes, *self.pos, self.bytes.len());
1086
        vec::bytes::copy_memory(bytes, view, count);
1087

1088
        *self.pos += count;
1089 1090

        count
1091
    }
1092

1093
    fn read_byte(&self) -> int {
1094 1095 1096 1097 1098 1099 1100
        if *self.pos == self.bytes.len() {
            return -1;
        }

        let b = self.bytes[*self.pos];
        *self.pos += 1u;
        b as int
1101
    }
1102 1103 1104 1105 1106

    fn eof(&self) -> bool {
        *self.pos == self.bytes.len()
    }

1107
    fn seek(&self, offset: int, whence: SeekStyle) {
1108 1109 1110 1111 1112 1113
        let pos = *self.pos;
        *self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence);
    }

    fn tell(&self) -> uint {
        *self.pos
1114 1115 1116
    }
}

1117 1118 1119 1120 1121
pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T {
    f(@BytesReader {
        bytes: bytes,
        pos: @mut 0
    } as @Reader)
1122 1123
}

1124
pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T {
1125
    str::byte_slice(s, |bytes| with_bytes_reader(bytes, f))
1126
}
1127 1128

// Writing
1129
pub enum FileFlag { Append, Create, Truncate, NoFlag, }
1130

1131
// What type of writer are we?
1132
#[deriving(Eq)]
1133
pub enum WriterType { Screen, File }
1134

1135 1136
// FIXME (#2004): Seekable really should be orthogonal.
// FIXME (#2004): eventually u64
1137
/// The raw underlying writer trait. All writers must implement this.
1138
pub trait Writer {
1139 1140

    /// Write all of the given bytes.
N
Niko Matsakis 已提交
1141
    fn write(&self, v: &[u8]);
1142 1143 1144

    /// Move the current position within the stream. The second parameter
    /// determines the position that the first parameter is relative to.
1145
    fn seek(&self, int, SeekStyle);
1146 1147

    /// Return the current position within the stream.
1148
    fn tell(&self) -> uint;
1149 1150

    /// Flush the output buffer for this stream (if there is one).
1151
    fn flush(&self) -> int;
1152 1153

    /// Determine if this Writer is writing to a file or not.
1154
    fn get_type(&self) -> WriterType;
M
Marijn Haverbeke 已提交
1155 1156
}

1157
impl Writer for @Writer {
N
Niko Matsakis 已提交
1158
    fn write(&self, v: &[u8]) { self.write(v) }
1159 1160 1161 1162 1163 1164
    fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) }
    fn tell(&self) -> uint { self.tell() }
    fn flush(&self) -> int { self.flush() }
    fn get_type(&self) -> WriterType { self.get_type() }
}

1165
impl<W:Writer,C> Writer for Wrapper<W, C> {
N
Niko Matsakis 已提交
1166
    fn write(&self, bs: &[u8]) { self.base.write(bs); }
1167 1168 1169 1170
    fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); }
    fn tell(&self) -> uint { self.base.tell() }
    fn flush(&self) -> int { self.base.flush() }
    fn get_type(&self) -> WriterType { File }
M
Marijn Haverbeke 已提交
1171
}
1172

1173
impl Writer for *libc::FILE {
N
Niko Matsakis 已提交
1174
    fn write(&self, v: &[u8]) {
1175 1176 1177 1178 1179 1180 1181 1182
        unsafe {
            do vec::as_const_buf(v) |vbuf, len| {
                let nout = libc::fwrite(vbuf as *c_void,
                                        1,
                                        len as size_t,
                                        *self);
                if nout != len as size_t {
                    error!("error writing buffer");
B
Brian Anderson 已提交
1183
                    error!("%s", os::last_os_error());
1184
                    fail!();
1185
                }
1186 1187
            }
        }
1188
    }
1189
    fn seek(&self, offset: int, whence: SeekStyle) {
1190
        unsafe {
P
Patrick Walton 已提交
1191
            assert!(libc::fseek(*self,
1192 1193
                                     offset as c_long,
                                     convert_whence(whence)) == 0 as c_int);
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
        }
    }
    fn tell(&self) -> uint {
        unsafe {
            libc::ftell(*self) as uint
        }
    }
    fn flush(&self) -> int {
        unsafe {
            libc::fflush(*self) as int
        }
1205
    }
1206
    fn get_type(&self) -> WriterType {
1207 1208 1209 1210 1211
        unsafe {
            let fd = libc::fileno(*self);
            if libc::isatty(fd) == 0 { File   }
            else                     { Screen }
        }
1212
    }
1213 1214
}

1215
pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer {
M
Marijn Haverbeke 已提交
1216
    if cleanup {
1217
        @Wrapper { base: f, cleanup: FILERes(f) } as @Writer
M
Marijn Haverbeke 已提交
1218
    } else {
1219
        @f as @Writer
M
Marijn Haverbeke 已提交
1220 1221
    }
}
1222

1223
impl Writer for fd_t {
N
Niko Matsakis 已提交
1224
    fn write(&self, v: &[u8]) {
1225 1226 1227 1228 1229 1230 1231 1232
        unsafe {
            let mut count = 0u;
            do vec::as_const_buf(v) |vbuf, len| {
                while count < len {
                    let vb = ptr::const_offset(vbuf, count) as *c_void;
                    let nout = libc::write(*self, vb, len as size_t);
                    if nout < 0 as ssize_t {
                        error!("error writing buffer");
B
Brian Anderson 已提交
1233
                        error!("%s", os::last_os_error());
1234
                        fail!();
1235 1236
                    }
                    count += nout as uint;
1237
                }
1238 1239 1240
            }
        }
    }
1241
    fn seek(&self, _offset: int, _whence: SeekStyle) {
P
Paul Stansifer 已提交
1242
        error!("need 64-bit foreign calls for seek, sorry");
1243
        fail!();
1244
    }
1245
    fn tell(&self) -> uint {
P
Paul Stansifer 已提交
1246
        error!("need 64-bit foreign calls for tell, sorry");
1247
        fail!();
1248
    }
1249 1250
    fn flush(&self) -> int { 0 }
    fn get_type(&self) -> WriterType {
1251 1252 1253
        unsafe {
            if libc::isatty(*self) == 0 { File } else { Screen }
        }
1254
    }
M
Marijn Haverbeke 已提交
1255
}
1256

1257
pub struct FdRes {
1258
    fd: fd_t,
1259 1260 1261 1262
}

impl Drop for FdRes {
    fn finalize(&self) {
1263 1264 1265 1266
        unsafe {
            libc::close(self.fd);
        }
    }
1267
}
1268

1269
pub fn FdRes(fd: fd_t) -> FdRes {
B
Brian Anderson 已提交
1270 1271 1272 1273 1274
    FdRes {
        fd: fd
    }
}

1275
pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer {
M
Marijn Haverbeke 已提交
1276
    if cleanup {
1277
        @Wrapper { base: fd, cleanup: FdRes(fd) } as @Writer
M
Marijn Haverbeke 已提交
1278
    } else {
1279
        @fd as @Writer
1280
    }
1281 1282
}

1283

1284
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
1285
                   -> Result<@Writer, ~str> {
1286
    #[cfg(windows)]
1287 1288 1289
    fn wb() -> c_int {
      (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
    }
1290

1291
    #[cfg(unix)]
1292 1293 1294
    fn wb() -> c_int { O_WRONLY as c_int }

    let mut fflags: c_int = wb();
1295
    for flags.each |f| {
1296
        match *f {
1297 1298 1299 1300
          Append => fflags |= O_APPEND as c_int,
          Create => fflags |= O_CREAT as c_int,
          Truncate => fflags |= O_TRUNC as c_int,
          NoFlag => ()
1301 1302
        }
    }
1303 1304 1305 1306 1307
    let fd = unsafe {
        do os::as_c_charp(path.to_str()) |pathbuf| {
            libc::open(pathbuf, fflags,
                       (S_IRUSR | S_IWUSR) as c_int)
        }
1308 1309
    };
    if fd < (0 as c_int) {
1310
        result::Err(fmt!("error opening %s: %s", path.to_str(),
1311
                         os::last_os_error()))
1312
    } else {
1313
        result::Ok(fd_writer(fd, true))
1314 1315 1316
    }
}

1317
pub fn u64_to_le_bytes<T>(n: u64, size: uint,
1318
                          f: &fn(v: &[u8]) -> T) -> T {
P
Patrick Walton 已提交
1319
    assert!(size <= 8u);
1320
    match size {
B
Brian Anderson 已提交
1321 1322 1323 1324
      1u => f(&[n as u8]),
      2u => f(&[n as u8,
              (n >> 8) as u8]),
      4u => f(&[n as u8,
1325 1326
              (n >> 8) as u8,
              (n >> 16) as u8,
B
Brian Anderson 已提交
1327 1328
              (n >> 24) as u8]),
      8u => f(&[n as u8,
1329 1330 1331 1332 1333 1334
              (n >> 8) as u8,
              (n >> 16) as u8,
              (n >> 24) as u8,
              (n >> 32) as u8,
              (n >> 40) as u8,
              (n >> 48) as u8,
B
Brian Anderson 已提交
1335 1336
              (n >> 56) as u8]),
      _ => {
1337

1338
        let mut bytes: ~[u8] = ~[], i = size, n = n;
1339
        while i > 0u {
1340
            bytes.push((n & 255_u64) as u8);
1341 1342 1343 1344 1345
            n >>= 8_u64;
            i -= 1u;
        }
        f(bytes)
      }
1346
    }
1347 1348
}

1349
pub fn u64_to_be_bytes<T>(n: u64, size: uint,
1350
                           f: &fn(v: &[u8]) -> T) -> T {
P
Patrick Walton 已提交
1351
    assert!(size <= 8u);
1352
    match size {
B
Brian Anderson 已提交
1353 1354 1355 1356
      1u => f(&[n as u8]),
      2u => f(&[(n >> 8) as u8,
              n as u8]),
      4u => f(&[(n >> 24) as u8,
1357 1358
              (n >> 16) as u8,
              (n >> 8) as u8,
B
Brian Anderson 已提交
1359 1360
              n as u8]),
      8u => f(&[(n >> 56) as u8,
1361 1362 1363 1364 1365 1366
              (n >> 48) as u8,
              (n >> 40) as u8,
              (n >> 32) as u8,
              (n >> 24) as u8,
              (n >> 16) as u8,
              (n >> 8) as u8,
B
Brian Anderson 已提交
1367 1368
              n as u8]),
      _ => {
1369
        let mut bytes: ~[u8] = ~[];
1370 1371 1372
        let mut i = size;
        while i > 0u {
            let shift = ((i - 1u) * 8u) as u64;
1373
            bytes.push((n >> shift) as u8);
1374 1375 1376 1377 1378
            i -= 1u;
        }
        f(bytes)
      }
    }
1379 1380
}

N
Niko Matsakis 已提交
1381
pub fn u64_from_be_bytes(data: &[u8],
1382 1383 1384
                         start: uint,
                         size: uint)
                      -> u64 {
1385
    let mut sz = size;
P
Patrick Walton 已提交
1386
    assert!((sz <= 8u));
1387 1388
    let mut val = 0_u64;
    let mut pos = start;
1389 1390 1391 1392 1393
    while sz > 0u {
        sz -= 1u;
        val += (data[pos] as u64) << ((sz * 8u) as u64);
        pos += 1u;
    }
B
Brian Anderson 已提交
1394
    return val;
1395 1396
}

1397 1398
// FIXME: #3048 combine trait+impl (or just move these to
// default methods on writer)
1399
/// Generic utility functions defined on writers.
1400
pub trait WriterUtil {
1401 1402

    /// Write a single utf-8 encoded char.
1403
    fn write_char(&self, ch: char);
1404 1405

    /// Write every char in the given str, encoded as utf-8.
1406
    fn write_str(&self, s: &str);
1407 1408

    /// Write the given str, as utf-8, followed by '\n'.
1409
    fn write_line(&self, s: &str);
1410 1411

    /// Write the result of passing n through `int::to_str_bytes`.
1412
    fn write_int(&self, n: int);
1413 1414

    /// Write the result of passing n through `uint::to_str_bytes`.
1415
    fn write_uint(&self, n: uint);
1416 1417

    /// Write a little-endian uint (number of bytes depends on system).
1418
    fn write_le_uint(&self, n: uint);
1419 1420

    /// Write a little-endian int (number of bytes depends on system).
1421
    fn write_le_int(&self, n: int);
1422 1423

    /// Write a big-endian uint (number of bytes depends on system).
1424
    fn write_be_uint(&self, n: uint);
1425 1426

    /// Write a big-endian int (number of bytes depends on system).
1427
    fn write_be_int(&self, n: int);
1428 1429

    /// Write a big-endian u64 (8 bytes).
1430
    fn write_be_u64(&self, n: u64);
1431 1432

    /// Write a big-endian u32 (4 bytes).
1433
    fn write_be_u32(&self, n: u32);
1434 1435

    /// Write a big-endian u16 (2 bytes).
1436
    fn write_be_u16(&self, n: u16);
1437 1438

    /// Write a big-endian i64 (8 bytes).
1439
    fn write_be_i64(&self, n: i64);
1440 1441

    /// Write a big-endian i32 (4 bytes).
1442
    fn write_be_i32(&self, n: i32);
1443 1444

    /// Write a big-endian i16 (2 bytes).
1445
    fn write_be_i16(&self, n: i16);
1446

1447 1448 1449 1450 1451 1452
    /// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
    fn write_be_f64(&self, f: f64);

    /// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
    fn write_be_f32(&self, f: f32);

1453
    /// Write a little-endian u64 (8 bytes).
1454
    fn write_le_u64(&self, n: u64);
1455 1456

    /// Write a little-endian u32 (4 bytes).
1457
    fn write_le_u32(&self, n: u32);
1458 1459

    /// Write a little-endian u16 (2 bytes).
1460
    fn write_le_u16(&self, n: u16);
1461 1462

    /// Write a little-endian i64 (8 bytes).
1463
    fn write_le_i64(&self, n: i64);
1464 1465

    /// Write a little-endian i32 (4 bytes).
1466
    fn write_le_i32(&self, n: i32);
1467 1468

    /// Write a little-endian i16 (2 bytes).
1469
    fn write_le_i16(&self, n: i16);
1470

1471 1472 1473 1474 1475 1476 1477 1478
    /// Write a little-endian IEEE754 double-precision floating-point
    /// (8 bytes).
    fn write_le_f64(&self, f: f64);

    /// Write a litten-endian IEEE754 single-precision floating-point
    /// (4 bytes).
    fn write_le_f32(&self, f: f32);

1479
    /// Write a u8 (1 byte).
1480
    fn write_u8(&self, n: u8);
1481 1482

    /// Write a i8 (1 byte).
1483
    fn write_i8(&self, n: i8);
1484 1485
}

1486
impl<T:Writer> WriterUtil for T {
1487
    fn write_char(&self, ch: char) {
1488
        if (ch as uint) < 128u {
1489
            self.write(&[ch as u8]);
M
Marijn Haverbeke 已提交
1490
        } else {
1491
            self.write_str(str::from_char(ch));
M
Marijn Haverbeke 已提交
1492
        }
1493
    }
1494 1495
    fn write_str(&self, s: &str) { str::byte_slice(s, |v| self.write(v)) }
    fn write_line(&self, s: &str) {
1496
        self.write_str(s);
1497
        self.write_str(&"\n");
1498
    }
1499
    fn write_int(&self, n: int) {
1500
        int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
1501
    }
1502
    fn write_uint(&self, n: uint) {
1503
        uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
1504
    }
1505
    fn write_le_uint(&self, n: uint) {
1506
        u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
1507
    }
1508
    fn write_le_int(&self, n: int) {
1509
        u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
1510
    }
1511
    fn write_be_uint(&self, n: uint) {
1512
        u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
1513
    }
1514
    fn write_be_int(&self, n: int) {
1515
        u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
1516
    }
1517
    fn write_be_u64(&self, n: u64) {
B
Brian Anderson 已提交
1518
        u64_to_be_bytes(n, 8u, |v| self.write(v))
1519
    }
1520
    fn write_be_u32(&self, n: u32) {
B
Brian Anderson 已提交
1521
        u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
1522
    }
1523
    fn write_be_u16(&self, n: u16) {
B
Brian Anderson 已提交
1524
        u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
1525
    }
1526
    fn write_be_i64(&self, n: i64) {
B
Brian Anderson 已提交
1527
        u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
1528
    }
1529
    fn write_be_i32(&self, n: i32) {
B
Brian Anderson 已提交
1530
        u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
1531
    }
1532
    fn write_be_i16(&self, n: i16) {
B
Brian Anderson 已提交
1533
        u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
1534
    }
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
    fn write_be_f64(&self, f:f64) {
        unsafe {
            self.write_be_u64(cast::transmute(f))
        }
    }
    fn write_be_f32(&self, f:f32) {
        unsafe {
            self.write_be_u32(cast::transmute(f))
        }
    }
1545
    fn write_le_u64(&self, n: u64) {
B
Brian Anderson 已提交
1546
        u64_to_le_bytes(n, 8u, |v| self.write(v))
1547
    }
1548
    fn write_le_u32(&self, n: u32) {
B
Brian Anderson 已提交
1549
        u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
1550
    }
1551
    fn write_le_u16(&self, n: u16) {
B
Brian Anderson 已提交
1552
        u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
1553
    }
1554
    fn write_le_i64(&self, n: i64) {
B
Brian Anderson 已提交
1555
        u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
1556
    }
1557
    fn write_le_i32(&self, n: i32) {
B
Brian Anderson 已提交
1558
        u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
1559
    }
1560
    fn write_le_i16(&self, n: i16) {
B
Brian Anderson 已提交
1561
        u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
1562
    }
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
    fn write_le_f64(&self, f:f64) {
        unsafe {
            self.write_le_u64(cast::transmute(f))
        }
    }
    fn write_le_f32(&self, f:f32) {
        unsafe {
            self.write_le_u32(cast::transmute(f))
        }
    }
1573

1574 1575
    fn write_u8(&self, n: u8) { self.write([n]) }
    fn write_i8(&self, n: i8) { self.write([n as u8]) }
1576

1577 1578
}

1579
#[allow(non_implicitly_copyable_typarams)]
1580
pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
B
Brian Anderson 已提交
1581
    mk_file_writer(path, flags).chain(|w| result::Ok(w))
1582 1583 1584
}


1585
// FIXME: fileflags // #2004
1586
pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
1587 1588 1589 1590 1591 1592
    unsafe {
        let f = do os::as_c_charp(path.to_str()) |pathbuf| {
            do os::as_c_charp("w") |modebuf| {
                libc::fopen(pathbuf, modebuf)
            }
        };
1593 1594 1595 1596 1597
        return if f as uint == 0u {
            result::Err(~"error opening " + path.to_str())
        } else {
            result::Ok(FILE_writer(f, true))
        }
1598
    }
1599 1600
}

1601 1602 1603
// FIXME (#2004) it would be great if this could be a const
// FIXME (#2004) why are these different from the way stdin() is
// implemented?
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614


/**
* Gives a `Writer` which allows you to write to the standard output.
*
* # Examples
* ~~~
* let stdout = core::io::stdout();
* stdout.write_str("hello\n");
* ~~~
*/
1615
pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625

/**
* Gives a `Writer` which allows you to write to standard error.
*
* # Examples
* ~~~
* let stderr = core::io::stderr();
* stderr.write_str("hello\n");
* ~~~
*/
1626
pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
1627

1628 1629
/**
* Prints a string to standard output.
S
Steve Klabnik 已提交
1630
*
1631 1632 1633 1634 1635
* This string will not have an implicit newline at the end. If you want
* an implicit newline, please see `println`.
*
* # Examples
* ~~~
1636 1637
* // print is imported into the prelude, and so is always available.
* print("hello");
1638 1639
* ~~~
*/
1640 1641 1642 1643
pub fn print(s: &str) {
    stdout().write_str(s);
}

1644 1645
/**
* Prints a string to standard output, followed by a newline.
S
Steve Klabnik 已提交
1646
*
1647 1648 1649 1650
* If you do not want an implicit newline, please see `print`.
*
* # Examples
* ~~~
1651 1652
* // println is imported into the prelude, and so is always available.
* println("hello");
1653 1654
* ~~~
*/
1655 1656 1657
pub fn println(s: &str) {
    stdout().write_line(s);
}
1658

1659
pub struct BytesWriter {
1660 1661
    bytes: @mut ~[u8],
    pos: @mut uint,
1662
}
1663

1664
impl Writer for BytesWriter {
N
Niko Matsakis 已提交
1665
    fn write(&self, v: &[u8]) {
1666
        let v_len = v.len();
1667

P
Patrick Walton 已提交
1668 1669 1670
        let bytes = &mut *self.bytes;
        let count = uint::max(bytes.len(), *self.pos + v_len);
        vec::reserve(bytes, count);
N
Niko Matsakis 已提交
1671

1672
        unsafe {
P
Patrick Walton 已提交
1673 1674 1675 1676 1677
            // Silly stage0 borrow check workaround...
            let casted: &mut ~[u8] = cast::transmute_copy(&bytes);
            vec::raw::set_len(casted, count);

            let view = vec::mut_slice(*bytes, *self.pos, count);
1678
            vec::bytes::copy_memory(view, v, v_len);
1679
        }
1680

1681
        *self.pos += v_len;
1682
    }
1683

1684
    fn seek(&self, offset: int, whence: SeekStyle) {
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
        let pos = *self.pos;
        let len = vec::uniq_len(&const *self.bytes);
        *self.pos = seek_in_buf(offset, pos, len, whence);
    }

    fn tell(&self) -> uint {
        *self.pos
    }

    fn flush(&self) -> int {
        0
    }

    fn get_type(&self) -> WriterType {
        File
1700
    }
1701 1702
}

1703
pub fn BytesWriter() -> BytesWriter {
1704 1705 1706 1707
    BytesWriter {
        bytes: @mut ~[],
        pos: @mut 0
    }
1708
}
1709

1710
pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] {
1711
    let wr = @BytesWriter();
1712
    f(wr as @Writer);
1713 1714
    let @BytesWriter { bytes, _ } = wr;
    copy *bytes
E
Erick Tryzelaar 已提交
1715
}
1716

1717
pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
1718 1719
    let mut v = with_bytes_writer(f);

1720 1721
    // Make sure the vector has a trailing null and is proper utf8.
    v.push(0);
P
Patrick Walton 已提交
1722
    assert!(str::is_utf8(v));
1723

1724 1725 1726
    unsafe {
        ::cast::transmute(v)
    }
1727
}
1728 1729

// Utility functions
1730
pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
M
Marijn Haverbeke 已提交
1731
   uint {
1732
    let mut bpos = pos as int;
M
Marijn Haverbeke 已提交
1733
    let blen = len as int;
1734
    match whence {
1735 1736 1737
      SeekSet => bpos = offset,
      SeekCur => bpos += offset,
      SeekEnd => bpos = blen + offset
1738
    }
B
Brian Anderson 已提交
1739
    if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; }
B
Brian Anderson 已提交
1740
    return bpos as uint;
1741
}
1742

1743
#[allow(non_implicitly_copyable_typarams)]
1744
pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
B
Brian Anderson 已提交
1745
    result::chain(read_whole_file(file), |bytes| {
1746
        if str::is_utf8(bytes) {
1747
            result::Ok(str::from_bytes(bytes))
1748
       } else {
1749
           result::Err(file.to_str() + ~" is not UTF-8")
1750
       }
1751
    })
1752 1753
}

1754 1755
// FIXME (#2004): implement this in a low-level way. Going through the
// abstractions is pointless.
1756
#[allow(non_implicitly_copyable_typarams)]
1757
pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
B
Brian Anderson 已提交
1758
    result::chain(file_reader(file), |rdr| {
1759
        result::Ok(rdr.read_whole_stream())
1760
    })
1761 1762
}

1763 1764
// fsync related

1765
pub mod fsync {
1766
    use io::{FILERes, FdRes, fd_t};
1767
    use kinds::Copy;
1768
    use libc;
1769 1770
    use ops::Drop;
    use option::{None, Option, Some};
1771
    use os;
1772

1773
    pub enum Level {
1774
        // whatever fsync does on that platform
1775
        FSync,
1776 1777

        // fdatasync on linux, similiar or more on other platforms
1778
        FDataSync,
1779 1780 1781 1782

        // full fsync
        //
        // You must additionally sync the parent directory as well!
1783
        FullFSync,
1784 1785 1786
    }


1787
    // Artifacts that need to fsync on destruction
1788
    pub struct Res<t> {
1789
        arg: Arg<t>,
1790 1791
    }

1792
    #[unsafe_destructor]
1793
    impl<T:Copy> Drop for Res<T> {
1794
        fn finalize(&self) {
1795 1796 1797 1798
            match self.arg.opt_level {
                None => (),
                Some(level) => {
                  // fail hard if not succesful
P
Patrick Walton 已提交
1799
                  assert!(((self.arg.fsync_fn)(self.arg.val, level)
1800 1801
                    != -1));
                }
1802
            }
1803 1804 1805
        }
    }

T
Tim Chevalier 已提交
1806
    pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{
B
Brian Anderson 已提交
1807
        Res {
L
Luqman Aden 已提交
1808
            arg: arg
B
Brian Anderson 已提交
1809 1810 1811
        }
    }

1812
    pub struct Arg<t> {
1813
        val: t,
B
Brian Anderson 已提交
1814
        opt_level: Option<Level>,
1815
        fsync_fn: @fn(f: t, Level) -> int,
1816
    }
1817 1818

    // fsync file after executing blk
1819 1820
    // FIXME (#2004) find better way to create resources within lifetime of
    // outer res
1821
    pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
1822
                         blk: &fn(v: Res<*libc::FILE>)) {
1823 1824 1825 1826 1827
        blk(Res(Arg {
            val: file.f, opt_level: opt_level,
            fsync_fn: |file, l| {
                unsafe {
                    os::fsync_fd(libc::fileno(file), l) as int
1828
                }
1829 1830
            }
        }));
1831 1832 1833
    }

    // fsync fd after executing blk
1834
    pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
1835
                       blk: &fn(v: Res<fd_t>)) {
1836
        blk(Res(Arg {
1837
            val: fd.fd, opt_level: opt_level,
1838
            fsync_fn: |fd, l| os::fsync_fd(fd, l) as int
1839 1840 1841 1842
        }));
    }

    // Type of objects that may want to fsync
1843
    pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
1844 1845

    // Call o.fsync after executing blk
1846 1847
    pub fn obj_sync(o: @FSyncable, opt_level: Option<Level>,
                    blk: &fn(v: Res<@FSyncable>)) {
1848
        blk(Res(Arg {
1849
            val: o, opt_level: opt_level,
1850
            fsync_fn: |o, l| o.fsync(l)
1851 1852 1853
        }));
    }
}
1854

1855 1856
#[cfg(test)]
mod tests {
1857
    use i32;
1858
    use io::{BytesWriter, SeekCur, SeekEnd, SeekSet};
1859
    use io;
1860
    use path::Path;
1861 1862 1863 1864
    use result;
    use str;
    use u64;
    use vec;
1865 1866 1867

    #[test]
    fn test_simple() {
1868
        let tmpfile = &Path("tmp/lib-io-test-simple.tmp");
B
Brian Anderson 已提交
1869
        debug!(tmpfile);
1870 1871
        let frood: ~str =
            ~"A hoopy frood who really knows where his towel is.";
B
Brian Anderson 已提交
1872
        debug!(copy frood);
1873
        {
1874
            let out: @io::Writer =
1875
                result::get(
B
Brian Anderson 已提交
1876
                    &io::file_writer(tmpfile, ~[io::Create, io::Truncate]));
1877 1878
            out.write_str(frood);
        }
1879
        let inp: @io::Reader = result::get(&io::file_reader(tmpfile));
1880
        let frood2: ~str = inp.read_c_str();
B
Brian Anderson 已提交
1881
        debug!(copy frood2);
1882
        assert_eq!(frood, frood2);
1883 1884 1885 1886
    }

    #[test]
    fn test_readchars_empty() {
1887
        do io::with_str_reader(~"") |inp| {
1888
            let res : ~[char] = inp.read_chars(128);
1889
            assert_eq!(res.len(), 0);
1890
        }
1891 1892
    }

1893 1894 1895 1896
    #[test]
    fn test_read_line_utf8() {
        do io::with_str_reader(~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤") |inp| {
            let line = inp.read_line();
1897
            assert_eq!(line, ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤");
1898 1899 1900
        }
    }

1901 1902 1903
    #[test]
    fn test_read_lines() {
        do io::with_str_reader(~"a\nb\nc\n") |inp| {
1904
            assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]);
1905 1906 1907
        }

        do io::with_str_reader(~"a\nb\nc") |inp| {
1908
            assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]);
1909 1910 1911
        }

        do io::with_str_reader(~"") |inp| {
P
Patrick Walton 已提交
1912
            assert!(inp.read_lines().is_empty());
1913 1914 1915
        }
    }

1916 1917
    #[test]
    fn test_readchars_wide() {
1918
        let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤";
1919
        let ivals : ~[int] = ~[
1920 1921 1922 1923
            29983, 38152, 30340, 27748,
            21273, 20999, 32905, 27748,
            104, 101, 108, 108, 111,
            29983, 38152, 30340, 27748,
1924
            21273, 20999, 32905, 27748];
1925
        fn check_read_ln(len : uint, s: &str, ivals: &[int]) {
1926 1927
            do io::with_str_reader(s) |inp| {
                let res : ~[char] = inp.read_chars(len);
Y
Youngmin Yoo 已提交
1928
                if len <= ivals.len() {
1929
                    assert_eq!(res.len(), len);
1930
                }
Y
Youngmin Yoo 已提交
1931
                assert!(vec::slice(ivals, 0u, res.len()) ==
1932
                             vec::map(res, |x| *x as int));
1933 1934
            }
        }
1935 1936
        let mut i = 0;
        while i < 8 {
1937
            check_read_ln(i, wide_test, ivals);
1938
            i += 1;
1939 1940
        }
        // check a long read for good measure
1941
        check_read_ln(128, wide_test, ivals);
1942 1943 1944 1945
    }

    #[test]
    fn test_readchar() {
1946 1947
        do io::with_str_reader(~"生") |inp| {
            let res : char = inp.read_char();
1948
            assert_eq!(res as int, 29983);
1949
        }
1950 1951 1952 1953
    }

    #[test]
    fn test_readchar_empty() {
1954 1955
        do io::with_str_reader(~"") |inp| {
            let res : char = inp.read_char();
1956
            assert_eq!(res as int, -1);
1957
        }
1958 1959 1960 1961
    }

    #[test]
    fn file_reader_not_exist() {
1962
        match io::file_reader(&Path("not a file")) {
B
Brian Anderson 已提交
1963
          result::Err(copy e) => {
1964
            assert_eq!(e, ~"error opening not a file");
1965
          }
1966
          result::Ok(_) => fail!()
1967 1968 1969
        }
    }

1970 1971
    #[test]
    #[should_fail]
1972
    #[ignore(cfg(windows))]
1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
    fn test_read_buffer_too_small() {
        let path = &Path("tmp/lib-io-test-read-buffer-too-small.tmp");
        // ensure the file exists
        io::file_writer(path, [io::Create]).get();

        let file = io::file_reader(path).get();
        let mut buf = vec::from_elem(5, 0);
        file.read(buf, 6); // this should fail because buf is too small
    }

    #[test]
    fn test_read_buffer_big_enough() {
        let path = &Path("tmp/lib-io-test-read-buffer-big-enough.tmp");
        // ensure the file exists
        io::file_writer(path, [io::Create]).get();

        let file = io::file_reader(path).get();
        let mut buf = vec::from_elem(5, 0);
        file.read(buf, 4); // this should succeed because buf is big enough
    }

1994 1995 1996 1997 1998 1999 2000
    #[test]
    fn test_write_empty() {
        let file = io::file_writer(&Path("tmp/lib-io-test-write-empty.tmp"),
                                   [io::Create]).get();
        file.write([]);
    }

2001 2002
    #[test]
    fn file_writer_bad_name() {
2003
        match io::file_writer(&Path("?/?"), ~[]) {
B
Brian Anderson 已提交
2004
          result::Err(copy e) => {
P
Patrick Walton 已提交
2005
            assert!(str::starts_with(e, "error opening"));
2006
          }
2007
          result::Ok(_) => fail!()
2008 2009 2010 2011 2012
        }
    }

    #[test]
    fn buffered_file_writer_bad_name() {
2013
        match io::buffered_file_writer(&Path("?/?")) {
B
Brian Anderson 已提交
2014
          result::Err(copy e) => {
P
Patrick Walton 已提交
2015
            assert!(str::starts_with(e, "error opening"));
2016
          }
2017
          result::Ok(_) => fail!()
2018 2019
        }
    }
N
Niko Matsakis 已提交
2020 2021

    #[test]
2022 2023 2024
    fn bytes_buffer_overwrite() {
        let wr = BytesWriter();
        wr.write(~[0u8, 1u8, 2u8, 3u8]);
P
Patrick Walton 已提交
2025
        assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]);
2026 2027
        wr.seek(-2, SeekCur);
        wr.write(~[4u8, 5u8, 6u8, 7u8]);
P
Patrick Walton 已提交
2028
        assert!(*wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]);
2029 2030 2031 2032
        wr.seek(-2, SeekEnd);
        wr.write(~[8u8]);
        wr.seek(1, SeekSet);
        wr.write(~[9u8]);
P
Patrick Walton 已提交
2033
        assert!(*wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
N
Niko Matsakis 已提交
2034
    }
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052

    #[test]
    fn test_read_write_le() {
        let path = Path("tmp/lib-io-test-read-write-le.tmp");
        let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];

        // write the ints to the file
        {
            let file = io::file_writer(&path, [io::Create]).get();
            for uints.each |i| {
                file.write_le_u64(*i);
            }
        }

        // then read them back and check that they are the same
        {
            let file = io::file_reader(&path).get();
            for uints.each |i| {
2053
                assert_eq!(file.read_le_u64(), *i);
2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
            }
        }
    }

    #[test]
    fn test_read_write_be() {
        let path = Path("tmp/lib-io-test-read-write-be.tmp");
        let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];

        // write the ints to the file
        {
            let file = io::file_writer(&path, [io::Create]).get();
            for uints.each |i| {
                file.write_be_u64(*i);
            }
        }

        // then read them back and check that they are the same
        {
            let file = io::file_reader(&path).get();
            for uints.each |i| {
2075
                assert_eq!(file.read_be_u64(), *i);
2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
            }
        }
    }

    #[test]
    fn test_read_be_int_n() {
        let path = Path("tmp/lib-io-test-read-be-int-n.tmp");
        let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value];

        // write the ints to the file
        {
            let file = io::file_writer(&path, [io::Create]).get();
            for ints.each |i| {
                file.write_be_i32(*i);
            }
        }

        // then read them back and check that they are the same
        {
            let file = io::file_reader(&path).get();
            for ints.each |i| {
                // this tests that the sign extension is working
                // (comparing the values as i32 would not test this)
2099
                assert_eq!(file.read_be_int_n(4), *i as i64);
2100 2101 2102 2103
            }
        }
    }

2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
    #[test]
    fn test_read_f32() {
        let path = Path("tmp/lib-io-test-read-f32.tmp");
        //big-endian floating-point 8.1250
        let buf = ~[0x41, 0x02, 0x00, 0x00];

        {
            let file = io::file_writer(&path, [io::Create]).get();
            file.write(buf);
        }

        {
            let file = io::file_reader(&path).get();
            let f = file.read_be_f32();
2118
            assert_eq!(f, 8.1250);
2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
        }
    }

#[test]
    fn test_read_write_f32() {
        let path = Path("tmp/lib-io-test-read-write-f32.tmp");
        let f:f32 = 8.1250;

        {
            let file = io::file_writer(&path, [io::Create]).get();
            file.write_be_f32(f);
            file.write_le_f32(f);
        }

        {
            let file = io::file_reader(&path).get();
2135 2136
            assert_eq!(file.read_be_f32(), 8.1250);
            assert_eq!(file.read_le_f32(), 8.1250);
2137 2138
        }
    }
2139
}