util.odin 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package io
  2. import "core:mem"
  3. import "core:strconv"
  4. read_ptr :: proc(r: Reader, p: rawptr, byte_size: int) -> (n: int, err: Error) {
  5. return read(r, mem.byte_slice(p, byte_size));
  6. }
  7. write_ptr :: proc(w: Writer, p: rawptr, byte_size: int) -> (n: int, err: Error) {
  8. return write(w, mem.byte_slice(p, byte_size));
  9. }
  10. read_ptr_at :: proc(r: Reader_At, p: rawptr, byte_size: int, offset: i64) -> (n: int, err: Error) {
  11. return read_at(r, mem.byte_slice(p, byte_size), offset);
  12. }
  13. write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64) -> (n: int, err: Error) {
  14. return write_at(w, mem.byte_slice(p, byte_size), offset);
  15. }
  16. write_u64 :: proc(w: Writer, i: u64, base: int = 10) -> (n: int, err: Error) {
  17. buf: [32]byte;
  18. s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil);
  19. return write_string(w, s);
  20. }
  21. write_i64 :: proc(w: Writer, i: i64, base: int = 10) -> (n: int, err: Error) {
  22. buf: [32]byte;
  23. s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil);
  24. return write_string(w, s);
  25. }
  26. write_uint :: proc(w: Writer, i: uint, base: int = 10) -> (n: int, err: Error) {
  27. return write_u64(w, u64(i), base);
  28. }
  29. write_int :: proc(w: Writer, i: int, base: int = 10) -> (n: int, err: Error) {
  30. return write_i64(w, i64(i), base);
  31. }
  32. Tee_Reader :: struct {
  33. r: Reader,
  34. w: Writer,
  35. }
  36. @(private)
  37. _tee_reader_vtable := &Stream_VTable{
  38. impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
  39. t := (^Tee_Reader)(s.stream_data);
  40. n, err = read(t.r, p);
  41. if n > 0 {
  42. if wn, werr := write(t.w, p[:n]); werr != nil {
  43. return wn, werr;
  44. }
  45. }
  46. return;
  47. },
  48. };
  49. // tee_reader_init returns a Reader that writes to 'w' what it reads from 'r'
  50. // All reads from 'r' performed through it are matched with a corresponding write to 'w'
  51. // There is no internal buffering done
  52. // The write must complete before th read completes
  53. // Any error encountered whilst writing is reported as a 'read' error
  54. // tee_reader_init must call io.destroy when done with
  55. tee_reader_init :: proc(t: ^Tee_Reader, r: Reader, w: Writer, allocator := context.allocator) -> Reader {
  56. t.r, t.w = r, w;
  57. return tee_reader_to_reader(t);
  58. }
  59. tee_reader_to_reader :: proc(t: ^Tee_Reader) -> (r: Reader) {
  60. r.stream_data = t;
  61. r.stream_vtable = _tee_reader_vtable;
  62. return;
  63. }
  64. // A Limited_Reader reads from r but limits the amount of data returned to just n bytes.
  65. // Each call to read updates n to reflect the new amount remaining.
  66. // read returns EOF when n <= 0 or when the underlying r returns EOF.
  67. Limited_Reader :: struct {
  68. r: Reader, // underlying reader
  69. n: i64, // max_bytes
  70. }
  71. @(private)
  72. _limited_reader_vtable := &Stream_VTable{
  73. impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
  74. l := (^Limited_Reader)(s.stream_data);
  75. if l.n <= 0 {
  76. return 0, .EOF;
  77. }
  78. p := p;
  79. if i64(len(p)) > l.n {
  80. p = p[0:l.n];
  81. }
  82. n, err = read(l.r, p);
  83. l.n -= i64(n);
  84. return;
  85. },
  86. };
  87. limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
  88. l.r = r;
  89. l.n = n;
  90. return limited_reader_to_reader(l);
  91. }
  92. limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) {
  93. r.stream_vtable = _limited_reader_vtable;
  94. r.stream_data = l;
  95. return;
  96. }
  97. // Section_Reader implements read, seek, and read_at on a section of an underlying Reader_At
  98. Section_Reader :: struct {
  99. r: Reader_At,
  100. base: i64,
  101. off: i64,
  102. limit: i64,
  103. }
  104. section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) {
  105. s.r = r;
  106. s.off = off;
  107. s.limit = off + n;
  108. return;
  109. }
  110. section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) {
  111. out.stream_data = s;
  112. out.stream_vtable = _section_reader_vtable;
  113. return;
  114. }
  115. @(private)
  116. _section_reader_vtable := &Stream_VTable{
  117. impl_read = proc(stream: Stream, p: []byte) -> (n: int, err: Error) {
  118. s := (^Section_Reader)(stream.stream_data);
  119. if s.off >= s.limit {
  120. return 0, .EOF;
  121. }
  122. p := p;
  123. if max := s.limit - s.off; i64(len(p)) > max {
  124. p = p[0:max];
  125. }
  126. n, err = read_at(s.r, p, s.off);
  127. s.off += i64(n);
  128. return;
  129. },
  130. impl_read_at = proc(stream: Stream, p: []byte, off: i64) -> (n: int, err: Error) {
  131. s := (^Section_Reader)(stream.stream_data);
  132. p, off := p, off;
  133. if off < 0 || off >= s.limit - s.base {
  134. return 0, .EOF;
  135. }
  136. off += s.base;
  137. if max := s.limit - off; i64(len(p)) > max {
  138. p = p[0:max];
  139. n, err = read_at(s.r, p, off);
  140. if err == nil {
  141. err = .EOF;
  142. }
  143. return;
  144. }
  145. return read_at(s.r, p, off);
  146. },
  147. impl_seek = proc(stream: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
  148. s := (^Section_Reader)(stream.stream_data);
  149. offset := offset;
  150. switch whence {
  151. case:
  152. return 0, .Invalid_Whence;
  153. case .Start:
  154. offset += s.base;
  155. case .Current:
  156. offset += s.off;
  157. case .End:
  158. offset += s.limit;
  159. }
  160. if offset < s.base {
  161. return 0, .Invalid_Offset;
  162. }
  163. s.off = offset;
  164. n = offset - s.base;
  165. return;
  166. },
  167. impl_size = proc(stream: Stream) -> i64 {
  168. s := (^Section_Reader)(stream.stream_data);
  169. return s.limit - s.base;
  170. },
  171. };