From 9b2c679d2d523305d9ab106b05e649865d6961c6 Mon Sep 17 00:00:00 2001 From: Mikhail Tavarez Date: Thu, 20 Jun 2024 11:48:00 -0500 Subject: [PATCH] cleanup (#46) --- gojo/bufio/__init__.mojo | 2 +- gojo/bufio/bufio.mojo | 182 ++++++++++++++++----------------- gojo/bufio/scan.mojo | 8 +- gojo/bytes/buffer.mojo | 19 ++-- gojo/bytes/reader.mojo | 10 +- gojo/io/__init__.mojo | 20 ++-- gojo/io/file.mojo | 8 +- gojo/io/io.mojo | 9 +- gojo/net/fd.mojo | 2 +- gojo/net/socket.mojo | 39 +++++-- gojo/net/tcp.mojo | 14 ++- gojo/net/udp.mojo | 4 +- gojo/strings/builder.mojo | 12 ++- gojo/strings/reader.mojo | 53 +++++----- gojo/syscall/file.mojo | 3 - tests/test_bufio.mojo | 29 +++--- tests/test_bytes_reader.mojo | 4 +- tests/test_strings_reader.mojo | 18 ++-- 18 files changed, 241 insertions(+), 195 deletions(-) diff --git a/gojo/bufio/__init__.mojo b/gojo/bufio/__init__.mojo index cd20874..2255063 100644 --- a/gojo/bufio/__init__.mojo +++ b/gojo/bufio/__init__.mojo @@ -1,2 +1,2 @@ -from .bufio import Reader, Writer, ReadWriter +from .bufio import Reader, Writer, ReadWriter, new_writer, new_reader, new_read_writer from .scan import Scanner, scan_words, scan_bytes, scan_lines, scan_runes diff --git a/gojo/bufio/bufio.mojo b/gojo/bufio/bufio.mojo index 072d87e..ffe8c79 100644 --- a/gojo/bufio/bufio.mojo +++ b/gojo/bufio/bufio.mojo @@ -16,10 +16,11 @@ alias ERR_NEGATIVE_WRITE = "bufio: writer returned negative count from write" # buffered input -struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): +# TODO: Uncomment write_to and write_buf once the bug with the trait's Span argument is fixed. +struct Reader[R: io.Reader, size: Int = MIN_READ_BUFFER_SIZE](Sized, io.Reader, io.ByteReader, io.ByteScanner): """Implements buffering for an io.Reader object.""" - var buf: InlineList[UInt8, io.BUFFER_SIZE] + var buf: InlineList[UInt8, size] var reader: R # reader provided by the client var read_pos: Int var write_pos: Int # buf read and write positions @@ -31,13 +32,13 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): fn __init__( inout self, owned reader: R, - buf: InlineList[UInt8, io.BUFFER_SIZE] = InlineList[UInt8, io.BUFFER_SIZE](), + buf: InlineList[UInt8, size] = InlineList[UInt8, size](), read_pos: Int = 0, write_pos: Int = 0, last_byte: Int = -1, last_rune_size: Int = -1, ): - self.buf = InlineList[UInt8, io.BUFFER_SIZE]() + self.buf = InlineList[UInt8, size]() for element in buf: self.buf.append(element[]) @@ -50,7 +51,7 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): @always_inline fn __moveinit__(inout self, owned existing: Self): - self.buf = InlineList[UInt8, io.BUFFER_SIZE]() + self.buf = InlineList[UInt8, size]() for element in existing.buf: self.buf.append(element[]) @@ -89,13 +90,13 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): return Span[UInt8, True, __lifetime_of(self)](array=Reference(self.buf._array)) @always_inline - fn reset(inout self, buf: InlineList[UInt8, io.BUFFER_SIZE], owned reader: R): + fn reset(inout self, buf: InlineList[UInt8, size], owned reader: R): """Discards any buffered data, resets all state, and switches the buffered reader to read from r. Calling reset on the zero value of [Reader] initializes the internal buffer to the default size. Calling self.reset(b) (that is, resetting a [Reader] to itself) does nothing.""" - self = Reader[R]( + self = Reader[R, size]( buf=buf, reader=reader^, last_byte=-1, @@ -143,7 +144,7 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): i -= 1 - self.err = Error(io.ERR_NO_PROGRESS) + self.err = Error(str(io.ERR_NO_PROGRESS)) @always_inline fn read_error(inout self) -> Error: @@ -230,7 +231,6 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): To read exactly len(src) bytes, use io.ReadFull(b, src). If the underlying [Reader] can return a non-zero count with io.EOF, then this Read method can do so as well; see the [io.Reader] docs.""" - # TODO: How do we check the capacity of a Span? Or UnsafePointer? if capacity == 0: if self.buffered() > 0: return 0, Error() @@ -582,102 +582,86 @@ struct Reader[R: io.Reader](Sized, io.Reader, io.ByteReader, io.ByteScanner): _ = buf.write(frag) return str(buf), err - fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - """Writes the internal buffer to the writer. This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. - If the underlying reader supports the [Reader.WriteTo] method, - this calls the underlying [Reader.WriteTo] without buffering. - write_to implements io.WriterTo. + # fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): + # """Writes the internal buffer to the writer. This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. + # If the underlying reader supports the [Reader.WriteTo] method, + # this calls the underlying [Reader.WriteTo] without buffering. + # write_to implements io.WriterTo. - Args: - writer: The writer to write to. + # Args: + # writer: The writer to write to. - Returns: - The number of bytes written. - """ - self.last_byte = -1 - self.last_rune_size = -1 + # Returns: + # The number of bytes written. + # """ + # self.last_byte = -1 + # self.last_rune_size = -1 - var bytes_written: Int - var err: Error - bytes_written, err = self.write_buf(writer) - if err: - return bytes_written, err + # var bytes_written: Int + # var err: Error + # bytes_written, err = self.write_buf(writer) + # if err: + # return bytes_written, err - # internal buffer not full, fill before writing to writer - if (self.write_pos - self.read_pos) < io.BUFFER_SIZE: - self.fill() + # # internal buffer not full, fill before writing to writer + # if (self.write_pos - self.read_pos) < io.BUFFER_SIZE: + # self.fill() - while self.read_pos < self.write_pos: - # self.read_pos < self.write_pos => buffer is not empty - var bw: Int - var err: Error - bw, err = self.write_buf(writer) - bytes_written += bw + # while self.read_pos < self.write_pos: + # # self.read_pos < self.write_pos => buffer is not empty + # var bw: Int + # var err: Error + # bw, err = self.write_buf(writer) + # bytes_written += bw - self.fill() # buffer is empty + # self.fill() # buffer is empty - return bytes_written, Error() + # return bytes_written, Error() - fn write_buf[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - """Writes the [Reader]'s buffer to the writer. + # fn write_buf[W: io.Writer](inout self, inout writer: W) -> (Int, Error): + # """Writes the [Reader]'s buffer to the writer. - Args: - writer: The writer to write to. - - Returns: - The number of bytes written. - """ - # Nothing to write - if self.read_pos == self.write_pos: - return Int(0), Error() - - # Write the buffer to the writer, if we hit EOF it's fine. That's not a failure condition. - var bytes_written: Int - var err: Error - var buf_to_write = self.as_bytes_slice()[self.read_pos : self.write_pos] - bytes_written, err = writer.write(buf_to_write) - if err: - return bytes_written, err - - if bytes_written < 0: - panic(ERR_NEGATIVE_WRITE) - - self.read_pos += bytes_written - return Int(bytes_written), Error() + # Args: + # writer: The writer to write to. + # Returns: + # The number of bytes written. + # """ + # # Nothing to write + # if self.read_pos == self.write_pos: + # return Int(0), Error() -# fn new_reader_size[R: io.Reader](owned reader: R, size: Int) -> Reader[R]: -# """Returns a new [Reader] whose buffer has at least the specified -# size. If the argument io.Reader is already a [Reader] with large enough -# size, it returns the underlying [Reader]. + # # Write the buffer to the writer, if we hit EOF it's fine. That's not a failure condition. + # var bytes_written: Int + # var err: Error + # var buf_to_write = self.as_bytes_slice()[self.read_pos : self.write_pos] + # bytes_written, err = writer.write(List[UInt8](buf_to_write)) + # if err: + # return bytes_written, err -# Args: -# reader: The reader to read from. -# size: The size of the buffer. + # if bytes_written < 0: + # panic(ERR_NEGATIVE_WRITE) -# Returns: -# The new [Reader]. -# """ -# # # Is it already a Reader? -# # b, ok := rd.(*Reader) -# # if ok and self.buf.capacity >= size: -# # return b + # self.read_pos += bytes_written + # return Int(bytes_written), Error() -# var r = Reader(reader ^) -# r.reset(InlineList[UInt8, io.BUFFER_SIZE](capacity=max(size, MIN_READ_BUFFER_SIZE)), reader ^) -# return r +fn new_reader[R: io.Reader, size: Int = MIN_READ_BUFFER_SIZE](owned reader: R) -> Reader[R, size]: + """Returns a new [Reader] whose buffer has at least the specified + size. If the argument io.Reader is already a [Reader] with large enough + size, it returns the underlying [Reader]. -# fn new_reader[R: io.Reader](reader: R) -> Reader[R]: -# """Returns a new [Reader] whose buffer has the default size. + Args: + reader: The reader to read from. -# Args: -# reader: The reader to read from. + Params: + size: The size of the buffer. -# Returns: -# The new [Reader]. -# """ -# return new_reader_size(reader, io.BUFFER_SIZE) + Returns: + The new [Reader]. + """ + var r = Reader[R, size](reader^) + return r^ # buffered output @@ -767,7 +751,7 @@ struct Writer[W: io.Writer, size: Int = io.BUFFER_SIZE]( # If the write was short, set a short write error and try to shift up the remaining bytes. if bytes_written < self.bytes_written and not err: - err = Error(io.ERR_SHORT_WRITE) + err = Error(str(io.ERR_SHORT_WRITE)) if err: if bytes_written > 0 and bytes_written < self.bytes_written: @@ -802,7 +786,7 @@ struct Writer[W: io.Writer, size: Int = io.BUFFER_SIZE]( """ return self.bytes_written - fn write(inout self, src: List[UInt8]) -> (Int, Error): + fn _write(inout self, src: Span[UInt8]) -> (Int, Error): """Writes the contents of src into the buffer. It returns the number of bytes written. If nn < len(src), it also returns an error explaining @@ -854,6 +838,22 @@ struct Writer[W: io.Writer, size: Int = io.BUFFER_SIZE]( total_bytes_written += n return total_bytes_written, err + @always_inline + fn write(inout self, src: List[UInt8]) -> (Int, Error): + """ + Appends a byte List to the builder buffer. + + Args: + src: The byte array to append. + """ + var span = Span(src) + + var bytes_read: Int + var err: Error + bytes_read, err = self._write(span) + + return bytes_read, err + @always_inline fn write_byte(inout self, src: UInt8) -> (Int, Error): """Writes a single byte to the internal buffer. @@ -951,14 +951,14 @@ struct Writer[W: io.Writer, size: Int = io.BUFFER_SIZE]( nr += 1 if nr == MAX_CONSECUTIVE_EMPTY_READS: - return bytes_read, Error(io.ERR_NO_PROGRESS) + return bytes_read, io.ERR_NO_PROGRESS self.bytes_written += bytes_read total_bytes_written += bytes_read if err: break - if err and str(err) == io.EOF: + if err and str(err) == str(io.EOF): # If we filled the buffer exactly, flush preemptively. if self.available() == 0: err = self.flush() diff --git a/gojo/bufio/scan.mojo b/gojo/bufio/scan.mojo index 8606069..64a7cd3 100644 --- a/gojo/bufio/scan.mojo +++ b/gojo/bufio/scan.mojo @@ -192,7 +192,7 @@ struct Scanner[R: io.Reader, split: SplitFunction = scan_lines](): # The functi loop += 1 if loop > MAX_CONSECUTIVE_EMPTY_READS: - self.set_err(Error(io.ERR_NO_PROGRESS)) + self.set_err(io.ERR_NO_PROGRESS) break fn set_err(inout self, err: Error): @@ -203,7 +203,7 @@ struct Scanner[R: io.Reader, split: SplitFunction = scan_lines](): # The functi """ if self.err: var value = str(self.err) - if value == "" or value == io.EOF: + if value == "" or value == str(io.EOF): self.err = err else: self.err = err @@ -218,11 +218,11 @@ struct Scanner[R: io.Reader, split: SplitFunction = scan_lines](): # The functi True if the advance was legal, False otherwise. """ if n < 0: - self.set_err(Error(str(ERR_NEGATIVE_ADVANCE))) + self.set_err(ERR_NEGATIVE_ADVANCE) return False if n > self.end - self.start: - self.set_err(Error(str(ERR_ADVANCE_TOO_FAR))) + self.set_err(ERR_ADVANCE_TOO_FAR) return False self.start += n diff --git a/gojo/bytes/buffer.mojo b/gojo/bytes/buffer.mojo index bbd2a93..668f9fe 100644 --- a/gojo/bytes/buffer.mojo +++ b/gojo/bytes/buffer.mojo @@ -185,12 +185,18 @@ struct Buffer( @always_inline fn write(inout self, src: List[Byte]) -> (Int, Error): """ - Appends a byte Span to the builder buffer. + Appends a byte List to the builder buffer. Args: src: The byte array to append. """ - return self._write(Span(src)) + var span = Span(src) + + var bytes_read: Int + var err: Error + bytes_read, err = self._write(span) + + return bytes_read, err @always_inline fn write_string(inout self, src: String) -> (Int, Error): @@ -200,7 +206,7 @@ struct Buffer( Args: src: The string to append. """ - return self._write(src.as_bytes_slice()) + return self.write(src.as_bytes_slice()) @always_inline fn write_byte(inout self, byte: Byte) -> (Int, Error): @@ -248,6 +254,7 @@ struct Buffer( Args: dest: The buffer to read into. + capacity: The capacity of the destination buffer. Returns: The number of bytes read from the buffer. @@ -259,7 +266,7 @@ struct Buffer( # TODO: How to check if the span's pointer has 0 capacity? We want to return early if the span can't receive any data. if capacity == 0: return 0, Error() - return 0, Error(io.EOF) + return 0, io.EOF # Copy the data of the internal buffer from offset to len(buf) into the destination buffer at the given index. var bytes_read = copy(dest, self.as_bytes_slice()[self.offset :]) @@ -301,7 +308,7 @@ struct Buffer( if self.empty(): # Buffer is empty, reset to recover space. self.reset() - return Byte(0), Error(io.EOF) + return Byte(0), io.EOF var byte = self._data[self.offset] self.offset += 1 @@ -366,7 +373,7 @@ struct Buffer( var err = Error() if i < 0: end = self[]._size - err = Error(io.EOF) + err = Error(str(io.EOF)) var line = self[].as_bytes_slice()[self[].offset : end] self[].offset = end diff --git a/gojo/bytes/reader.mojo b/gojo/bytes/reader.mojo index 54a1b7f..8948b9a 100644 --- a/gojo/bytes/reader.mojo +++ b/gojo/bytes/reader.mojo @@ -79,7 +79,7 @@ struct Reader( Int: The number of bytes read into dest.""" if self.index >= self.size: - return 0, Error(io.EOF) + return 0, io.EOF # Copy the data of the internal buffer from offset to len(buf) into the destination buffer at the given index. self.prev_rune = -1 @@ -125,12 +125,12 @@ struct Reader( return 0, Error("bytes.Reader.read_at: negative offset") if off >= Int(self.size): - return 0, Error(io.EOF) + return 0, io.EOF var unread_bytes = self.as_bytes_slice()[off : self.size] var bytes_written = copy(dest, unread_bytes) if bytes_written < len(dest): - return 0, Error(io.EOF) + return 0, io.EOF return bytes_written, Error() @@ -160,7 +160,7 @@ struct Reader( """Reads and returns a single byte from the internal buffer. Implements the [io.ByteReader] Interface.""" self.prev_rune = -1 if self.index >= self.size: - return UInt8(0), Error(io.EOF) + return UInt8(0), io.EOF var byte = self.data[self.index] self.index += 1 @@ -256,7 +256,7 @@ struct Reader( self.index += write_count if write_count != len(bytes): - return write_count, Error(io.ERR_SHORT_WRITE) + return write_count, io.ERR_SHORT_WRITE return write_count, Error() diff --git a/gojo/io/__init__.mojo b/gojo/io/__init__.mojo index 216bb1e..fb4e9b6 100644 --- a/gojo/io/__init__.mojo +++ b/gojo/io/__init__.mojo @@ -20,13 +20,13 @@ alias SEEK_END = 2 # seek relative to the end # ERR_SHORT_WRITE means that a write accepted fewer bytes than requested # but failed to return an explicit error. -alias ERR_SHORT_WRITE = "short write" +alias ERR_SHORT_WRITE = Error("short write") # ERR_INVALID_WRITE means that a write returned an impossible count. -alias ERR_INVALID_WRITE = "invalid write result" +alias ERR_INVALID_WRITE = Error("invalid write result") # ERR_SHORT_BUFFER means that a read required a longer buffer than was provided. -alias ERR_SHORT_BUFFER = "short buffer" +alias ERR_SHORT_BUFFER = Error("short buffer") # EOF is the error returned by Read when no more input is available. # (Read must return EOF itself, not an error wrapping EOF, @@ -35,16 +35,16 @@ alias ERR_SHORT_BUFFER = "short buffer" # If the EOF occurs unexpectedly in a structured data stream, # the appropriate error is either [ERR_UNEXPECTED_EOF] or some other error # giving more detail. -alias EOF = "EOF" +alias EOF = Error("EOF") # ERR_UNEXPECTED_EOF means that EOF was encountered in the # middle of reading a fixed-size block or data structure. -alias ERR_UNEXPECTED_EOF = "unexpected EOF" +alias ERR_UNEXPECTED_EOF = Error("unexpected EOF") # ERR_NO_PROGRESS is returned by some clients of a [Reader] when # many calls to Read have failed to return any data or error, # usually the sign of a broken [Reader] implementation. -alias ERR_NO_PROGRESS = "multiple Read calls return no data or error" +alias ERR_NO_PROGRESS = Error("multiple Read calls return no data or error") trait Reader(Movable): @@ -99,6 +99,9 @@ trait Writer(Movable): Implementations must not retain p. """ + # fn _write(inout self, src: Span[UInt8]) -> (Int, Error): + # ... + fn write(inout self, src: List[UInt8]) -> (Int, Error): ... @@ -256,7 +259,10 @@ trait WriterAt: Implementations must not retain p.""" - fn write_at(self, src: Span[UInt8], off: Int) -> (Int, Error): + fn _write_at(self, src: Span[UInt8], off: Int) -> (Int, Error): + ... + + fn write_at(self, src: List[UInt8], off: Int) -> (Int, Error): ... diff --git a/gojo/io/file.mojo b/gojo/io/file.mojo index a904b3c..443ae93 100644 --- a/gojo/io/file.mojo +++ b/gojo/io/file.mojo @@ -50,7 +50,7 @@ struct FileWrapper(FileDescriptorBase, io.ByteReader): _ = copy(dest, Span(result), len(dest)) if bytes_read == 0: - return bytes_read, Error(io.EOF) + return bytes_read, io.EOF return bytes_read, Error() @@ -74,7 +74,7 @@ struct FileWrapper(FileDescriptorBase, io.ByteReader): _ = copy(dest, result, len(dest)) if bytes_read == 0: - return bytes_read, Error(io.EOF) + return bytes_read, io.EOF return bytes_read, Error() @@ -91,7 +91,7 @@ struct FileWrapper(FileDescriptorBase, io.ByteReader): bytes.extend(temp) if len(temp) < io.BUFFER_SIZE: - return bytes, Error(io.EOF) + return bytes, io.EOF @always_inline fn read_byte(inout self) -> (UInt8, Error): @@ -139,7 +139,7 @@ struct FileWrapper(FileDescriptorBase, io.ByteReader): try: self.handle.write(src.unsafe_ptr()) - return len(src), Error(io.EOF) + return len(src), io.EOF except e: return 0, Error(str(e)) diff --git a/gojo/io/io.mojo b/gojo/io/io.mojo index 064b06d..87b7da2 100644 --- a/gojo/io/io.mojo +++ b/gojo/io/io.mojo @@ -51,7 +51,7 @@ fn read_at_least[R: Reader](inout reader: R, inout dest: List[Byte], min: Int) - The number of bytes read.""" var error = Error() if len(dest) < min: - return 0, Error(io.ERR_SHORT_BUFFER) + return 0, io.ERR_SHORT_BUFFER var total_bytes_read: Int = 0 while total_bytes_read < min and not error: @@ -63,7 +63,7 @@ fn read_at_least[R: Reader](inout reader: R, inout dest: List[Byte], min: Int) - error = Error() elif total_bytes_read > 0 and str(error): - error = Error(ERR_UNEXPECTED_EOF) + error = ERR_UNEXPECTED_EOF return total_bytes_read, error @@ -424,9 +424,8 @@ fn read_all[R: Reader](inout reader: R) -> (List[Byte], Error): var bytes_read: Int var err: Error bytes_read, err = reader.read(temp) - var err_message = str(err) - if err_message != "": - if err_message != EOF: + if str(err) != "": + if str(err) != str(EOF): return dest, err at_eof = True diff --git a/gojo/net/fd.mojo b/gojo/net/fd.mojo index a9d9d4c..5511422 100644 --- a/gojo/net/fd.mojo +++ b/gojo/net/fd.mojo @@ -50,7 +50,7 @@ struct FileDescriptor(FileDescriptorBase): 0, ) if bytes_received == 0: - return bytes_received, Error(io.EOF) + return bytes_received, io.EOF if bytes_received == -1: return 0, Error("Failed to receive message from socket.") diff --git a/gojo/net/socket.mojo b/gojo/net/socket.mojo index cafc451..f21867d 100644 --- a/gojo/net/socket.mojo +++ b/gojo/net/socket.mojo @@ -358,6 +358,18 @@ struct Socket(FileDescriptorBase): self.remote_address = BaseAddr(remote.host, remote.port) return Error() + @always_inline + fn _write(inout self: Self, src: Span[UInt8]) -> (Int, Error): + """Send data to the socket. The socket must be connected to a remote socket. + + Args: + src: The data to send. + + Returns: + The number of bytes sent. + """ + return self.fd._write(src) + @always_inline fn write(inout self: Self, src: List[UInt8]) -> (Int, Error): """Send data to the socket. The socket must be connected to a remote socket. @@ -370,14 +382,13 @@ struct Socket(FileDescriptorBase): """ return self.fd.write(src) - fn send_all(self, src: List[UInt8], max_attempts: Int = 3) raises: + fn send_all(self, src: Span[UInt8], max_attempts: Int = 3) -> Error: """Send data to the socket. The socket must be connected to a remote socket. Args: src: The data to send. max_attempts: The maximum number of attempts to send the data. """ - var data = src.unsafe_ptr() var bytes_to_send = len(src) var total_bytes_sent = 0 var attempts = 0 @@ -385,21 +396,23 @@ struct Socket(FileDescriptorBase): # Try to send all the data in the buffer. If it did not send all the data, keep trying but start from the offset of the last successful send. while total_bytes_sent < len(src): if attempts > max_attempts: - raise Error("Failed to send message after " + str(max_attempts) + " attempts.") + return Error("Failed to send message after " + str(max_attempts) + " attempts.") var bytes_sent = send( self.fd.fd, - data.offset(total_bytes_sent), + src.unsafe_ptr() + total_bytes_sent, bytes_to_send - total_bytes_sent, 0, ) if bytes_sent == -1: - raise Error("Failed to send message, wrote" + String(total_bytes_sent) + "bytes before failing.") + return Error("Failed to send message, wrote" + String(total_bytes_sent) + "bytes before failing.") total_bytes_sent += bytes_sent attempts += 1 + return Error() + @always_inline - fn send_to(inout self, src: List[UInt8], address: String, port: Int) -> (Int, Error): + fn send_to(inout self, src: Span[UInt8], address: String, port: Int) -> (Int, Error): """Send data to the a remote address by connecting to the remote socket before sending. The socket must be not already be connected to a remote socket. @@ -444,7 +457,7 @@ struct Socket(FileDescriptorBase): var bytes = List[UInt8](unsafe_pointer=buffer, size=bytes_received, capacity=size) if bytes_received < bytes.capacity: - return bytes, Error(io.EOF) + return bytes, io.EOF return bytes, Error() @@ -513,7 +526,7 @@ struct Socket(FileDescriptorBase): var bytes = List[UInt8](unsafe_pointer=buffer, size=bytes_received, capacity=size) if bytes_received < bytes.capacity: - return bytes, remote, Error(io.EOF) + return bytes, remote, io.EOF return bytes, remote, Error() @@ -542,7 +555,7 @@ struct Socket(FileDescriptorBase): return 0, HostPort(), err if bytes_read < dest.capacity: - return bytes_read, remote, Error(io.EOF) + return bytes_read, remote, io.EOF return bytes_read, remote, Error() @@ -578,5 +591,9 @@ struct Socket(FileDescriptorBase): # self.set_socket_option(SocketOptions.SO_RCVTIMEO, duration) @always_inline - fn send_file(self, file: FileHandle, offset: Int = 0) raises: - self.send_all(file.read_bytes()) + fn send_file(self, file: FileHandle) -> Error: + try: + var bytes = file.read_bytes() + return self.send_all(Span(bytes)) + except e: + return e diff --git a/gojo/net/tcp.mojo b/gojo/net/tcp.mojo index b459826..148565e 100644 --- a/gojo/net/tcp.mojo +++ b/gojo/net/tcp.mojo @@ -69,7 +69,7 @@ struct TCPConnection(Movable): var err = Error() bytes_read, err = self.socket._read(dest, capacity) if err: - if str(err) != io.EOF: + if str(err) != str(io.EOF): return bytes_read, err return bytes_read, err @@ -93,6 +93,18 @@ struct TCPConnection(Movable): return bytes_read, err + @always_inline + fn _write(inout self, src: Span[UInt8]) -> (Int, Error): + """Writes data to the underlying file descriptor. + + Args: + src: The buffer to read data into. + + Returns: + The number of bytes written, or an error if one occurred. + """ + return self.socket._write(src) + @always_inline fn write(inout self, src: List[UInt8]) -> (Int, Error): """Writes data to the underlying file descriptor. diff --git a/gojo/net/udp.mojo b/gojo/net/udp.mojo index 61cb4cb..ebc0fc0 100644 --- a/gojo/net/udp.mojo +++ b/gojo/net/udp.mojo @@ -68,7 +68,7 @@ struct UDPConnection(Movable): return bytes_read, remote, err - fn write_to(inout self, src: List[UInt8], address: UDPAddr) -> (Int, Error): + fn write_to(inout self, src: Span[UInt8], address: UDPAddr) -> (Int, Error): """Writes data to the underlying file descriptor. Args: @@ -80,7 +80,7 @@ struct UDPConnection(Movable): """ return self.socket.send_to(src, address.ip, address.port) - fn write_to(inout self, src: List[UInt8], host: String, port: Int) -> (Int, Error): + fn write_to(inout self, src: Span[UInt8], host: String, port: Int) -> (Int, Error): """Writes data to the underlying file descriptor. Args: diff --git a/gojo/strings/builder.mojo b/gojo/strings/builder.mojo index f38df8c..24ac6cd 100644 --- a/gojo/strings/builder.mojo +++ b/gojo/strings/builder.mojo @@ -136,12 +136,18 @@ struct StringBuilder[growth_factor: Float32 = 2]( @always_inline fn write(inout self, src: List[UInt8]) -> (Int, Error): """ - Appends a byte Span to the builder buffer. + Appends a byte List to the builder buffer. Args: - src: The byte array to append. + src: The byte array to append. """ - return self._write(Span(src)) + var span = Span(src) + + var bytes_read: Int + var err: Error + bytes_read, err = self._write(span) + + return bytes_read, err @always_inline fn write_string(inout self, src: String) -> (Int, Error): diff --git a/gojo/strings/reader.mojo b/gojo/strings/reader.mojo index 61292bf..97ca0d9 100644 --- a/gojo/strings/reader.mojo +++ b/gojo/strings/reader.mojo @@ -3,6 +3,7 @@ from ..builtins import copy, panic @value +# TODO: Uncomment write_to and write_buf once the bug with the trait's Span argument is fixed. struct Reader( Sized, io.Reader, @@ -10,7 +11,7 @@ struct Reader( io.ByteReader, io.ByteScanner, io.Seeker, - io.WriterTo, + # io.WriterTo, ): """A Reader that implements the [io.Reader], [io.ReaderAt], [io.ByteReader], [io.ByteScanner], [io.Seeker], and [io.WriterTo] traits by reading from a string. The zero value for Reader operates like a Reader of an empty string. @@ -63,7 +64,7 @@ struct Reader( The number of bytes read into dest. """ if self.read_pos >= len(self.string): - return 0, Error(io.EOF) + return 0, io.EOF self.prev_rune = -1 var bytes_written = copy(dest, self.string.as_bytes_slice()[self.read_pos :]) @@ -108,12 +109,12 @@ struct Reader( return 0, Error("strings.Reader.read_at: negative offset") if off >= len(self.string): - return 0, Error(io.EOF) + return 0, io.EOF var error = Error() var copied_elements_count = copy(dest, self.string.as_bytes_slice()[off:]) if copied_elements_count < len(dest): - error = Error(io.EOF) + error = Error(str(io.EOF)) return copied_elements_count, error @@ -143,7 +144,7 @@ struct Reader( """Reads the next byte from the underlying string.""" self.prev_rune = -1 if self.read_pos >= len(self.string): - return UInt8(0), Error(io.EOF) + return UInt8(0), io.EOF var b = self.string.as_bytes_slice()[self.read_pos] self.read_pos += 1 @@ -215,32 +216,32 @@ struct Reader( self.read_pos = position return position, Error() - fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - """Writes the remaining portion of the underlying string to the provided writer. - Implements the [io.WriterTo] trait. + # fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): + # """Writes the remaining portion of the underlying string to the provided writer. + # Implements the [io.WriterTo] trait. - Args: - writer: The writer to write the remaining portion of the string to. + # Args: + # writer: The writer to write the remaining portion of the string to. - Returns: - The number of bytes written to the writer. - """ - self.prev_rune = -1 - var err = Error() - if self.read_pos >= len(self.string): - return Int(0), err + # Returns: + # The number of bytes written to the writer. + # """ + # self.prev_rune = -1 + # var err = Error() + # if self.read_pos >= len(self.string): + # return Int(0), err - var chunk_to_write = self.string.as_bytes_slice()[self.read_pos :] - var bytes_written: Int - bytes_written, err = writer.write(chunk_to_write) - if bytes_written > len(chunk_to_write): - panic("strings.Reader.write_to: invalid write_string count") + # var chunk_to_write = self.string.as_bytes_slice()[self.read_pos :] + # var bytes_written: Int + # bytes_written, err = writer.write(chunk_to_write) + # if bytes_written > len(chunk_to_write): + # panic("strings.Reader.write_to: invalid write_string count") - self.read_pos += bytes_written - if bytes_written != len(chunk_to_write) and not err: - err = Error(io.ERR_SHORT_WRITE) + # self.read_pos += bytes_written + # if bytes_written != len(chunk_to_write) and not err: + # err = Error(io.ERR_SHORT_WRITE) - return bytes_written, err + # return bytes_written, err # # TODO: How can I differentiate between the two write_to methods when the writer implements both traits? # fn write_to[W: io.StringWriter](inout self, inout writer: W) raises -> Int: diff --git a/gojo/syscall/file.mojo b/gojo/syscall/file.mojo index e3a7ed7..ef0427e 100644 --- a/gojo/syscall/file.mojo +++ b/gojo/syscall/file.mojo @@ -1,6 +1,3 @@ -from . import c_int, c_char, c_void, c_size_t, c_ssize_t - - trait FileDescriptorBase(io.Reader, io.Writer, io.Closer): ... diff --git a/tests/test_bufio.mojo b/tests/test_bufio.mojo index 4d759e8..8d02f3b 100644 --- a/tests/test_bufio.mojo +++ b/tests/test_bufio.mojo @@ -1,7 +1,7 @@ from tests.wrapper import MojoTest from gojo.bytes import buffer from gojo.builtins.bytes import to_string -from gojo.bufio import Reader, Scanner, scan_words, scan_bytes, Writer +from gojo.bufio import Reader, Scanner, scan_words, scan_bytes, Writer, new_writer, new_reader from gojo.io import read_all, FileWrapper from gojo.strings import StringBuilder @@ -34,20 +34,20 @@ fn test_read_all(): test.assert_equal(String(bytes), "0123456789") -fn test_write_to(): - var test = MojoTest("Testing bufio.Reader.write_to") +# fn test_write_to(): +# var test = MojoTest("Testing bufio.Reader.write_to") - var buf = buffer.new_buffer("0123456789") - var reader = Reader(buf^) +# var buf = buffer.new_buffer("0123456789") +# var reader = Reader(buf^) - # Create a new writer containing the content "Hello World" - var writer = buffer.new_buffer("Hello World") +# # Create a new writer containing the content "Hello World" +# var writer = buffer.new_buffer("Hello World") - # Write the content of the reader to the writer - _ = reader.write_to(writer) +# # Write the content of the reader to the writer +# _ = reader.write_to(writer) - # Check if the content of the writer is "Hello World0123456789" - test.assert_equal(str(writer), "Hello World0123456789") +# # Check if the content of the writer is "Hello World0123456789" +# test.assert_equal(str(writer), "Hello World0123456789") fn test_read_and_unread_byte(): @@ -124,8 +124,9 @@ fn test_write(): var test = MojoTest("Testing bufio.Writer.write and flush") # Create a new List[UInt8] Buffer Writer and use it to create the buffered Writer - var buf = buffer.new_buffer() - var writer = Writer(buf^) + # var buf = buffer.new_buffer() + var writer = new_writer(buffer.new_buffer()) + # var writer = Writer(buf^) # Write the content from src to the buffered writer's internal buffer and flush it to the List[UInt8] Buffer Writer. var src = String("0123456789").as_bytes() @@ -226,7 +227,7 @@ fn test_read_from(): fn main(): test_read() test_read_all() - test_write_to() + # test_write_to() test_read_and_unread_byte() test_read_slice() test_peek() diff --git a/tests/test_bytes_reader.mojo b/tests/test_bytes_reader.mojo index b703ced..1075061 100644 --- a/tests/test_bytes_reader.mojo +++ b/tests/test_bytes_reader.mojo @@ -38,10 +38,10 @@ fn test_read_after_big_seek() raises: if not err: raise Error("Expected error not raised while testing big seek.") - if str(err) != io.EOF: + if str(err) != str(io.EOF): raise err - test.assert_equal(str(err), io.EOF) + test.assert_equal(str(err), str(io.EOF)) fn test_read_at() raises: diff --git a/tests/test_strings_reader.mojo b/tests/test_strings_reader.mojo index 8673c16..feb5be0 100644 --- a/tests/test_strings_reader.mojo +++ b/tests/test_strings_reader.mojo @@ -68,15 +68,15 @@ fn test_read_and_unread_byte() raises: test.assert_equal(len(reader), len(example)) -fn test_write_to() raises: - var test = MojoTest("Testing strings.Reader.write_to") - var example: String = "Hello, World!" - var reader = new_reader("Hello, World!") +# fn test_write_to() raises: +# var test = MojoTest("Testing strings.Reader.write_to") +# var example: String = "Hello, World!" +# var reader = new_reader("Hello, World!") - # Write from the string reader to a StringBuilder. - var builder = StringBuilder() - _ = reader.write_to(builder) - test.assert_equal(str(builder), example) +# # Write from the string reader to a StringBuilder. +# var builder = StringBuilder() +# _ = reader.write_to(builder) +# test.assert_equal(str(builder), example) fn main() raises: @@ -84,5 +84,5 @@ fn main() raises: test_read_at() test_seek() test_read_and_unread_byte() - test_write_to() + # test_write_to() test_read_slice()