hopp/tape/encode.go

119 lines
3.6 KiB
Go

package tape
import "io"
import "math"
import "bufio"
// Encodable is any type that can write itself to an encoder.
type Encodable interface {
// Encode sends data to encoder. It returns the amount of bytes written,
// and an error if the write stopped early.
Encode(encoder *Encoder) (n int, err error)
}
// Encoder encodes data to an io.Writer.
type Encoder struct {
bufio.Writer
}
// NewEncoder creates a new encoder that writes to writer.
func NewEncoder(writer io.Writer) *Encoder {
encoder := &Encoder { }
encoder.Reset(writer)
return encoder
}
// WriteInt8 encodes an 8-bit signed integer to the output writer.
func (this *Encoder) WriteInt8(value int8) (n int, err error) {
return this.WriteUint8(uint8(value))
}
// WriteUint8 encodes an 8-bit unsigned integer to the output writer.
func (this *Encoder) WriteUint8(value uint8) (n int, err error) {
return this.Write([]byte { byte(value) })
}
// WriteInt16 encodes an 16-bit signed integer to the output writer.
func (this *Encoder) WriteInt16(value int16) (n int, err error) {
return this.WriteUint16(uint16(value))
}
// WriteUint16 encodes an 16-bit unsigned integer to the output writer.
func (this *Encoder) WriteUint16(value uint16) (n int, err error) {
return this.Write([]byte {
byte(value >> 8),
byte(value),
})
}
// WriteInt32 encodes an 32-bit signed integer to the output writer.
func (this *Encoder) WriteInt32(value int32) (n int, err error) {
return this.WriteUint32(uint32(value))
}
// WriteUint32 encodes an 32-bit unsigned integer to the output writer.
func (this *Encoder) WriteUint32(value uint32) (n int, err error) {
return this.Write([]byte {
byte(value >> 24),
byte(value >> 16),
byte(value >> 8),
byte(value),
})
}
// WriteInt64 encodes an 64-bit signed integer to the output writer.
func (this *Encoder) WriteInt64(value int64) (n int, err error) {
return this.WriteUint64(uint64(value))
}
// WriteUint64 encodes an 64-bit unsigned integer to the output writer.
func (this *Encoder) WriteUint64(value uint64) (n int, err error) {
return this.Write([]byte {
byte(value >> 56),
byte(value >> 48),
byte(value >> 40),
byte(value >> 32),
byte(value >> 24),
byte(value >> 16),
byte(value >> 8),
byte(value),
})
}
// WriteIntN encodes an N-byte signed integer to the output writer.
func (this *Encoder) WriteIntN(value int64, bytes int) (n int, err error) {
return this.WriteUintN(uint64(value), bytes)
}
// for Write/ReadUintN, increase buffers if go somehow gets support for over 64
// bit integers. we could also make an expanding int type in goutil to use here,
// or maybe there is one in the stdlib. keep the int64 versions as well though
// because its ergonomic.
// WriteUintN encodes an N-byte unsigned integer to the output writer.
func (this *Encoder) WriteUintN(value uint64, bytes int) (n int, err error) {
// TODO: don't make multiple write calls (without allocating)
buffer := [1]byte { }
for bytesLeft := bytes; bytesLeft > 0; bytesLeft -- {
buffer[0] = byte(value) >> ((bytesLeft - 1) * 8)
nn, err := this.Write(buffer[:])
n += nn; if err != nil { return n, err }
}
return n, nil
}
// WriteFloat32 encodes a 32-bit floating point value to the output writer.
func (this *Encoder) WriteFloat32(value float32) (n int, err error) {
return this.WriteUint32(math.Float32bits(value))
}
// WriteFloat64 encodes a 64-bit floating point value to the output writer.
func (this *Encoder) WriteFloat64(value float64) (n int, err error) {
return this.WriteUint64(math.Float64bits(value))
}
// WriteTag encodes a [Tag] to the output writer.
func (this *Encoder) WriteTag(value Tag) (n int, err error) {
return this.WriteUint8(uint8(value))
}