| 
									
										
										
										
											2022-05-08 19:49:45 +02:00
										 |  |  | package byteutil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"unicode/utf8" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2023-11-27 13:16:26 +00:00
										 |  |  | 	// ensure we conform | 
					
						
							|  |  |  | 	// to interfaces. | 
					
						
							| 
									
										
										
										
											2022-05-08 19:49:45 +02:00
										 |  |  | 	_ interface { | 
					
						
							|  |  |  | 		io.Writer | 
					
						
							|  |  |  | 		io.ByteWriter | 
					
						
							|  |  |  | 		WriteRune(rune) (int, error) | 
					
						
							|  |  |  | 		io.StringWriter | 
					
						
							|  |  |  | 		io.WriterAt | 
					
						
							|  |  |  | 		WriteStringAt(string, int64) (int, error) | 
					
						
							| 
									
										
										
										
											2023-11-27 13:16:26 +00:00
										 |  |  | 		io.ReaderFrom | 
					
						
							|  |  |  | 		io.WriterTo | 
					
						
							| 
									
										
										
										
											2022-05-08 19:49:45 +02:00
										 |  |  | 	} = (*Buffer)(nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ErrBeyondBufferLen is returned if .WriteAt() is attempted beyond buffer length. | 
					
						
							|  |  |  | 	ErrBeyondBufferLen = errors.New("start beyond buffer length") | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Buffer is a simple wrapper around a byte slice. | 
					
						
							|  |  |  | type Buffer struct{ B []byte } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteByte will append given byte to buffer, fulfilling io.ByteWriter. | 
					
						
							|  |  |  | func (buf *Buffer) WriteByte(c byte) error { | 
					
						
							|  |  |  | 	buf.B = append(buf.B, c) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteRune will append given rune to buffer. | 
					
						
							|  |  |  | func (buf *Buffer) WriteRune(r rune) (int, error) { | 
					
						
							|  |  |  | 	// Check for single-byte rune | 
					
						
							|  |  |  | 	if r < utf8.RuneSelf { | 
					
						
							|  |  |  | 		buf.B = append(buf.B, byte(r)) | 
					
						
							|  |  |  | 		return 1, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Before-len | 
					
						
							|  |  |  | 	l := len(buf.B) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Grow to max size rune | 
					
						
							|  |  |  | 	buf.Grow(utf8.UTFMax) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Write encoded rune to buffer | 
					
						
							|  |  |  | 	n := utf8.EncodeRune(buf.B[l:len(buf.B)], r) | 
					
						
							|  |  |  | 	buf.B = buf.B[:l+n] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return n, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Write will append given byte slice to buffer, fulfilling io.Writer. | 
					
						
							|  |  |  | func (buf *Buffer) Write(b []byte) (int, error) { | 
					
						
							|  |  |  | 	buf.B = append(buf.B, b...) | 
					
						
							|  |  |  | 	return len(b), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteString will append given string to buffer, fulfilling io.StringWriter. | 
					
						
							|  |  |  | func (buf *Buffer) WriteString(s string) (int, error) { | 
					
						
							|  |  |  | 	buf.B = append(buf.B, s...) | 
					
						
							|  |  |  | 	return len(s), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteAt will append given byte slice to buffer at index 'start', fulfilling io.WriterAt. | 
					
						
							|  |  |  | func (buf *Buffer) WriteAt(b []byte, start int64) (int, error) { | 
					
						
							|  |  |  | 	if start > int64(len(buf.B)) { | 
					
						
							|  |  |  | 		return 0, ErrBeyondBufferLen | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buf.Grow(len(b) - int(int64(len(buf.B))-start)) | 
					
						
							|  |  |  | 	return copy(buf.B[start:], b), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteStringAt will append given string to buffer at index 'start'. | 
					
						
							|  |  |  | func (buf *Buffer) WriteStringAt(s string, start int64) (int, error) { | 
					
						
							|  |  |  | 	if start > int64(len(buf.B)) { | 
					
						
							|  |  |  | 		return 0, ErrBeyondBufferLen | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buf.Grow(len(s) - int(int64(len(buf.B))-start)) | 
					
						
							|  |  |  | 	return copy(buf.B[start:], s), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-27 13:16:26 +00:00
										 |  |  | // ReadFrom will read bytes from reader into buffer, fulfilling io.ReaderFrom. | 
					
						
							|  |  |  | func (buf *Buffer) ReadFrom(r io.Reader) (int64, error) { | 
					
						
							|  |  |  | 	var nn int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure there's cap | 
					
						
							|  |  |  | 	// for a first read. | 
					
						
							|  |  |  | 	buf.Guarantee(512) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		// Read into next chunk of buffer. | 
					
						
							|  |  |  | 		n, err := r.Read(buf.B[len(buf.B):cap(buf.B)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Reslice buf + update count. | 
					
						
							|  |  |  | 		buf.B = buf.B[:len(buf.B)+n] | 
					
						
							|  |  |  | 		nn += int64(n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if err == io.EOF { | 
					
						
							|  |  |  | 				// mask EOF. | 
					
						
							|  |  |  | 				err = nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nn, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if len(buf.B) == cap(buf.B) { | 
					
						
							|  |  |  | 			// Add capacity (let append pick). | 
					
						
							|  |  |  | 			buf.B = append(buf.B, 0)[:len(buf.B)] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteTo will write bytes from buffer into writer, fulfilling io.WriterTo. | 
					
						
							|  |  |  | func (buf *Buffer) WriteTo(w io.Writer) (int64, error) { | 
					
						
							|  |  |  | 	n, err := w.Write(buf.B) | 
					
						
							|  |  |  | 	return int64(n), err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-08 19:49:45 +02:00
										 |  |  | // Len returns the length of the buffer's underlying byte slice. | 
					
						
							|  |  |  | func (buf *Buffer) Len() int { | 
					
						
							|  |  |  | 	return len(buf.B) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Cap returns the capacity of the buffer's underlying byte slice. | 
					
						
							|  |  |  | func (buf *Buffer) Cap() int { | 
					
						
							|  |  |  | 	return cap(buf.B) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Grow will increase the buffers length by 'sz', and the capacity by at least this. | 
					
						
							|  |  |  | func (buf *Buffer) Grow(sz int) { | 
					
						
							|  |  |  | 	buf.Guarantee(sz) | 
					
						
							|  |  |  | 	buf.B = buf.B[:len(buf.B)+sz] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Guarantee will guarantee buffer containers at least 'sz' remaining capacity. | 
					
						
							|  |  |  | func (buf *Buffer) Guarantee(sz int) { | 
					
						
							|  |  |  | 	if sz > cap(buf.B)-len(buf.B) { | 
					
						
							|  |  |  | 		nb := make([]byte, 2*cap(buf.B)+sz) | 
					
						
							|  |  |  | 		copy(nb, buf.B) | 
					
						
							|  |  |  | 		buf.B = nb[:len(buf.B)] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Truncate will reduce the length of the buffer by 'n'. | 
					
						
							|  |  |  | func (buf *Buffer) Truncate(n int) { | 
					
						
							|  |  |  | 	if n > len(buf.B) { | 
					
						
							|  |  |  | 		n = len(buf.B) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	buf.B = buf.B[:len(buf.B)-n] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Reset will reset the buffer length to 0 (retains capacity). | 
					
						
							|  |  |  | func (buf *Buffer) Reset() { | 
					
						
							|  |  |  | 	buf.B = buf.B[:0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String returns the underlying byte slice as a string. Please note | 
					
						
							|  |  |  | // this value is tied directly to the underlying byte slice, if you | 
					
						
							|  |  |  | // write to the buffer then returned string values will also change. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // To get an immutable string from buffered data, use string(buf.B). | 
					
						
							|  |  |  | func (buf *Buffer) String() string { | 
					
						
							|  |  |  | 	return B2S(buf.B) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Full returns the full capacity byteslice allocated for this buffer. | 
					
						
							|  |  |  | func (buf *Buffer) Full() []byte { | 
					
						
							|  |  |  | 	return buf.B[0:cap(buf.B)] | 
					
						
							|  |  |  | } |