aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/go_request_reply.go
diff options
context:
space:
mode:
authorPřemysl Janouch <p@janouch.name>2018-09-08 16:54:17 +0200
committerPřemysl Janouch <p@janouch.name>2018-09-08 16:54:17 +0200
commit3173202cc1e08762c6e156a8fffd23269a5ddb2b (patch)
tree95c4a06f8384d41b15e9c22afac0a387de79dc51 /nexgb/xgbgen/go_request_reply.go
parent632b3ae494d45755525644fe5d04475c95aae364 (diff)
parent3906399e7c2a40fbaf355de572cf50a314083f64 (diff)
downloadhaven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.tar.gz
haven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.tar.xz
haven-3173202cc1e08762c6e156a8fffd23269a5ddb2b.zip
Merge aarzilli/xgb, branch xcb1.12 as nexgb
History has been linearized and rewritten to stay under the new subdirectory. I want to make changes incompatible to BurntSushi/xgb. The history begs for being thrown away entirely because of its quality and because it doesn't cover the Google period but it is still useful for copyright tracking.
Diffstat (limited to 'nexgb/xgbgen/go_request_reply.go')
-rw-r--r--nexgb/xgbgen/go_request_reply.go242
1 files changed, 242 insertions, 0 deletions
diff --git a/nexgb/xgbgen/go_request_reply.go b/nexgb/xgbgen/go_request_reply.go
new file mode 100644
index 0000000..9cadc33
--- /dev/null
+++ b/nexgb/xgbgen/go_request_reply.go
@@ -0,0 +1,242 @@
+package main
+
+import (
+ "fmt"
+ "strings"
+)
+
+func (r *Request) Define(c *Context) {
+ c.Putln("// %s is a cookie used only for %s requests.",
+ r.CookieName(), r.SrcName())
+ c.Putln("type %s struct {", r.CookieName())
+ c.Putln("*xgb.Cookie")
+ c.Putln("}")
+ c.Putln("")
+ if r.Reply != nil {
+ c.Putln("// %s sends a checked request.", r.SrcName())
+ c.Putln("// If an error occurs, it will be returned with the reply "+
+ "by calling %s.Reply()", r.CookieName())
+ c.Putln("func %s(c *xgb.Conn, %s) %s {",
+ r.SrcName(), r.ParamNameTypes(), r.CookieName())
+ r.CheckExt(c)
+ c.Putln("cookie := c.NewCookie(true, true)")
+ c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
+ c.Putln("return %s{cookie}", r.CookieName())
+ c.Putln("}")
+ c.Putln("")
+
+ c.Putln("// %sUnchecked sends an unchecked request.", r.SrcName())
+ c.Putln("// If an error occurs, it can only be retrieved using " +
+ "xgb.WaitForEvent or xgb.PollForEvent.")
+ c.Putln("func %sUnchecked(c *xgb.Conn, %s) %s {",
+ r.SrcName(), r.ParamNameTypes(), r.CookieName())
+ r.CheckExt(c)
+ c.Putln("cookie := c.NewCookie(false, true)")
+ c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
+ c.Putln("return %s{cookie}", r.CookieName())
+ c.Putln("}")
+ c.Putln("")
+
+ r.ReadReply(c)
+ } else {
+ c.Putln("// %s sends an unchecked request.", r.SrcName())
+ c.Putln("// If an error occurs, it can only be retrieved using " +
+ "xgb.WaitForEvent or xgb.PollForEvent.")
+ c.Putln("func %s(c *xgb.Conn, %s) %s {",
+ r.SrcName(), r.ParamNameTypes(), r.CookieName())
+ r.CheckExt(c)
+ c.Putln("cookie := c.NewCookie(false, false)")
+ c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
+ c.Putln("return %s{cookie}", r.CookieName())
+ c.Putln("}")
+ c.Putln("")
+
+ c.Putln("// %sChecked sends a checked request.", r.SrcName())
+ c.Putln("// If an error occurs, it can be retrieved using "+
+ "%s.Check()", r.CookieName())
+ c.Putln("func %sChecked(c *xgb.Conn, %s) %s {",
+ r.SrcName(), r.ParamNameTypes(), r.CookieName())
+ r.CheckExt(c)
+ c.Putln("cookie := c.NewCookie(true, false)")
+ c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
+ c.Putln("return %s{cookie}", r.CookieName())
+ c.Putln("}")
+ c.Putln("")
+
+ c.Putln("// Check returns an error if one occurred for checked " +
+ "requests that are not expecting a reply.")
+ c.Putln("// This cannot be called for requests expecting a reply, " +
+ "nor for unchecked requests.")
+ c.Putln("func (cook %s) Check() error {", r.CookieName())
+ c.Putln("return cook.Cookie.Check()")
+ c.Putln("}")
+ c.Putln("")
+ }
+ r.WriteRequest(c)
+}
+
+func (r *Request) CheckExt(c *Context) {
+ if !c.protocol.isExt() {
+ return
+ }
+ c.Putln("c.ExtLock.RLock()")
+ c.Putln("defer c.ExtLock.RUnlock()")
+ c.Putln("if _, ok := c.Extensions[\"%s\"]; !ok {", c.protocol.ExtXName)
+ c.Putln("panic(\"Cannot issue request '%s' using the uninitialized "+
+ "extension '%s'. %s.Init(connObj) must be called first.\")",
+ r.SrcName(), c.protocol.ExtXName, c.protocol.PkgName())
+ c.Putln("}")
+}
+
+func (r *Request) ReadReply(c *Context) {
+ c.Putln("// %s represents the data returned from a %s request.",
+ r.ReplyTypeName(), r.SrcName())
+ c.Putln("type %s struct {", r.ReplyTypeName())
+ c.Putln("Sequence uint16 // sequence number of the request for this reply")
+ c.Putln("Length uint32 // number of bytes in this reply")
+ for _, field := range r.Reply.Fields {
+ field.Define(c)
+ }
+ c.Putln("}")
+ c.Putln("")
+
+ c.Putln("// Reply blocks and returns the reply data for a %s request.",
+ r.SrcName())
+ c.Putln("func (cook %s) Reply() (*%s, error) {",
+ r.CookieName(), r.ReplyTypeName())
+ c.Putln("buf, err := cook.Cookie.Reply()")
+ c.Putln("if err != nil {")
+ c.Putln("return nil, err")
+ c.Putln("}")
+ c.Putln("if buf == nil {")
+ c.Putln("return nil, nil")
+ c.Putln("}")
+ c.Putln("return %s(buf), nil", r.ReplyName())
+ c.Putln("}")
+ c.Putln("")
+
+ c.Putln("// %s reads a byte slice into a %s value.",
+ r.ReplyName(), r.ReplyTypeName())
+ c.Putln("func %s(buf []byte) *%s {",
+ r.ReplyName(), r.ReplyTypeName())
+ c.Putln("v := new(%s)", r.ReplyTypeName())
+ c.Putln("b := 1 // skip reply determinant")
+ c.Putln("")
+ for i, field := range r.Reply.Fields {
+ field.Read(c, "v.")
+ c.Putln("")
+ if i == 0 {
+ c.Putln("v.Sequence = xgb.Get16(buf[b:])")
+ c.Putln("b += 2")
+ c.Putln("")
+ c.Putln("v.Length = xgb.Get32(buf[b:]) // 4-byte units")
+ c.Putln("b += 4")
+ c.Putln("")
+ }
+ }
+ c.Putln("return v")
+ c.Putln("}")
+ c.Putln("")
+}
+
+func (r *Request) WriteRequest(c *Context) {
+ sz := r.Size(c)
+ writeSize1 := func() {
+ if sz.exact {
+ c.Putln("xgb.Put16(buf[b:], uint16(size / 4)) " +
+ "// write request size in 4-byte units")
+ } else {
+ c.Putln("blen := b")
+ }
+ c.Putln("b += 2")
+ c.Putln("")
+ }
+ writeSize2 := func() {
+ if sz.exact {
+ c.Putln("return buf")
+ return
+ }
+ c.Putln("b = xgb.Pad(b)")
+ c.Putln("xgb.Put16(buf[blen:], uint16(b / 4)) " +
+ "// write request size in 4-byte units")
+ c.Putln("return buf[:b]")
+ }
+ c.Putln("// Write request to wire for %s", r.SrcName())
+ c.Putln("// %s writes a %s request to a byte slice.",
+ r.ReqName(), r.SrcName())
+ c.Putln("func %s(c *xgb.Conn, %s) []byte {",
+ r.ReqName(), r.ParamNameTypes())
+ c.Putln("size := %s", sz)
+ c.Putln("b := 0")
+ c.Putln("buf := make([]byte, size)")
+ c.Putln("")
+ if c.protocol.isExt() {
+ c.Putln("c.ExtLock.RLock()")
+ c.Putln("buf[b] = c.Extensions[\"%s\"]", c.protocol.ExtXName)
+ c.Putln("c.ExtLock.RUnlock()")
+ c.Putln("b += 1")
+ c.Putln("")
+ }
+ c.Putln("buf[b] = %d // request opcode", r.Opcode)
+ c.Putln("b += 1")
+ c.Putln("")
+ if len(r.Fields) == 0 {
+ if !c.protocol.isExt() {
+ c.Putln("b += 1 // padding")
+ }
+ writeSize1()
+ } else if c.protocol.isExt() {
+ writeSize1()
+ }
+ for i, field := range r.Fields {
+ field.Write(c, "")
+ c.Putln("")
+ if i == 0 && !c.protocol.isExt() {
+ writeSize1()
+ }
+ }
+ writeSize2()
+ c.Putln("}")
+ c.Putln("")
+}
+
+func (r *Request) ParamNames() string {
+ names := make([]string, 0, len(r.Fields))
+ for _, field := range r.Fields {
+ switch f := field.(type) {
+ case *ValueField:
+ names = append(names, f.MaskName)
+ names = append(names, f.ListName)
+ case *PadField:
+ continue
+ case *ExprField:
+ continue
+ default:
+ names = append(names, fmt.Sprintf("%s", field.SrcName()))
+ }
+ }
+ return strings.Join(names, ", ")
+}
+
+func (r *Request) ParamNameTypes() string {
+ nameTypes := make([]string, 0, len(r.Fields))
+ for _, field := range r.Fields {
+ switch f := field.(type) {
+ case *ValueField:
+ nameTypes = append(nameTypes,
+ fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
+ nameTypes = append(nameTypes,
+ fmt.Sprintf("%s []uint32", f.ListName))
+ case *PadField:
+ continue
+ case *ExprField:
+ continue
+ case *RequiredStartAlign:
+ continue
+ default:
+ nameTypes = append(nameTypes,
+ fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))
+ }
+ }
+ return strings.Join(nameTypes, ", ")
+}