github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/bnry/write.go (about) 1 package bnry 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 "math" 9 "reflect" 10 "strings" 11 12 "golang.org/x/exp/constraints" 13 ) 14 15 // Write writes the given values to the given writer. 16 // Values should be of any of the supported types. 17 // Panics if a value is of an unsupported type. 18 func Write(w io.Writer, vals ...any) error { 19 return NewWriter(w).Write(vals...) 20 } 21 22 // MarshalBinary writes the given values to a byte slice. 23 // Values should be of any of the supported types. 24 // Panics if a value is of an unsupported type. 25 func MarshalBinary(vals ...any) []byte { 26 buf := bytes.NewBuffer(nil) 27 NewWriter(buf).Write(vals...) 28 return buf.Bytes() 29 } 30 31 type Writer struct { 32 w io.Writer 33 buf [binary.MaxVarintLen64]byte 34 } 35 36 func NewWriter(w io.Writer) *Writer { 37 return &Writer{w: w} 38 } 39 40 // Write writes the given values. 41 // Values should be of any of the supported types. 42 // Panics if a value is of an unsupported type. 43 func (w *Writer) Write(vals ...any) error { 44 for _, v := range vals { 45 if err := w.writeSingle(v); err != nil { 46 return err 47 } 48 } 49 return nil 50 } 51 52 // Writes a single value as binary. 53 func (w *Writer) writeSingle(val any) error { 54 switch val := val.(type) { 55 case uint8: 56 return w.writeByte(val) 57 case uint16: 58 return writeUint(w, val) 59 case uint32: 60 return writeUint(w, val) 61 case uint64: 62 return writeUint(w, val) 63 case uint: 64 return writeUint(w, val) 65 case int8: 66 return w.writeByte(byte(val)) 67 case int16: 68 return writeInt(w, val) 69 case int32: 70 return writeInt(w, val) 71 case int64: 72 return writeInt(w, val) 73 case int: 74 return writeInt(w, val) 75 case float32: 76 return writeUint(w, math.Float32bits(val)) 77 case float64: 78 return writeUint(w, math.Float64bits(val)) 79 case bool: 80 return w.writeByte(boolToByte(val)) 81 case string: 82 return w.writeString(val) 83 case []uint8: 84 return w.writeUint8Slice(val) 85 case []uint16: 86 return writeUintSlice(w, val) 87 case []uint32: 88 return writeUintSlice(w, val) 89 case []uint64: 90 return writeUintSlice(w, val) 91 case []uint: 92 return writeUintSlice(w, val) 93 case []int8: 94 return w.writeInt8Slice(val) 95 case []int16: 96 return writeIntSlice(w, val) 97 case []int32: 98 return writeIntSlice(w, val) 99 case []int64: 100 return writeIntSlice(w, val) 101 case []int: 102 return writeIntSlice(w, val) 103 case []float32: 104 return w.writeFloat32Slice(val) 105 case []float64: 106 return w.writeFloat64Slice(val) 107 case []bool: 108 return w.writeBoolSlice(val) 109 case []string: 110 return w.writeStringSlice(val) 111 default: 112 panic(fmt.Sprintf("unsupported type: %v", 113 reflect.TypeOf(val).Name())) 114 } 115 } 116 117 func (w *Writer) writeByte(b byte) error { 118 w.buf[0] = b 119 _, err := w.w.Write(w.buf[:1]) 120 return err 121 } 122 123 func writeUint[T constraints.Unsigned](w *Writer, i T) error { 124 _, err := w.w.Write(binary.AppendUvarint(w.buf[:0], uint64(i))) 125 return err 126 } 127 128 func writeInt[T constraints.Signed](w *Writer, i T) error { 129 _, err := w.w.Write(binary.AppendVarint(w.buf[:0], int64(i))) 130 return err 131 } 132 133 func (w *Writer) writeUint8Slice(s []uint8) error { 134 if err := writeUint(w, uint(len(s))); err != nil { 135 return err 136 } 137 _, err := w.w.Write(s) 138 return err 139 } 140 141 func (w *Writer) writeString(s string) error { 142 if err := writeUint(w, uint(len(s))); err != nil { 143 return err 144 } 145 _, err := strings.NewReader(s).WriteTo(w.w) 146 return err 147 } 148 149 func (w *Writer) writeInt8Slice(s []int8) error { 150 if err := writeUint(w, uint(len(s))); err != nil { 151 return err 152 } 153 for _, x := range s { 154 if err := w.writeByte(byte(x)); err != nil { 155 return err 156 } 157 } 158 return nil 159 } 160 161 func writeUintSlice[T constraints.Unsigned](w *Writer, s []T) error { 162 if err := writeUint(w, uint(len(s))); err != nil { 163 return err 164 } 165 for _, x := range s { 166 if err := writeUint(w, x); err != nil { 167 return err 168 } 169 } 170 return nil 171 } 172 173 func writeIntSlice[T constraints.Signed](w *Writer, s []T) error { 174 if err := writeUint(w, uint(len(s))); err != nil { 175 return err 176 } 177 for _, x := range s { 178 if err := writeInt(w, x); err != nil { 179 return err 180 } 181 } 182 return nil 183 } 184 185 func (w *Writer) writeFloat32Slice(s []float32) error { 186 if err := writeUint(w, uint(len(s))); err != nil { 187 return err 188 } 189 for _, x := range s { 190 if err := writeUint(w, math.Float32bits(x)); err != nil { 191 return err 192 } 193 } 194 return nil 195 } 196 197 func (w *Writer) writeFloat64Slice(s []float64) error { 198 if err := writeUint(w, uint(len(s))); err != nil { 199 return err 200 } 201 for _, x := range s { 202 if err := writeUint(w, math.Float64bits(x)); err != nil { 203 return err 204 } 205 } 206 return nil 207 } 208 209 func (w *Writer) writeBoolSlice(s []bool) error { 210 if err := writeUint(w, uint(len(s))); err != nil { 211 return err 212 } 213 for _, x := range s { 214 if err := w.writeByte(boolToByte(x)); err != nil { 215 return err 216 } 217 } 218 return nil 219 } 220 221 func (w *Writer) writeStringSlice(s []string) error { 222 if err := writeUint(w, uint(len(s))); err != nil { 223 return err 224 } 225 for _, x := range s { 226 if err := w.writeString(x); err != nil { 227 return err 228 } 229 } 230 return nil 231 } 232 233 func boolToByte(b bool) byte { 234 if b { 235 return 1 236 } else { 237 return 0 238 } 239 }