package tape import "fmt" type Tag byte; const ( SI Tag = 0 << 5 // Small integer LI Tag = 1 << 5 // Large integer FP Tag = 2 << 5 // Floating point SBA Tag = 3 << 5 // Small byte array LBA Tag = 4 << 5 // Large byte array OTA Tag = 5 << 5 // One-tag array KTV Tag = 6 << 5 // Key-tag-value table TNMask Tag = 0xE0 // The entire TN bitfield CNMask Tag = 0x1F // The entire CN bitfield CNLimit Tag = 32 // All valid CNs are < CNLimit ) func (tag Tag) TN() int { return int(tag >> 5) } func (tag Tag) CN() int { return int(tag & CNMask) } func (tag Tag) WithCN(cn int) Tag { return (tag & TNMask) | Tag(cn % 32) } func (tag Tag) WithoutCN() Tag { return tag.WithCN(0) } func (tag Tag) Is(other Tag) bool { return tag.TN() == other.TN() } func (tag Tag) String() string { tn := fmt.Sprint(tag.TN()) switch tag.WithoutCN() { case SI: tn = "SI" case LI: tn = "LI" case FP: tn = "FP" case SBA: tn = "SBA" case LBA: tn = "LBA" case OTA: tn = "OTA" case KTV: tn = "KTV" } return fmt.Sprintf("%s:%d", tn, tag.CN()) } // BufferTag returns the appropriate tag for a buffer. func BufferTag(value []byte) Tag { return bufferLenTag(len(value)) } func bufferLenTag(length int) Tag { if length < int(CNLimit) { return SBA.WithCN(length) } else { return LBA.WithCN(IntBytes(uint64(length))) } }