module io // Reader represents a stream of data that can be read pub interface Reader { // read reads up to buf.len bytes and places // them into buf. // A type that implements this should return // `none` on end of stream (EOF) instead of just returning 0 read(mut buf []byte) ?int } // make_reader is a temp that converts a type to a reader // (e.g. for use in struct initialisation) // (this shouldnt need to be a thing but until coercion gets made better // it is required) pub fn make_reader(r Reader) Reader { return r } const ( read_all_len = 10 * 1024 read_all_grow_len = 1024 ) // ReadAllConfig allows options to be passed for the behaviour // of read_all pub struct ReadAllConfig { reader Reader read_to_end_of_stream bool } // read_all reads all bytes from a reader until either a 0 length read // or if read_to_end_of_stream is true then the end of the stream (`none`) pub fn read_all(config ReadAllConfig) ?[]byte { r := config.reader read_till_eof := config.read_to_end_of_stream mut b := []byte{len: read_all_len} mut read := 0 for { new_read := r.read(mut b[read..]) or { break } read += new_read if !read_till_eof && read == 0 { break } if b.len == read { unsafe { b.grow_len(read_all_grow_len) } } } return b[..read] } // read_any reads any available bytes from a reader // (until the reader returns a read of 0 length) pub fn read_any(r Reader) ?[]byte { mut b := []byte{len: read_all_len} mut read := 0 for { new_read := r.read(mut b[read..]) or { break } read += new_read if new_read == 0 { break } if b.len == read { unsafe { b.grow_len(read_all_grow_len) } } } return b[..read] } // RandomReader represents a stream of data that can be read from at a random location interface RandomReader { read_from(pos int, mut buf []byte) ?int }