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
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 |
|
}
|
|
|