Skip to main content

goish/
io.rs

1// io: Go's io package — Reader/Writer interfaces + Copy/EOF.
2//
3//   Go                                  goish
4//   ─────────────────────────────────   ──────────────────────────────────
5//   n, err := r.Read(buf)               let (n, err) = r.Read(&mut buf);
6//   n, err := w.Write(buf)              let (n, err) = w.Write(buf);
7//   n, err := io.Copy(dst, src)         let (n, err) = io::Copy(&mut dst, &mut src);
8//   if err == io.EOF { ... }            if errors::Is(&err, &io::EOF) { ... }
9//
10// Thin Go-named layer over `std::io::Read` / `std::io::Write`. Any type
11// implementing those std traits automatically satisfies goish's Reader/Writer.
12
13use crate::errors::{error, nil, New};
14use crate::types::{byte, int, int64};
15
16/// io.EOF — returned by Reader.Read when no more input is available.
17/// Compare with errors::Is(&err, &io::EOF).
18pub fn EOF() -> error {
19    New("EOF")
20}
21
22pub trait Reader {
23    fn Read(&mut self, p: &mut [byte]) -> (int, error);
24}
25
26pub trait Writer {
27    fn Write(&mut self, p: &[byte]) -> (int, error);
28}
29
30// Blanket impls: anything that impls std::io::Read is a goish Reader,
31// anything that impls std::io::Write is a goish Writer.
32
33impl<R: std::io::Read + ?Sized> Reader for R {
34    fn Read(&mut self, p: &mut [byte]) -> (int, error) {
35        match std::io::Read::read(self, p) {
36            Ok(0) if !p.is_empty() => (0, EOF()),
37            Ok(n) => (n as int, nil),
38            Err(e) => (0, New(&format!("{}", e))),
39        }
40    }
41}
42
43impl<W: std::io::Write + ?Sized> Writer for W {
44    fn Write(&mut self, p: &[byte]) -> (int, error) {
45        match std::io::Write::write(self, p) {
46            Ok(n) => (n as int, nil),
47            Err(e) => (0, New(&format!("{}", e))),
48        }
49    }
50}
51
52/// io.Copy(dst, src) — stream every byte from src to dst.
53#[allow(non_snake_case)]
54pub fn Copy<W: std::io::Write + ?Sized, R: std::io::Read + ?Sized>(
55    dst: &mut W,
56    src: &mut R,
57) -> (int64, error) {
58    match std::io::copy(src, dst) {
59        Ok(n) => (n as int64, nil),
60        Err(e) => (0, New(&format!("io.Copy: {}", e))),
61    }
62}
63
64/// io.ReadAll(r) — read until EOF, return the full contents.
65#[allow(non_snake_case)]
66pub fn ReadAll<R: std::io::Read + ?Sized>(r: &mut R) -> (Vec<byte>, error) {
67    let mut buf = Vec::new();
68    match r.read_to_end(&mut buf) {
69        Ok(_) => (buf, nil),
70        Err(e) => (buf, New(&format!("io.ReadAll: {}", e))),
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use std::io::Cursor;
78
79    #[test]
80    fn reader_read_from_cursor() {
81        let mut cur = Cursor::new(b"hello".to_vec());
82        let mut buf = [0u8; 5];
83        let (n, err) = cur.Read(&mut buf);
84        assert!(err == nil);
85        assert_eq!(n, 5);
86        assert_eq!(&buf, b"hello");
87    }
88
89    #[test]
90    fn writer_write_to_vec() {
91        let mut v: Vec<u8> = Vec::new();
92        let (n, err) = v.Write(b"abc");
93        assert!(err == nil);
94        assert_eq!(n, 3);
95        assert_eq!(v, b"abc");
96    }
97
98    #[test]
99    fn copy_streams_bytes() {
100        let mut src = Cursor::new(b"payload".to_vec());
101        let mut dst: Vec<u8> = Vec::new();
102        let (n, err) = Copy(&mut dst, &mut src);
103        assert!(err == nil);
104        assert_eq!(n, 7);
105        assert_eq!(dst, b"payload");
106    }
107
108    #[test]
109    fn read_all_returns_full_contents() {
110        let mut src = Cursor::new(b"goish".to_vec());
111        let (buf, err) = ReadAll(&mut src);
112        assert!(err == nil);
113        assert_eq!(buf, b"goish");
114    }
115}