io: allow BufferedReader.read_line() to accept custom line delimiters (#20655)

This commit is contained in:
syrmel 2024-01-26 10:37:30 +01:00 committed by GitHub
parent 2c6a8c536c
commit 754c83a8ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 6 deletions

View file

@ -21,6 +21,12 @@ pub struct BufferedReaderConfig {
retries int = 2 // how many times to retry before assuming the stream ended
}
// BufferedReadLineConfig are options that can be given to the read_line() function.
@[params]
pub struct BufferedReadLineConfig {
delim u8 = `\n` // line delimiter
}
// new_buffered_reader creates a new BufferedReader.
pub fn new_buffered_reader(o BufferedReaderConfig) &BufferedReader {
if o.cap <= 0 {
@ -107,10 +113,10 @@ pub fn (r BufferedReader) end_of_stream() bool {
return r.end_of_stream
}
// read_line attempts to read a line from the buffered reader
// it will read until it finds a new line character (\n) or
// the end of stream.
pub fn (mut r BufferedReader) read_line() !string {
// read_line attempts to read a line from the buffered reader.
// It will read until it finds the specified line delimiter
// such as (\n, the default or \0) or the end of stream.
pub fn (mut r BufferedReader) read_line(config BufferedReadLineConfig) !string {
if r.end_of_stream {
return Eof{}
}
@ -132,10 +138,10 @@ pub fn (mut r BufferedReader) read_line() !string {
for ; i < r.len; i++ {
r.total_read++
c := r.buf[i]
if c == `\n` {
if c == config.delim {
// great, we hit something
// do some checking for whether we hit \r\n or just \n
if i != 0 && r.buf[i - 1] == `\r` {
if i != 0 && config.delim == `\n` && r.buf[i - 1] == `\r` {
x := i - 1
line << r.buf[r.offset..x]
} else {

View file

@ -161,3 +161,26 @@ fn test_totalread_readline() {
assert r.total_read == text.len
}
fn test_read_line_until_zero_terminated() {
text := 'This is a test\0Nice try!\0'
mut s := StringReader{
text: text
}
mut r := new_buffered_reader(reader: s)
line1 := r.read_line(delim: `\0`) or {
assert false
panic('bad')
}
assert line1 == 'This is a test'
line2 := r.read_line(delim: `\0`) or {
assert false
panic('bad')
}
assert line2 == 'Nice try!'
if _ := r.read_line(delim: `\0`) {
assert false
panic('bad')
}
assert r.end_of_stream()
}