go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/recordio/writer.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package recordio 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "io" 21 ) 22 23 func writeFrameHeader(w io.Writer, frameSize uint64) (int, error) { 24 sizeBuf := make([]byte, binary.MaxVarintLen64) 25 return w.Write(sizeBuf[:binary.PutUvarint(sizeBuf, frameSize)]) 26 } 27 28 // WriteFrame writes a single frame to an io.Writer. 29 func WriteFrame(w io.Writer, frame []byte) (int, error) { 30 count, err := writeFrameHeader(w, uint64(len(frame))) 31 if err != nil { 32 return count, err 33 } 34 35 amount, err := w.Write(frame) 36 count += amount 37 if err != nil { 38 return count, err 39 } 40 41 return count, nil 42 } 43 44 // Writer implements the io.Writer interface. Data written to the Writer is 45 // translated into a series of frames. Each frame is spearated by a call to 46 // Flush. 47 // 48 // Frame boundaries are created by calling Flush. Flush will always write a 49 // frame, even if the frame's data size is zero. 50 // 51 // Data written over consecutive Write calls belongs to the same frame. It is 52 // buffered until a frame boundary is created via Flush(). 53 type Writer interface { 54 io.Writer 55 56 // Flush writes the buffered frame 57 Flush() error 58 59 // Reset clears the writer state and attaches it to a new inner Writer 60 // instance. 61 Reset(io.Writer) 62 } 63 64 // writer implements the Writer interface by wrapping an io.Writer. 65 type writer struct { 66 inner io.Writer 67 buf bytes.Buffer 68 } 69 70 // NewWriter creates a new Writer instance that data as frames to an underlying 71 // io.Writer. 72 func NewWriter(w io.Writer) Writer { 73 return &writer{ 74 inner: w, 75 } 76 } 77 78 func (w *writer) Write(data []byte) (int, error) { 79 return w.buf.Write(data) 80 } 81 82 func (w *writer) Flush() error { 83 _, err := WriteFrame(w.inner, w.buf.Bytes()) 84 if err != nil { 85 return err 86 } 87 88 w.buf.Reset() 89 return nil 90 } 91 92 func (w *writer) Reset(inner io.Writer) { 93 w.inner = inner 94 w.buf.Reset() 95 }