Browse Source

Update docs for packages fmt and io

gingerBill 3 years ago
parent
commit
f20105ddfe
4 changed files with 81 additions and 10 deletions
  1. 27 6
      core/fmt/fmt.odin
  2. 6 1
      core/fmt/fmt_js.odin
  3. 9 1
      core/fmt/fmt_os.odin
  4. 39 2
      core/io/io.odin

+ 27 - 6
core/fmt/fmt.odin

@@ -11,6 +11,7 @@ import "core:time"
 import "core:unicode/utf8"
 import "core:unicode/utf8"
 import "core:intrinsics"
 import "core:intrinsics"
 
 
+// Internal data structure that stores the required information for formatted printing
 Info :: struct {
 Info :: struct {
 	minus:     bool,
 	minus:     bool,
 	plus:      bool,
 	plus:      bool,
@@ -46,9 +47,13 @@ Register_User_Formatter_Error :: enum {
 // it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary
 // it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary
 _user_formatters: ^map[typeid]User_Formatter
 _user_formatters: ^map[typeid]User_Formatter
 
 
+// set_user_formatters assigns m to a global value allowing the user have custom print formatting for specific
+// types
 set_user_formatters :: proc(m: ^map[typeid]User_Formatter) {
 set_user_formatters :: proc(m: ^map[typeid]User_Formatter) {
 	_user_formatters = m
 	_user_formatters = m
 }
 }
+// register_user_formatter assigns a formatter to a specific typeid. set_user_formatters must be called
+// before any use of this procedure.
 register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Register_User_Formatter_Error {
 register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Register_User_Formatter_Error {
 	if _user_formatters == nil {
 	if _user_formatters == nil {
 		return .No_User_Formatter
 		return .No_User_Formatter
@@ -61,7 +66,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
 }
 }
 
 
 
 
-// aprint* procedures return a string that was allocated with the current context
+// aprint procedure return a string that was allocated with the current context
 // They must be freed accordingly
 // They must be freed accordingly
 aprint :: proc(args: ..any, sep := " ") -> string {
 aprint :: proc(args: ..any, sep := " ") -> string {
 	str: strings.Builder
 	str: strings.Builder
@@ -69,12 +74,16 @@ aprint :: proc(args: ..any, sep := " ") -> string {
 	sbprint(buf=&str, args=args, sep=sep)
 	sbprint(buf=&str, args=args, sep=sep)
 	return strings.to_string(str)
 	return strings.to_string(str)
 }
 }
+// aprintln procedure return a string that was allocated with the current context
+// They must be freed accordingly
 aprintln :: proc(args: ..any, sep := " ") -> string {
 aprintln :: proc(args: ..any, sep := " ") -> string {
 	str: strings.Builder
 	str: strings.Builder
 	strings.init_builder(&str)
 	strings.init_builder(&str)
 	sbprintln(buf=&str, args=args, sep=sep)
 	sbprintln(buf=&str, args=args, sep=sep)
 	return strings.to_string(str)
 	return strings.to_string(str)
 }
 }
+// aprintf procedure return a string that was allocated with the current context
+// They must be freed accordingly
 aprintf :: proc(fmt: string, args: ..any) -> string {
 aprintf :: proc(fmt: string, args: ..any) -> string {
 	str: strings.Builder
 	str: strings.Builder
 	strings.init_builder(&str)
 	strings.init_builder(&str)
@@ -83,19 +92,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
 }
 }
 
 
 
 
-// tprint* procedures return a string that was allocated with the current context's temporary allocator
+// tprint procedure return a string that was allocated with the current context's temporary allocator
 tprint :: proc(args: ..any, sep := " ") -> string {
 tprint :: proc(args: ..any, sep := " ") -> string {
 	str: strings.Builder
 	str: strings.Builder
 	strings.init_builder(&str, context.temp_allocator)
 	strings.init_builder(&str, context.temp_allocator)
 	sbprint(buf=&str, args=args, sep=sep)
 	sbprint(buf=&str, args=args, sep=sep)
 	return strings.to_string(str)
 	return strings.to_string(str)
 }
 }
+// tprintln procedure return a string that was allocated with the current context's temporary allocator
 tprintln :: proc(args: ..any, sep := " ") -> string {
 tprintln :: proc(args: ..any, sep := " ") -> string {
 	str: strings.Builder
 	str: strings.Builder
 	strings.init_builder(&str, context.temp_allocator)
 	strings.init_builder(&str, context.temp_allocator)
 	sbprintln(buf=&str, args=args, sep=sep)
 	sbprintln(buf=&str, args=args, sep=sep)
 	return strings.to_string(str)
 	return strings.to_string(str)
 }
 }
+// tprintf procedure return a string that was allocated with the current context's temporary allocator
 tprintf :: proc(fmt: string, args: ..any) -> string {
 tprintf :: proc(fmt: string, args: ..any) -> string {
 	str: strings.Builder
 	str: strings.Builder
 	strings.init_builder(&str, context.temp_allocator)
 	strings.init_builder(&str, context.temp_allocator)
@@ -104,21 +115,24 @@ tprintf :: proc(fmt: string, args: ..any) -> string {
 }
 }
 
 
 
 
-// bprint* procedures return a string using a buffer from an array
+// bprint procedures return a string using a buffer from an array
 bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
 bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	return sbprint(buf=&sb, args=args, sep=sep)
 	return sbprint(buf=&sb, args=args, sep=sep)
 }
 }
+// bprintln procedures return a string using a buffer from an array
 bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
 bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	return sbprintln(buf=&sb, args=args, sep=sep)
 	return sbprintln(buf=&sb, args=args, sep=sep)
 }
 }
+// bprintf procedures return a string using a buffer from an array
 bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
 bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	sb := strings.builder_from_slice(buf[0:len(buf)])
 	return sbprintf(&sb, fmt, ..args)
 	return sbprintf(&sb, fmt, ..args)
 }
 }
 
 
 
 
+// formatted assert
 assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) -> bool {
 assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) -> bool {
 	if !condition {
 	if !condition {
 		p := context.assertion_failure_proc
 		p := context.assertion_failure_proc
@@ -131,6 +145,7 @@ assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_locati
 	return condition
 	return condition
 }
 }
 
 
+// formatted panic
 panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
 panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
 	p := context.assertion_failure_proc
 	p := context.assertion_failure_proc
 	if p == nil {
 	if p == nil {
@@ -142,24 +157,26 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
 
 
 
 
 
 
-
-
+// sbprint formats using the default print settings and writes to buf
 sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
 sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
 	wprint(w=strings.to_writer(buf), args=args, sep=sep)
 	wprint(w=strings.to_writer(buf), args=args, sep=sep)
 	return strings.to_string(buf^)
 	return strings.to_string(buf^)
 }
 }
 
 
+// sbprintln formats using the default print settings and writes to buf
 sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
 sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
 	wprintln(w=strings.to_writer(buf), args=args, sep=sep)
 	wprintln(w=strings.to_writer(buf), args=args, sep=sep)
 	return strings.to_string(buf^)
 	return strings.to_string(buf^)
 }
 }
 
 
