util.odin 4.3 KB

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