package tape import "io" import "math" // 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 wraps an [io.Writer] and encodes data to it. type Encoder struct { io.Writer } // WriteByte encodes a single byte to the output writer. func (this *Encoder) WriteByte(value byte) (n int, err error) { return this.WriteByte(uint8(value)) } // 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 below functions, 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)) }