v2 / vlib / io / buffered_writer.v
105 lines · 95 sloc · 2.34 KB · 64a868ff2780efa6e9670c2459f015c92ffd1b7e
Raw
1module io
2
3pub struct BufferedWriter {
4mut:
5 n int
6 wr Writer
7pub mut:
8 buf []u8
9}
10
11@[params]
12pub struct BufferedWriterConfig {
13pub:
14 writer Writer
15 cap int = 128 * 1024
16}
17
18// new_buffered_writer creates a new BufferedWriter with the specified BufferedWriterConfig.
19// Returns an error when cap is 0 or negative.
20pub fn new_buffered_writer(o BufferedWriterConfig) !&BufferedWriter {
21 if o.cap < 1 {
22 return error('`o.cap` must be a positive integer')
23 }
24
25 return &BufferedWriter{
26 buf: []u8{len: o.cap}
27 wr: o.writer
28 }
29}
30
31// reset resets the buffer to its initial state.
32pub fn (mut b BufferedWriter) reset() {
33 cap := b.buf.len
34 b.buf = []u8{len: cap}
35 b.n = 0
36}
37
38// buffered returns the number of bytes currently stored in the buffer.
39pub fn (b BufferedWriter) buffered() int {
40 return b.n
41}
42
43// flush writes the buffered data to the underlying writer and clears the buffer, ensures all data is
44// written.
45// Returns an error if the writer fails to write all buffered data.
46pub fn (mut b BufferedWriter) flush() ! {
47 if b.buffered() == 0 {
48 return
49 }
50 mut written := 0
51 for written < b.n {
52 n := b.wr.write(b.buf[written..b.n]) or {
53 b.shift_unwritten_to_front(written)
54 return err
55 }
56 if n <= 0 || n > b.n - written {
57 b.shift_unwritten_to_front(written)
58 return error('writer returned an invalid number of bytes while flushing')
59 }
60 written += n
61 }
62 b.n = 0
63}
64
65// available returns the amount of available space left in the buffer.
66pub fn (b BufferedWriter) available() int {
67 return b.buf.len - b.n
68}
69
70fn (mut b BufferedWriter) shift_unwritten_to_front(written int) {
71 if written <= 0 {
72 return
73 }
74 remaining := b.n - written
75 if remaining <= 0 {
76 b.n = 0
77 return
78 }
79 copy(mut b.buf[..remaining], b.buf[written..b.n])
80 b.n = remaining
81}
82
83// write writes `src` in the buffer, flushing it to the underlying writer as needed, and returns the
84// number of bytes written.
85pub fn (mut b BufferedWriter) write(src []u8) !int {
86 mut written := 0
87 for written < src.len {
88 remaining := src.len - written
89 if b.buffered() == 0 && remaining > b.available() {
90 n := b.wr.write(src[written..])!
91 if n <= 0 || n > remaining {
92 return error('writer returned an invalid number of bytes while writing')
93 }
94 written += n
95 continue
96 }
97 n := copy(mut b.buf[b.n..], src[written..])
98 b.n += n
99 written += n
100 if b.available() == 0 {
101 b.flush()!
102 }
103 }
104 return written
105}
106