+// sbprintf formats according to the specififed format string and writes to buf
 sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
 sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
 	wprintf(w=strings.to_writer(buf), fmt=fmt, args=args)
 	wprintf(w=strings.to_writer(buf), fmt=fmt, args=args)
 	return strings.to_string(buf^)
 	return strings.to_string(buf^)
 }
 }
 
 
 
 
+// wprint formats using the default print settings and writes to w
 wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 	fi: Info
 	fi: Info
 	fi.writer = w
 	fi.writer = w
@@ -194,6 +211,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 	return int(size1 - size0)
 	return int(size1 - size0)
 }
 }
 
 
+// wprintln formats using the default print settings and writes to w
 wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 	fi: Info
 	fi: Info
 	fi.writer = w
 	fi.writer = w
@@ -214,6 +232,7 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
 	return int(size1 - size0)
 	return int(size1 - size0)
 }
 }
 
 
+// wprintf formats according to the specififed format string and writes to w
 wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
 wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
 	fi: Info
 	fi: Info
 	arg_index: int = 0
 	arg_index: int = 0
@@ -493,11 +512,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
 	return int(size1 - size0)
 	return int(size1 - size0)
 }
 }
 
 
+// wprint_type is a utility procedure to write a ^runtime.Type_Info value to w
 wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
 wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
 	n, err := reflect.write_type(w, info)
 	n, err := reflect.write_type(w, info)
 	io.flush(auto_cast w)
 	io.flush(auto_cast w)
 	return n, err
 	return n, err
 }
 }
+// wprint_typeid is a utility procedure to write a typeid value to w
 wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) {
 wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) {
 	n, err := reflect.write_type(w, type_info_of(id))
 	n, err := reflect.write_type(w, type_info_of(id))
 	io.flush(auto_cast w)
 	io.flush(auto_cast w)
@@ -829,7 +850,7 @@ _pad :: proc(fi: ^Info, s: string) {
 
 
 fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
 fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
 	switch verb {
 	switch verb {
-	case 'f', 'F', 'v':
+	case 'f', 'F', 'g', 'G', 'v':
 		prec: int = 3
 		prec: int = 3
 		if fi.prec_set {
 		if fi.prec_set {
 			prec = fi.prec
 			prec = fi.prec

+ 6 - 1
core/fmt/fmt_js.odin

@@ -34,11 +34,16 @@ stderr := io.Writer{
 	},
 	},
 }
 }
 
 
-// print* procedures return the number of bytes written
+// print formats using the default print settings and writes to stdout
 print   :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) }
 print   :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) }
