diff options
author | Přemysl Janouch <p@janouch.name> | 2018-09-08 16:54:17 +0200 |
---|---|---|
committer | Přemysl Janouch <p@janouch.name> | 2018-09-08 16:54:17 +0200 |
commit | 3173202cc1e08762c6e156a8fffd23269a5ddb2b (patch) | |
tree | 95c4a06f8384d41b15e9c22afac0a387de79dc51 /nexgb/xgbgen/go_request_reply.go | |
parent | 632b3ae494d45755525644fe5d04475c95aae364 (diff) | |
parent | 3906399e7c2a40fbaf355de572cf50a314083f64 (diff) | |
download | haven-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.go | 242 |
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, ", ") +} |