-
-
Notifications
You must be signed in to change notification settings - Fork 120
/
write.go
108 lines (94 loc) · 2.28 KB
/
write.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
}