+// println formats using the default print settings and writes to stdout
 println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) }
 println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) }
+// printf formats according to the specififed format string and writes to stdout
 printf  :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) }
 printf  :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) }
 
 
+// eprint formats using the default print settings and writes to stderr
 eprint   :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) }
 eprint   :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) }
+// eprintln formats using the default print settings and writes to stderr
 eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) }
 eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) }
+// eprintf formats according to the specififed format string and writes to stderr
 eprintf  :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) }
 eprintf  :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) }

+ 9 - 1
core/fmt/fmt_os.odin

@@ -5,15 +5,18 @@ import "core:runtime"
 import "core:os"
 import "core:os"
 import "core:io"
 import "core:io"
 
 
+// fprint formats using the default print settings and writes to fd
 fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
 fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
 	w := io.to_writer(os.stream_from_handle(fd))
 	w := io.to_writer(os.stream_from_handle(fd))
 	return wprint(w=w, args=args, sep=sep)
 	return wprint(w=w, args=args, sep=sep)
 }
 }
 
 
+// fprintln formats using the default print settings and writes to fd
 fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
 fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
 	w := io.to_writer(os.stream_from_handle(fd))
 	w := io.to_writer(os.stream_from_handle(fd))
 	return wprintln(w=w, args=args, sep=sep)
 	return wprintln(w=w, args=args, sep=sep)
 }
 }
+// fprintf formats according to the specififed format string and writes to fd
 fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 	w := io.to_writer(os.stream_from_handle(fd))
 	w := io.to_writer(os.stream_from_handle(fd))
 	return wprintf(w, fmt, ..args)
 	return wprintf(w, fmt, ..args)
@@ -27,11 +30,16 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
 	return wprint_typeid(w, id)
 	return wprint_typeid(w, id)
 }
 }
 
 
-// print* procedures return the number of bytes written
+// print formats using the default print settings and writes to os.stdout
 print   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
 print   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
+// println formats using the default print settings and writes to os.stdout
 println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
 println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
+// printf formats according to the specififed format string and writes to os.stdout
 printf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
 printf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
 
 
+// eprint formats using the default print settings and writes to os.stderr
 eprint   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
 eprint   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
+// eprintln formats using the default print settings and writes to os.stderr
 eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
 eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
+// eprintf formats according to the specififed format string and writes to os.stderr
 eprintf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }
 eprintf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }

+ 39 - 2
core/io/io.odin

@@ -1,9 +1,13 @@
+// package io provides basic interfaces for generic data stream primitives.
+// The purpose of this package is wrap existing data structures and their
+// operations into an abstracted stream interface.
 package io
 package io
 
 
 import "core:intrinsics"
 import "core:intrinsics"
 import "core:runtime"
 import "core:runtime"
 import "core:unicode/utf8"
 import "core:unicode/utf8"
 
 
