Browse Source

Return partial reads

gingerBill 1 year ago
parent
commit
20223345a4
1 changed files with 15 additions and 4 deletions
  1. 15 4
      core/encoding/csv/reader.odin

+ 15 - 4
core/encoding/csv/reader.odin

@@ -124,6 +124,7 @@ reader_destroy :: proc(r: ^Reader) {
 // read reads a single record (a slice of fields) from r
 //
 // All \r\n sequences are normalized to \n, including multi-line field
+@(require_results)
 read :: proc(r: ^Reader, allocator := context.allocator) -> (record: []string, err: Error) {
 	if r.reuse_record {
 		record, err = _read_record(r, &r.last_record, allocator)
@@ -136,6 +137,7 @@ read :: proc(r: ^Reader, allocator := context.allocator) -> (record: []string, e
 }
 
 // is_io_error checks where an Error is a specific io.Error kind
+@(require_results)
 is_io_error :: proc(err: Error, io_err: io.Error) -> bool {
 	if v, ok := err.(io.Error); ok {
 		return v == io_err
@@ -143,10 +145,10 @@ is_io_error :: proc(err: Error, io_err: io.Error) -> bool {
 	return false
 }
 
-
 // read_all reads all the remaining records from r.
 // Each record is a slice of fields.
 // read_all is defined to read until an EOF, and does not treat, and does not treat EOF as an error
+@(require_results)
 read_all :: proc(r: ^Reader, allocator := context.allocator) -> ([][]string, Error) {
 	context.allocator = allocator
 	records: [dynamic][]string
@@ -156,13 +158,18 @@ read_all :: proc(r: ^Reader, allocator := context.allocator) -> ([][]string, Err
 			return records[:], nil
 		}
 		if rerr != nil {
-			return nil, rerr
+			// allow for a partial read
+			if record != nil {
+				append(&records, record)
+			}
+			return records[:], rerr
 		}
 		append(&records, record)
 	}
 }
 
 // read reads a single record (a slice of fields) from the provided input.
+@(require_results)
 read_from_string :: proc(input: string, record_allocator := context.allocator, buffer_allocator := context.allocator) -> (record: []string, n: int, err: Error) {
 	ir: strings.Reader
 	strings.reader_init(&ir, input)
@@ -178,6 +185,7 @@ read_from_string :: proc(input: string, record_allocator := context.allocator, b
 
 
 // read_all reads all the remaining records from the provided input.
+@(require_results)
 read_all_from_string :: proc(input: string, records_allocator := context.allocator, buffer_allocator := context.allocator) -> ([][]string, Error) {
 	ir: strings.Reader
 	strings.reader_init(&ir, input)
@@ -189,7 +197,7 @@ read_all_from_string :: proc(input: string, records_allocator := context.allocat
 	return read_all(&r, records_allocator)
 }
 
-@private
+@(private, require_results)
 is_valid_delim :: proc(r: rune) -> bool {
 	switch r {
 	case 0, '"', '\r', '\n', utf8.RUNE_ERROR:
@@ -198,8 +206,9 @@ is_valid_delim :: proc(r: rune) -> bool {
 	return utf8.valid_rune(r)
 }
 
-@private
+@(private, require_results)
 _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.allocator) -> ([]string, Error) {
+	@(require_results)
 	read_line :: proc(r: ^Reader) -> ([]byte, io.Error) {
 		if !r.multiline_fields {
 			line, err := bufio.reader_read_slice(&r.r, '\n')
@@ -269,6 +278,7 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
 		unreachable()
 	}
 
+	@(require_results)
 	length_newline :: proc(b: []byte) -> int {
 		if len(b) > 0 && b[len(b)-1] == '\n' {
 			return 1
@@ -276,6 +286,7 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
 		return 0
 	}
 
+	@(require_results)
 	next_rune :: proc(b: []byte) -> rune {
 		r, _ := utf8.decode_rune(b)
 		return r