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  }