+// Seek whence values
 Seek_From :: enum {
 Seek_From :: enum {
 	Start   = 0, // seek relative to the origin of the file
 	Start   = 0, // seek relative to the origin of the file
 	Current = 1, // seek relative to the current offset
 	Current = 1, // seek relative to the current offset
@@ -139,6 +143,10 @@ destroy :: proc(s: Stream) -> Error {
 	return .Empty
 	return .Empty
 }
 }
 
 
+// read reads up to len(p) bytes into s. It returns the number of bytes read and any error if occurred.
+//
+// When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of
+// bytes read along with the error.
 read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
 read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
 	if s.stream_vtable != nil && s.impl_read != nil {
 	if s.stream_vtable != nil && s.impl_read != nil {
 		n, err = s->impl_read(p)
 		n, err = s->impl_read(p)
@@ -150,6 +158,7 @@ read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
 	return 0, .Empty
 	return 0, .Empty
 }
 }
 
 
+// write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred.
 write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
 write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
 	if s.stream_vtable != nil && s.impl_write != nil {
 	if s.stream_vtable != nil && s.impl_write != nil {
 		n, err = s->impl_write(p)
 		n, err = s->impl_write(p)
@@ -161,6 +170,13 @@ write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Erro
 	return 0, .Empty
 	return 0, .Empty
 }
 }
 
 
+// seek sets the offset of the next read or write to offset.
+//
+// .Start means seek relative to the origin of the file.
+// .Current means seek relative to the current offset.
+// .End means seek relative to the end.
+//
+// seek returns the new offset to the start of the file/stream, and any error if occurred.
 seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
 seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
 	if s.stream_vtable != nil && s.impl_seek != nil {
 	if s.stream_vtable != nil && s.impl_seek != nil {
 		return s->impl_seek(offset, whence)
 		return s->impl_seek(offset, whence)
@@ -168,6 +184,8 @@ seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
 	return 0, .Empty
 	return 0, .Empty
 }
 }
 
 
+// The behaviour of close after the first call is stream implementation defined.
+// Different streams may document their own behaviour.
 close :: proc(s: Closer) -> Error {
 close :: proc(s: Closer) -> Error {
 	if s.stream_vtable != nil && s.impl_close != nil {
 	if s.stream_vtable != nil && s.impl_close != nil {
 		return s->impl_close()
 		return s->impl_close()
@@ -184,6 +202,7 @@ flush :: proc(s: Flusher) -> Error {
 	return .None
 	return .None
 }
 }
 
 
+// size returns the size of the stream. If the stream does not support querying its size, 0 will be returned.
 size :: proc(s: Stream) -> i64 {
 size :: proc(s: Stream) -> i64 {
 	if s.stream_vtable == nil {
 	if s.stream_vtable == nil {
 		return 0
 		return 0
@@ -214,7 +233,12 @@ size :: proc(s: Stream) -> i64 {
 
 
 
 
 
 
-
+// read_at reads len(p) bytes into p starting with the provided offset in the underlying Reader_At stream r.
+// It returns the number of bytes read and any error if occurred.
+//
+// When read_at returns n < len(p), it returns a non-nil Error explaining why.
+//
+// If n == len(p), err may be either nil or .EOF
 read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) {
 read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) {
 	defer if n_read != nil {
 	defer if n_read != nil {
 		n_read^ += n
 		n_read^ += n
@@ -245,6 +269,11 @@ read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n:
 
 
 }
 }
 
 
+// write_at writes len(p) bytes into p starting with the provided offset in the underlying Writer_At stream w.
+// It returns the number of bytes written and any error if occurred.
+//
+// If write_at is writing to a Writer_At which has a seek offset, then write_at should not affect the underlying
+// seek offset.
 write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) {
 write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) {
 	defer if n_written != nil {
 	defer if n_written != nil {
 		n_written^ += n
 		n_written^ += n
@@ -294,6 +323,7 @@ read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) {
 }
 }
 
 
 
 
+// read_byte reads and returns the next byte from r.
 read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
 read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
 	defer if err == nil && n_read != nil {
 	defer if err == nil && n_read != nil {
 		n_read^ += 1
 		n_read^ += 1
@@ -347,6 +377,7 @@ _write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Err
 	return err
 	return err
 }
 }
 
 
+// read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes.
 read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
 read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
 	defer if err == nil && n_read != nil {
 	defer if err == nil && n_read != nil {
 		n_read^ += size
 		n_read^ += size
@@ -405,10 +436,12 @@ unread_rune :: proc(s: Rune_Scanner) -> Error {
 }
 }
 
 
 
 
+// write_string writes the contents of the string s to w.
 write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) {
 write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) {
 	return write(s, transmute([]byte)str, n_written)
 	return write(s, transmute([]byte)str, n_written)
 }
 }
 
 
+// write_rune writes a UTF-8 encoded rune to w.
 write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
 write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
 	defer if err == nil && n_written != nil {
 	defer if err == nil && n_written != nil {
 		n_written^ += size
 		n_written^ += size
@@ -430,12 +463,16 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err
 }
 }
 
 
 
 
-
+// read_full expected exactly len(buf) bytes from r into buf.
 read_full :: proc(r: Reader, buf: []byte) -> (n: int, err: Error) {
 read_full :: proc(r: Reader, buf: []byte) -> (n: int, err: Error) {
 	return read_at_least(r, buf, len(buf))
 	return read_at_least(r, buf, len(buf))
 }
 }
 
 
 
 
+// read_at_least reads from r into buf until it has read at least min bytes. It returns the number
+// of bytes copied and an error if fewer bytes were read. `.EOF` is only returned if no bytes were read.
+// `.Unexpected_EOF` is returned when an `.EOF ` is returned by the passed Reader after reading
+// fewer than min bytes. If len(buf) is less than min, `.Short_Buffer` is returned.
 read_at_least :: proc(r: Reader, buf: []byte, min: int) -> (n: int, err: Error) {
 read_at_least :: proc(r: Reader, buf: []byte, min: int) -> (n: int, err: Error) {
 	if len(buf) < min {
 	if len(buf) < min {
 		return 0, .Short_Buffer
 		return 0, .Short_Buffer