aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/go_request_reply.go
diff options
context:
space:
mode:
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, ", ")
+}