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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
package main
import (
"fmt"
"log"
"unicode"
)
// Doc contains any documentation, if present. Example C code is excluded.
type Doc struct {
Brief string // short description
Description string // long description
Fields map[string]string // from field name to description
Errors map[string]string // from error type to description
}
// DescribeField is an accessor that supports nil receivers.
func (d *Doc) DescribeField(name string) string {
if d == nil {
return ""
}
return d.Fields[name]
}
// Request represents all XML 'request' nodes.
// If the request doesn't have a reply, Reply is nil.
type Request struct {
srcName string // The Go name of this request.
xmlName string // The XML name of this request.
Opcode int
Combine bool // Not currently used.
Fields []Field // All fields in the request.
Reply *Reply // A reply, if one exists for this request.
Doc Doc // Documentation.
}
type Requests []*Request
func (rs Requests) Len() int { return len(rs) }
func (rs Requests) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
func (rs Requests) Less(i, j int) bool { return rs[i].xmlName < rs[j].xmlName }
// Initialize creates the proper Go source name for this request.
// It also initializes the reply if one exists, and all fields in this request.
func (r *Request) Initialize(p *Protocol) {
r.srcName = SrcName(p, r.xmlName)
if p.isExt() {
r.srcName = r.srcName
}
if r.Reply != nil {
r.Reply.Initialize(p)
}
for _, field := range r.Fields {
field.Initialize(p)
}
}
func (r *Request) SrcName() string {
return r.srcName
}
func (r *Request) XmlName() string {
return r.xmlName
}
// ReplyName gets the Go source name of the function that generates a
// reply type from a slice of bytes.
// The generated function is not currently exported.
func (r *Request) ReplyName() string {
if r.Reply == nil {
log.Panicf("Cannot call 'ReplyName' on request %s, which has no reply.",
r.SrcName())
}
name := r.SrcName()
lower := string(unicode.ToLower(rune(name[0]))) + name[1:]
return fmt.Sprintf("%sReply", lower)
}
// ReplyTypeName gets the Go source name of the type holding all reply data
// for this request.
func (r *Request) ReplyTypeName() string {
if r.Reply == nil {
log.Panicf("Cannot call 'ReplyName' on request %s, which has no reply.",
r.SrcName())
}
return fmt.Sprintf("%sReply", r.SrcName())
}
// ReqName gets the Go source name of the function that generates a byte
// slice from a list of parameters.
// The generated function is not currently exported.
func (r *Request) ReqName() string {
name := r.SrcName()
lower := string(unicode.ToLower(rune(name[0]))) + name[1:]
return fmt.Sprintf("%sRequest", lower)
}
// CookieName gets the Go source name of the type that holds cookies for
// this request.
func (r *Request) CookieName() string {
return fmt.Sprintf("%sCookie", r.SrcName())
}
// Size for Request needs a context.
// Namely, if this is an extension, we need to account for *four* bytes
// of a header (extension opcode, request opcode, and the sequence number).
// If it's a core protocol request, then we only account for *three*
// bytes of the header (remove the extension opcode).
func (r *Request) Size(c *Context) Size {
size := newFixedSize(0, true)
// If this is a core protocol request, we squeeze in an extra byte of
// data (from the fields below) between the opcode and the size of the
// request. In an extension request, this byte is always occupied
// by the opcode of the request (while the first byte is always occupied
// by the opcode of the extension).
if !c.protocol.isExt() {
size = size.Add(newFixedSize(3, true))
} else {
size = size.Add(newFixedSize(4, true))
}
for _, field := range r.Fields {
switch field := field.(type) {
case *LocalField: // local fields don't go over the wire
continue
case *SingleField:
fsz := field.Size()
if _, isstruct := field.Type.(*Struct); isstruct {
fsz.Expression = fsz.Expression.Specialize(field.SrcName())
}
size = size.Add(fsz)
default:
size = size.Add(field.Size())
}
}
return newExpressionSize(&Padding{
Expr: size.Expression,
}, size.exact)
}
// Reply encapsulates the fields associated with a 'reply' element.
type Reply struct {
Fields []Field
Doc Doc
}
// Size gets the number of bytes in this request's reply.
// A reply always has at least 7 bytes:
// 1 byte: A reply discriminant (first byte set to 1)
// 2 bytes: A sequence number
// 4 bytes: Number of additional bytes in 4-byte units past initial 32 bytes.
func (r *Reply) Size() Size {
size := newFixedSize(0, true)
// Account for reply discriminant, sequence number and reply length
size = size.Add(newFixedSize(7, true))
for _, field := range r.Fields {
size = size.Add(field.Size())
}
return size
}
func (r *Reply) Initialize(p *Protocol) {
for _, field := range r.Fields {
field.Initialize(p)
}
}
|