utils/serialization.go (290 lines of code) (raw):

// Copyright (c) 2017-2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package utils import ( "bytes" "unsafe" ) // AlignOffset returns the next offset given a specific alignment. func AlignOffset(offset int, alignment int) int { if alignment > 1 { remainder := offset % alignment if remainder != 0 { return offset + alignment - remainder } } return offset } // BufferReader provides read function for different type to read from the underline buffer. type BufferReader struct { buffer []byte } // NewBufferReader creates a BufferReader. func NewBufferReader(buffer []byte) BufferReader { return BufferReader{buffer: buffer} } // ReadUint8 reads 1 byte from buffer. func (b BufferReader) ReadUint8(offset int) (uint8, error) { if offset+1 > len(b.buffer) { return 0, StackError(nil, "Failed to read uint8 from offset %d", offset) } return *(*uint8)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadInt8 reads 1 byte from buffer. func (b BufferReader) ReadInt8(offset int) (int8, error) { if offset+1 > len(b.buffer) { return 0, StackError(nil, "Failed to read int8 from offset %d", offset) } return *(*int8)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadUint16 reads 2 bytes from buffer. func (b BufferReader) ReadUint16(offset int) (uint16, error) { if offset+2 > len(b.buffer) { return 0, StackError(nil, "Failed to read uint16 from offset %d", offset) } return *(*uint16)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadInt16 reads 2 bytes from buffer. func (b BufferReader) ReadInt16(offset int) (int16, error) { if offset+2 > len(b.buffer) { return 0, StackError(nil, "Failed to read int16 from offset %d", offset) } return *(*int16)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadUint32 reads 4 bytes from buffer. func (b BufferReader) ReadUint32(offset int) (uint32, error) { if offset+4 > len(b.buffer) { return 0, StackError(nil, "Failed to read uint32 from offset %d", offset) } return *(*uint32)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadInt32 reads 4 bytes from buffer. func (b BufferReader) ReadInt32(offset int) (int32, error) { if offset+4 > len(b.buffer) { return 0, StackError(nil, "Failed to read int32 from offset %d", offset) } return *(*int32)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadUint64 reads 8 bytes from buffer. func (b BufferReader) ReadUint64(offset int) (uint64, error) { if offset+8 > len(b.buffer) { return 0, StackError(nil, "Failed to read uint64 from offset %d", offset) } return *(*uint64)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadInt64 reads 8 bytes from buffer. func (b BufferReader) ReadInt64(offset int) (int64, error) { if offset+8 > len(b.buffer) { return 0, StackError(nil, "Failed to read int64 from offset %d", offset) } return *(*int64)(unsafe.Pointer(&b.buffer[offset])), nil } // ReadFloat32 reads 4 bytes from buffer. func (b BufferReader) ReadFloat32(offset int) (float32, error) { if offset+4 > len(b.buffer) { return 0, StackError(nil, "Failed to read float32 from offset %d", offset) } return *(*float32)(unsafe.Pointer(&b.buffer[offset])), nil } // BufferWriter provides functions to write different data types into the underline buffer. It // supports both random access and sequential access. type BufferWriter struct { offset int bitOffset int buffer []byte } // NewBufferWriter creates a new buffer writer over a buffer. func NewBufferWriter(buffer []byte) BufferWriter { return BufferWriter{buffer: buffer} } // GetOffset returns the current offset value. func (b BufferWriter) GetOffset() int { return b.offset } // AlignBytes aligns the offset/bit offset to the next byte specified in alignment. // The new offset may cross the buffer boundary. func (b *BufferWriter) AlignBytes(alignment int) { if b.bitOffset > 0 { b.offset++ b.bitOffset = 0 } b.offset = AlignOffset(b.offset, alignment) } // SkipBytes moves the underline offset by specified bytes. // The new offset may cross the buffer boundary. func (b *BufferWriter) SkipBytes(bytes int) { b.AlignBytes(1) b.offset += bytes } // SkipBits moves the bit offset and possibly byte offset. // The new offset may cross the buffer boundary. func (b *BufferWriter) SkipBits(bits int) { b.bitOffset += bits b.offset += b.bitOffset / 8 b.bitOffset = b.bitOffset % 8 } // AppendBool append a boolean value to buffer and advances byte/bit offset. func (b *BufferWriter) AppendBool(value bool) error { if b.offset >= len(b.buffer) { return StackError(nil, "Failed to write bool to buffer at offset (%d,%d)", b.offset, b.bitOffset) } // Need to advance to the next byte. if value { b.buffer[b.offset] |= 0x1 << uint8(b.bitOffset) } else { b.buffer[b.offset] &^= 0x1 << uint8(b.bitOffset) } if b.bitOffset == 7 { b.offset++ b.bitOffset = 0 } else { b.bitOffset++ } return nil } // AppendInt8 writes a int8 value to buffer and advances offset. func (b *BufferWriter) AppendInt8(value int8) error { b.AlignBytes(1) if err := b.WriteInt8(value, b.offset); err != nil { return err } b.offset++ return nil } // AppendUint8 writes a uint8 value to buffer and advances offset. func (b *BufferWriter) AppendUint8(value uint8) error { b.AlignBytes(1) if err := b.WriteUint8(value, b.offset); err != nil { return err } b.offset++ return nil } // AppendInt16 writes a int16 value to buffer and advances offset. func (b *BufferWriter) AppendInt16(value int16) error { b.AlignBytes(1) if err := b.WriteInt16(value, b.offset); err != nil { return err } b.offset += 2 return nil } // AppendUint16 writes a uint16 value to buffer and advances offset. func (b *BufferWriter) AppendUint16(value uint16) error { b.AlignBytes(1) if err := b.WriteUint16(value, b.offset); err != nil { return err } b.offset += 2 return nil } // AppendInt32 writes a int32 value to buffer and advances offset. func (b *BufferWriter) AppendInt32(value int32) error { b.AlignBytes(1) if err := b.WriteInt32(value, b.offset); err != nil { return err } b.offset += 4 return nil } // AppendInt64 writes a int64 value to buffer and advances offset. func (b *BufferWriter) AppendInt64(value int64) error { b.AlignBytes(1) if err := b.WriteInt64(value, b.offset); err != nil { return err } b.offset += 8 return nil } // AppendUint32 writes a uint32 value to buffer and advances offset. func (b *BufferWriter) AppendUint32(value uint32) error { b.AlignBytes(1) if err := b.WriteUint32(value, b.offset); err != nil { return err } b.offset += 4 return nil } // AppendUint64 writes a uint64 value to buffer and advances offset. func (b *BufferWriter) AppendUint64(value uint64) error { b.AlignBytes(1) if err := b.WriteUint64(value, b.offset); err != nil { return err } b.offset += 8 return nil } // AppendFloat32 writes a float32 value to buffer and advances offset. func (b *BufferWriter) AppendFloat32(value float32) error { b.AlignBytes(1) if err := b.WriteFloat32(value, b.offset); err != nil { return err } b.offset += 4 return nil } // Append writes a byte slice to buffer and advances offset. func (b *BufferWriter) Append(bs []byte) error { b.AlignBytes(1) if _, err := b.WriteAt(bs, int64(b.offset)); err != nil { return err } b.offset += len(bs) return nil } // WriteInt8 writes a int8 value to buffer at given offset. func (b *BufferWriter) WriteInt8(value int8, offset int) error { if offset+1 > len(b.buffer) { return StackError(nil, "Failed to write int8 to buffer at offset %d", offset) } *(*int8)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteUint8 writes a uint8 value to buffer and advances offset. func (b *BufferWriter) WriteUint8(value uint8, offset int) error { if offset+1 > len(b.buffer) { return StackError(nil, "Failed to write uint8 to buffer at offset %d", offset) } *(*uint8)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteInt16 writes a int16 value to buffer and advances offset. func (b *BufferWriter) WriteInt16(value int16, offset int) error { if offset+2 > len(b.buffer) { return StackError(nil, "Failed to write int16 to buffer at offset %d", offset) } *(*int16)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteUint16 writes a uint16 value to buffer and advances offset. func (b *BufferWriter) WriteUint16(value uint16, offset int) error { if offset+2 > len(b.buffer) { return StackError(nil, "Failed to write uint16 to buffer at offset %d", offset) } *(*uint16)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteInt32 writes a int32 value to buffer and advances offset. func (b *BufferWriter) WriteInt32(value int32, offset int) error { if offset+4 > len(b.buffer) { return StackError(nil, "Failed to write int32 to buffer at offset %d", offset) } *(*int32)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteInt64 writes a int64 value to buffer and advances offset. func (b *BufferWriter) WriteInt64(value int64, offset int) error { if offset+8 > len(b.buffer) { return StackError(nil, "Failed to write int64 to buffer at offset %d", offset) } *(*int64)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteUint32 writes a uint32 value to buffer and advances offset. func (b *BufferWriter) WriteUint32(value uint32, offset int) error { if offset+4 > len(b.buffer) { return StackError(nil, "Failed to write uint32 to buffer at offset %d", offset) } *(*uint32)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteUint64 writes a uint64 value to buffer and advances offset. func (b *BufferWriter) WriteUint64(value uint64, offset int) error { if offset+8 > len(b.buffer) { return StackError(nil, "Failed to write uint64 to buffer at offset %d", offset) } *(*uint64)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // WriteFloat32 writes a float32 value to buffer and advances offset. func (b *BufferWriter) WriteFloat32(value float32, offset int) error { if offset+4 > len(b.buffer) { return StackError(nil, "Failed to write float32 to buffer at offset %d", offset) } *(*float32)(unsafe.Pointer(&b.buffer[offset])) = value return nil } // Write implements Write in io.Writer interface func (b *BufferWriter) Write(bs []byte) (int, error) { err := b.Append(bs) if err != nil { return 0, err } return len(bs), nil } // WriteAt implements WriteAt in io.WriterAt interface func (b *BufferWriter) WriteAt(bs []byte, offset int64) (int, error) { if offset+int64(len(bs)) > int64(len(b.buffer)) { return 0, StackError(nil, "Failed to write []byte to buffer at offset %d", offset) } copy(b.buffer[offset:], bs) return len(bs), nil } // ClosableBuffer is not really closable but just implements the utils.WriteSyncCloser interface. type ClosableBuffer struct { *bytes.Buffer } // Close just implements Close function of utils.WriteSyncCloser interface. func (cb *ClosableBuffer) Close() error { return nil } // ClosableReader is not really closable but just implements the utils.WriteSyncCloser interface. type ClosableReader struct { *bytes.Reader } // Close just implements Close function of utils.WriteSyncCloser interface. func (cr *ClosableReader) Close() error { return nil } // Sync just implements Sync function of utils.WriteSyncCloser interface. func (cr *ClosableBuffer) Sync() error { return nil }