github.com/robotn/xgb@v0.0.0-20190912153532-2cb92d044934/xgbgen/request_reply.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "unicode" 7 ) 8 9 // Request represents all XML 'request' nodes. 10 // If the request doesn't have a reply, Reply is nil. 11 type Request struct { 12 srcName string // The Go name of this request. 13 xmlName string // The XML name of this request. 14 Opcode int 15 Combine bool // Not currently used. 16 Fields []Field // All fields in the request. 17 Reply *Reply // A reply, if one exists for this request. 18 } 19 20 type Requests []*Request 21 22 func (rs Requests) Len() int { return len(rs) } 23 func (rs Requests) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] } 24 func (rs Requests) Less(i, j int) bool { return rs[i].xmlName < rs[j].xmlName } 25 26 // Initialize creates the proper Go source name for this request. 27 // It also initializes the reply if one exists, and all fields in this request. 28 func (r *Request) Initialize(p *Protocol) { 29 r.srcName = SrcName(p, r.xmlName) 30 if p.isExt() { 31 r.srcName = r.srcName 32 } 33 34 if r.Reply != nil { 35 r.Reply.Initialize(p) 36 } 37 for _, field := range r.Fields { 38 field.Initialize(p) 39 } 40 } 41 42 func (r *Request) SrcName() string { 43 return r.srcName 44 } 45 46 func (r *Request) XmlName() string { 47 return r.xmlName 48 } 49 50 // ReplyName gets the Go source name of the function that generates a 51 // reply type from a slice of bytes. 52 // The generated function is not currently exported. 53 func (r *Request) ReplyName() string { 54 if r.Reply == nil { 55 log.Panicf("Cannot call 'ReplyName' on request %s, which has no reply.", 56 r.SrcName()) 57 } 58 name := r.SrcName() 59 lower := string(unicode.ToLower(rune(name[0]))) + name[1:] 60 return fmt.Sprintf("%sReply", lower) 61 } 62 63 // ReplyTypeName gets the Go source name of the type holding all reply data 64 // for this request. 65 func (r *Request) ReplyTypeName() string { 66 if r.Reply == nil { 67 log.Panicf("Cannot call 'ReplyName' on request %s, which has no reply.", 68 r.SrcName()) 69 } 70 return fmt.Sprintf("%sReply", r.SrcName()) 71 } 72 73 // ReqName gets the Go source name of the function that generates a byte 74 // slice from a list of parameters. 75 // The generated function is not currently exported. 76 func (r *Request) ReqName() string { 77 name := r.SrcName() 78 lower := string(unicode.ToLower(rune(name[0]))) + name[1:] 79 return fmt.Sprintf("%sRequest", lower) 80 } 81 82 // CookieName gets the Go source name of the type that holds cookies for 83 // this request. 84 func (r *Request) CookieName() string { 85 return fmt.Sprintf("%sCookie", r.SrcName()) 86 } 87 88 // Size for Request needs a context. 89 // Namely, if this is an extension, we need to account for *four* bytes 90 // of a header (extension opcode, request opcode, and the sequence number). 91 // If it's a core protocol request, then we only account for *three* 92 // bytes of the header (remove the extension opcode). 93 func (r *Request) Size(c *Context) Size { 94 size := newFixedSize(0, true) 95 96 // If this is a core protocol request, we squeeze in an extra byte of 97 // data (from the fields below) between the opcode and the size of the 98 // request. In an extension request, this byte is always occupied 99 // by the opcode of the request (while the first byte is always occupied 100 // by the opcode of the extension). 101 if !c.protocol.isExt() { 102 size = size.Add(newFixedSize(3, true)) 103 } else { 104 size = size.Add(newFixedSize(4, true)) 105 } 106 107 for _, field := range r.Fields { 108 switch field.(type) { 109 case *LocalField: // local fields don't go over the wire 110 continue 111 case *SingleField: 112 // mofos!!! 113 if r.SrcName() == "ConfigureWindow" && 114 field.SrcName() == "ValueMask" { 115 116 continue 117 } 118 size = size.Add(field.Size()) 119 default: 120 size = size.Add(field.Size()) 121 } 122 } 123 return newExpressionSize(&Padding{ 124 Expr: size.Expression, 125 }, size.exact) 126 } 127 128 // Reply encapsulates the fields associated with a 'reply' element. 129 type Reply struct { 130 Fields []Field 131 } 132 133 // Size gets the number of bytes in this request's reply. 134 // A reply always has at least 7 bytes: 135 // 1 byte: A reply discriminant (first byte set to 1) 136 // 2 bytes: A sequence number 137 // 4 bytes: Number of additional bytes in 4-byte units past initial 32 bytes. 138 func (r *Reply) Size() Size { 139 size := newFixedSize(0, true) 140 141 // Account for reply discriminant, sequence number and reply length 142 size = size.Add(newFixedSize(7, true)) 143 144 for _, field := range r.Fields { 145 size = size.Add(field.Size()) 146 } 147 return size 148 } 149 150 func (r *Reply) Initialize(p *Protocol) { 151 for _, field := range r.Fields { 152 field.Initialize(p) 153 } 154 }