diff --git a/vlib/io/buffered_reader.v b/vlib/io/buffered_reader.v index 9ffb73548d..cf25a4f5f5 100644 --- a/vlib/io/buffered_reader.v +++ b/vlib/io/buffered_reader.v @@ -36,20 +36,23 @@ pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader { } // read fufills the Reader interface -pub fn (mut r BufferedReader) read(mut buf []u8) ?int { +pub fn (mut r BufferedReader) read(mut buf []u8) !int { if r.end_of_stream { - return none + return IError(Eof{}) } // read data out of the buffer if we dont have any if r.needs_fill() { if !r.fill_buffer() { // end of stream - return none + return IError(Eof{}) } } read := copy(mut buf, r.buf[r.offset..r.len]) if read == 0 { - return none + return IError(NotExpected{ + cause: 'invalid copy of buffer' + code: -1 + }) } r.offset += read return read diff --git a/vlib/io/custom_string_reading_test.v b/vlib/io/custom_string_reading_test.v index 87db85f1e4..f0b2f901bd 100644 --- a/vlib/io/custom_string_reading_test.v +++ b/vlib/io/custom_string_reading_test.v @@ -10,12 +10,12 @@ fn imin(a int, b int) int { return if a < b { a } else { b } } -fn (mut s StringReader) read(mut buf []u8) ?int { +fn (mut s StringReader) read(mut buf []u8) !int { $if debug { eprintln('>>>> StringReader.read output buf.len: $buf.len') } if s.place > s.text.len + 1 { - return none + return IError(io.Eof{}) } mut howmany := imin(buf.len, s.text.len - s.place) xxx := s.text[s.place..s.place + howmany].bytes() diff --git a/vlib/io/io_test.v b/vlib/io/io_test.v index 194e61d82e..70c0c6d26e 100644 --- a/vlib/io/io_test.v +++ b/vlib/io/io_test.v @@ -12,9 +12,9 @@ pub mut: bytes []u8 } -fn (mut b Buf) read(mut buf []u8) ?int { +fn (mut b Buf) read(mut buf []u8) !int { if !(b.i < b.bytes.len) { - return none + return IError(io.Eof{}) } n := copy(mut buf, b.bytes[b.i..]) b.i += n diff --git a/vlib/io/reader.v b/vlib/io/reader.v index fc729b832e..6bcc77942f 100644 --- a/vlib/io/reader.v +++ b/vlib/io/reader.v @@ -1,13 +1,32 @@ module io +/// Eof error means that we reach the end of the stream. +pub struct Eof { + Error +} + +// NotExpected is a generic error that means that we receave a not expecte error. +pub struct NotExpected { + cause string + code int +} + +fn (err NotExpected) msg() string { + return err.cause +} + +fn (err NotExpected) code() int { + return err.code +} + // 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 + // `io.Eof` on end of stream (EOF) instead of just returning 0 mut: - read(mut buf []u8) ?int + read(mut buf []u8) !int } const ( @@ -50,7 +69,7 @@ pub fn read_any(mut r Reader) ?[]u8 { mut b := []u8{len: io.read_all_len} mut read := 0 for { - new_read := r.read(mut b[read..]) or { break } + new_read := r.read(mut b[read..]) or { return none } read += new_read if new_read == 0 { break diff --git a/vlib/io/reader_test.v b/vlib/io/reader_test.v index 9cc7b35c24..3e7f72f64b 100644 --- a/vlib/io/reader_test.v +++ b/vlib/io/reader_test.v @@ -7,9 +7,9 @@ mut: i int } -fn (mut b Buf) read(mut buf []u8) ?int { +fn (mut b Buf) read(mut buf []u8) !int { if !(b.i < b.bytes.len) { - return none + return IError(Eof{}) } n := copy(mut buf, b.bytes[b.i..]) b.i += n @@ -44,9 +44,9 @@ mut: place int } -fn (mut s StringReader) read(mut buf []u8) ?int { +fn (mut s StringReader) read(mut buf []u8) !int { if s.place >= s.text.len { - return none + return IError(Eof{}) } read := copy(mut buf, s.text[s.place..].bytes()) s.place += read diff --git a/vlib/io/readerwriter.v b/vlib/io/readerwriter.v index ac77500578..b03c891a09 100644 --- a/vlib/io/readerwriter.v +++ b/vlib/io/readerwriter.v @@ -14,7 +14,7 @@ mut: w Writer } -pub fn (mut r ReaderWriterImpl) read(mut buf []u8) ?int { +pub fn (mut r ReaderWriterImpl) read(mut buf []u8) !int { return r.r.read(mut buf) } diff --git a/vlib/net/http/request_test.v b/vlib/net/http/request_test.v index 1ab43d87de..98fe941f79 100644 --- a/vlib/net/http/request_test.v +++ b/vlib/net/http/request_test.v @@ -8,9 +8,9 @@ mut: place int } -fn (mut s StringReader) read(mut buf []u8) ?int { +fn (mut s StringReader) read(mut buf []u8) !int { if s.place >= s.text.len { - return none + return IError(io.Eof{}) } max_bytes := 100 end := if s.place + max_bytes >= s.text.len { s.text.len } else { s.place + max_bytes } diff --git a/vlib/net/openssl/ssl_connection.v b/vlib/net/openssl/ssl_connection.v index 3de3c92ca8..78737bfd0d 100644 --- a/vlib/net/openssl/ssl_connection.v +++ b/vlib/net/openssl/ssl_connection.v @@ -180,8 +180,8 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int { return res } -pub fn (mut s SSLConn) read(mut buffer []u8) ?int { - res := s.socket_read_into_ptr(&u8(buffer.data), buffer.len)? +pub fn (mut s SSLConn) read(mut buffer []u8) !int { + res := s.socket_read_into_ptr(&u8(buffer.data), buffer.len) or { return err } return res } diff --git a/vlib/net/tcp.v b/vlib/net/tcp.v index 606469de18..b04c3de933 100644 --- a/vlib/net/tcp.v +++ b/vlib/net/tcp.v @@ -1,6 +1,7 @@ module net import time +import io import strings const ( @@ -132,8 +133,13 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int { return none } -pub fn (c TcpConn) read(mut buf []u8) ?int { - return c.read_ptr(buf.data, buf.len) +pub fn (c TcpConn) read(mut buf []u8) !int { + return c.read_ptr(buf.data, buf.len) or { + return IError(io.NotExpected{ + cause: 'unexpected error in `read_ptr` function' + code: -1 + }) + } } pub fn (mut c TcpConn) read_deadline() ?time.Time { diff --git a/vlib/net/websocket/io.v b/vlib/net/websocket/io.v index 4606304a6a..b0cebd0b16 100644 --- a/vlib/net/websocket/io.v +++ b/vlib/net/websocket/io.v @@ -9,10 +9,10 @@ fn (mut ws Client) socket_read(mut buffer []u8) ?int { return error('socket_read: trying to read a closed socket') } if ws.is_ssl { - r := ws.ssl_conn.read(mut buffer)? + r := ws.ssl_conn.read(mut buffer) or { return none } return r } else { - r := ws.conn.read(mut buffer)? + r := ws.conn.read(mut buffer) or { return none } return r } } diff --git a/vlib/os/file.c.v b/vlib/os/file.c.v index db4add5c3c..7ed7897c4b 100644 --- a/vlib/os/file.c.v +++ b/vlib/os/file.c.v @@ -1,5 +1,24 @@ module os +/// Eof error means that we reach the end of the file. +pub struct Eof { + Error +} + +// NotExpected is a generic error that means that we receave a not expecte error. +pub struct NotExpected { + cause string + code int +} + +fn (err NotExpected) msg() string { + return err.cause +} + +fn (err NotExpected) code() int { + return err.code +} + pub struct File { mut: cfile voidptr // Using void* instead of FILE* @@ -192,11 +211,16 @@ pub fn (mut f File) reopen(path string, mode string) ? { } // read implements the Reader interface. -pub fn (f &File) read(mut buf []u8) ?int { +pub fn (f &File) read(mut buf []u8) !int { if buf.len == 0 { - return 0 + return IError(Eof{}) + } + nbytes := fread(buf.data, 1, buf.len, f.cfile) or { + return IError(NotExpected{ + cause: 'unexpected error from fread' + code: -1 + }) } - nbytes := fread(buf.data, 1, buf.len, f.cfile)? return nbytes } diff --git a/vlib/os/file_test.v b/vlib/os/file_test.v index 7acf45d88e..d1392cd6c2 100644 --- a/vlib/os/file_test.v +++ b/vlib/os/file_test.v @@ -130,11 +130,11 @@ fn test_read_eof_last_read_partial_buffer_fill() ? { f = os.open_file(tfile, 'r')? mut br := []u8{len: 100} // Read first 100 bytes of 199 byte file, should fill buffer with no error. - n0 := f.read(mut br)? + n0 := f.read(mut br) or { return error('failed to read 100 bytes') } assert n0 == 100 // Read remaining 99 bytes of 199 byte file, should fill buffer with no // error, even though end-of-file was reached. - n1 := f.read(mut br)? + n1 := f.read(mut br) or { return error('failed to read 100 bytes') } assert n1 == 99 // Read again, end-of-file was previously reached so should return none // error. @@ -143,8 +143,8 @@ fn test_read_eof_last_read_partial_buffer_fill() ? { // not return a number of bytes read when end-of-file is reached. assert false } else { - // Expect none to have been returned when end-of-file. - assert err is none + // Expected an error when received end-of-file. + assert err !is none } f.close() } @@ -162,11 +162,11 @@ fn test_read_eof_last_read_full_buffer_fill() ? { f = os.open_file(tfile, 'r')? mut br := []u8{len: 100} // Read first 100 bytes of 200 byte file, should fill buffer with no error. - n0 := f.read(mut br)? + n0 := f.read(mut br) or { return error('failed to read 100 bytes') } assert n0 == 100 // Read remaining 100 bytes of 200 byte file, should fill buffer with no // error. The end-of-file isn't reached yet, but there is no more data. - n1 := f.read(mut br)? + n1 := f.read(mut br) or { return error('failed to read 100 bytes') } assert n1 == 100 // Read again, end-of-file was previously reached so should return none // error. @@ -175,8 +175,8 @@ fn test_read_eof_last_read_full_buffer_fill() ? { // not return a number of bytes read when end-of-file is reached. assert false } else { - // Expect none to have been returned when end-of-file. - assert err is none + // Expect an error at EOF. + assert err !is none } f.close() } diff --git a/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v b/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v index 988307e4e6..87a4479f07 100644 --- a/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v +++ b/vlib/v/gen/js/sourcemap/vlq/vlq_decode_test.v @@ -35,9 +35,9 @@ fn test_decode_a() ? { } } -fn (mut b TestReader) read(mut buf []u8) ?int { +fn (mut b TestReader) read(mut buf []u8) !int { if !(b.i < b.bytes.len) { - return none + return IError(io.Eof{}) } n := copy(mut buf, b.bytes[b.i..]) b.i += n