You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

108 lines
2.3 KiB

package entity
import (
"io"
"unicode/utf8"
)
// ComputeLength returns length of s encoded as UTF-16 string.
//
// While Telegram API docs state that they expect the number of UTF-8
// code points, in fact they are talking about UTF-16 code units.
func ComputeLength(s string) int {
// From utf16 package.
n := 0
for _, v := range s {
n += utf16RuneLen(v)
}
return n
}
// ComputeLengthBytes returns length of s encoded as UTF-16 string.
//
// While Telegram API docs state that they expect the number of UTF-8
// code points, in fact they are talking about UTF-16 code units.
func ComputeLengthBytes(s []byte) (n int) {
// From utf16 package.
var i int
for i < len(s) {
v, size := utf8.DecodeRune(s[i:])
i += size
n += utf16RuneLen(v)
}
return n
}
func utf16RuneLen(v rune) int {
const (
surrSelf = 0x10000
maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
)
if surrSelf <= v && v <= maxRune {
return 2
}
return 1
}
func (b *Builder) appendMessage(s string, formats ...Formatter) *Builder {
if s == "" {
return b
}
offset := b.utf16length
length := ComputeLength(s)
b.appendEntities(offset, length, utf8entity{
offset: b.message.Len(),
length: len(s),
}, formats...)
_, _ = b.WriteString(s)
return b
}
func (b *Builder) appendEntities(offset, length int, u utf8entity, formats ...Formatter) *Builder {
b.lastFormatIndex = len(b.entities)
for i := range formats {
b.entities = append(b.entities, formats[i](offset, length))
b.lengths = append(b.lengths, u)
}
return b
}
var _ = []interface {
io.Writer
io.StringWriter
io.ByteWriter
WriteRune(rune) (int, error)
}{
(*Builder)(nil),
}
// Write implements io.Writer.
func (b *Builder) Write(s []byte) (int, error) {
n, err := b.message.Write(s)
b.utf16length += ComputeLengthBytes(s)
return n, err
}
// WriteString implements io.StringWriter.
func (b *Builder) WriteString(s string) (int, error) {
n, err := b.message.WriteString(s)
b.utf16length += ComputeLength(s)
return n, err
}
// WriteByte implements io.ByteWriter.
func (b *Builder) WriteByte(s byte) error {
err := b.message.WriteByte(s)
b.utf16length++
return err
}
// WriteRune implements rune writer.
func (b *Builder) WriteRune(s rune) (int, error) {
n, err := b.message.WriteRune(s)
b.utf16length += utf16RuneLen(s)
return n, err
}