package tape import "iter" // DecodePairs decodes message tag/value pairs from a byte slice. It returns an // iterator over all pairs, where the first value is the tag and the second is // the value. If data yielded by the iterator is retained, it must be copied // first. func DecodePairs(data []byte) (iter.Seq2[uint16, []byte], error) { // determine section bounds if len(data) < 2 { return nil, ErrDataTooLarge } length16, _ := DecodeI16[uint16](data[0:2]) data = data[2:] length := int(length16) headerSize := length * 4 if len(data) < headerSize { return nil, ErrDataTooLarge } valuesData := data[headerSize:] // ensure the value buffer is big enough var valuesSize int for index := range length { offset := index * 4 end, _ := DecodeI16[uint16](data[offset + 2:offset + 4]) valuesSize = int(end) } if valuesSize > len(valuesData) { return nil, ErrDataTooLarge } // return iterator return func(yield func(uint16, []byte) bool) { start := uint16(0) for index := range length { offset := index * 4 key , _ := DecodeI16[uint16](data[offset + 0:offset + 2]) end, _ := DecodeI16[uint16](data[offset + 2:offset + 4]) // if nextValuesOffset < len(valuesData) { if !yield(key, valuesData[start:end]) { return } // } else { // if !yield(key, nil) { // return // } // } start = end } }, nil } // EncodePairs encodes message tag/value pairs into a byte slice. func EncodePairs(pairs map[uint16] []byte) ([]byte, error) { // determine section bounds headerSize := 2 + len(pairs) * 4 valuesSize := 0 for _, value := range pairs { valuesSize += len(value) } // generate data buffer := make([]byte, headerSize + valuesSize) length16, ok := U16CastSafe(len(pairs)) if !ok { return nil, ErrDataTooLarge } EncodeI16[uint16](buffer[0:2], length16) index := 0 end := headerSize for key, value := range pairs { start := end end += len(value) tagOffset := 2 + index * 4 end16, ok := U16CastSafe(end - headerSize) if !ok { return nil, ErrDataTooLarge } // write tag and length EncodeI16[uint16](buffer[tagOffset + 0:tagOffset + 2], key) EncodeI16[uint16](buffer[tagOffset + 2:tagOffset + 4], end16) // write value copy(buffer[start:end], value) index ++ } return buffer, nil }