github.com/robotn/xgb@v0.0.0-20190912153532-2cb92d044934/xgbgen/go_request_reply.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  func (r *Request) Define(c *Context) {
     9  	c.Putln("// %s is a cookie used only for %s requests.",
    10  		r.CookieName(), r.SrcName())
    11  	c.Putln("type %s struct {", r.CookieName())
    12  	c.Putln("*xgb.Cookie")
    13  	c.Putln("}")
    14  	c.Putln("")
    15  	if r.Reply != nil {
    16  		c.Putln("// %s sends a checked request.", r.SrcName())
    17  		c.Putln("// If an error occurs, it will be returned with the reply "+
    18  			"by calling %s.Reply()", r.CookieName())
    19  		c.Putln("func %s(c *xgb.Conn, %s) %s {",
    20  			r.SrcName(), r.ParamNameTypes(), r.CookieName())
    21  		r.CheckExt(c)
    22  		c.Putln("cookie := c.NewCookie(true, true)")
    23  		c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
    24  		c.Putln("return %s{cookie}", r.CookieName())
    25  		c.Putln("}")
    26  		c.Putln("")
    27  
    28  		c.Putln("// %sUnchecked sends an unchecked request.", r.SrcName())
    29  		c.Putln("// If an error occurs, it can only be retrieved using " +
    30  			"xgb.WaitForEvent or xgb.PollForEvent.")
    31  		c.Putln("func %sUnchecked(c *xgb.Conn, %s) %s {",
    32  			r.SrcName(), r.ParamNameTypes(), r.CookieName())
    33  		r.CheckExt(c)
    34  		c.Putln("cookie := c.NewCookie(false, true)")
    35  		c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
    36  		c.Putln("return %s{cookie}", r.CookieName())
    37  		c.Putln("}")
    38  		c.Putln("")
    39  
    40  		r.ReadReply(c)
    41  	} else {
    42  		c.Putln("// %s sends an unchecked request.", r.SrcName())
    43  		c.Putln("// If an error occurs, it can only be retrieved using " +
    44  			"xgb.WaitForEvent or xgb.PollForEvent.")
    45  		c.Putln("func %s(c *xgb.Conn, %s) %s {",
    46  			r.SrcName(), r.ParamNameTypes(), r.CookieName())
    47  		r.CheckExt(c)
    48  		c.Putln("cookie := c.NewCookie(false, false)")
    49  		c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
    50  		c.Putln("return %s{cookie}", r.CookieName())
    51  		c.Putln("}")
    52  		c.Putln("")
    53  
    54  		c.Putln("// %sChecked sends a checked request.", r.SrcName())
    55  		c.Putln("// If an error occurs, it can be retrieved using "+
    56  			"%s.Check()", r.CookieName())
    57  		c.Putln("func %sChecked(c *xgb.Conn, %s) %s {",
    58  			r.SrcName(), r.ParamNameTypes(), r.CookieName())
    59  		r.CheckExt(c)
    60  		c.Putln("cookie := c.NewCookie(true, false)")
    61  		c.Putln("c.NewRequest(%s(c, %s), cookie)", r.ReqName(), r.ParamNames())
    62  		c.Putln("return %s{cookie}", r.CookieName())
    63  		c.Putln("}")
    64  		c.Putln("")
    65  
    66  		c.Putln("// Check returns an error if one occurred for checked " +
    67  			"requests that are not expecting a reply.")
    68  		c.Putln("// This cannot be called for requests expecting a reply, " +
    69  			"nor for unchecked requests.")
    70  		c.Putln("func (cook %s) Check() error {", r.CookieName())
    71  		c.Putln("return cook.Cookie.Check()")
    72  		c.Putln("}")
    73  		c.Putln("")
    74  	}
    75  	r.WriteRequest(c)
    76  }
    77  
    78  func (r *Request) CheckExt(c *Context) {
    79  	if !c.protocol.isExt() {
    80  		return
    81  	}
    82  	c.Putln("c.ExtLock.RLock()")
    83  	c.Putln("defer c.ExtLock.RUnlock()")
    84  	c.Putln("if _, ok := c.Extensions[\"%s\"]; !ok {", c.protocol.ExtXName)
    85  	c.Putln("panic(\"Cannot issue request '%s' using the uninitialized "+
    86  		"extension '%s'. %s.Init(connObj) must be called first.\")",
    87  		r.SrcName(), c.protocol.ExtXName, c.protocol.PkgName())
    88  	c.Putln("}")
    89  }
    90  
    91  func (r *Request) ReadReply(c *Context) {
    92  	c.Putln("// %s represents the data returned from a %s request.",
    93  		r.ReplyTypeName(), r.SrcName())
    94  	c.Putln("type %s struct {", r.ReplyTypeName())
    95  	c.Putln("Sequence uint16 // sequence number of the request for this reply")
    96  	c.Putln("Length uint32 // number of bytes in this reply")
    97  	for _, field := range r.Reply.Fields {
    98  		field.Define(c)
    99  	}
   100  	c.Putln("}")
   101  	c.Putln("")
   102  
   103  	c.Putln("// Reply blocks and returns the reply data for a %s request.",
   104  		r.SrcName())
   105  	c.Putln("func (cook %s) Reply() (*%s, error) {",
   106  		r.CookieName(), r.ReplyTypeName())
   107  	c.Putln("buf, err := cook.Cookie.Reply()")
   108  	c.Putln("if err != nil {")
   109  	c.Putln("return nil, err")
   110  	c.Putln("}")
   111  	c.Putln("if buf == nil {")
   112  	c.Putln("return nil, nil")
   113  	c.Putln("}")
   114  	c.Putln("return %s(buf), nil", r.ReplyName())
   115  	c.Putln("}")
   116  	c.Putln("")
   117  
   118  	c.Putln("// %s reads a byte slice into a %s value.",
   119  		r.ReplyName(), r.ReplyTypeName())
   120  	c.Putln("func %s(buf []byte) *%s {",
   121  		r.ReplyName(), r.ReplyTypeName())
   122  	c.Putln("v := new(%s)", r.ReplyTypeName())
   123  	c.Putln("b := 1 // skip reply determinant")
   124  	c.Putln("")
   125  	for i, field := range r.Reply.Fields {
   126  		field.Read(c, "v.")
   127  		c.Putln("")
   128  		if i == 0 {
   129  			c.Putln("v.Sequence = xgb.Get16(buf[b:])")
   130  			c.Putln("b += 2")
   131  			c.Putln("")
   132  			c.Putln("v.Length = xgb.Get32(buf[b:]) // 4-byte units")
   133  			c.Putln("b += 4")
   134  			c.Putln("")
   135  		}
   136  	}
   137  	c.Putln("return v")
   138  	c.Putln("}")
   139  	c.Putln("")
   140  }
   141  
   142  func (r *Request) WriteRequest(c *Context) {
   143  	sz := r.Size(c)
   144  	writeSize1 := func() {
   145  		if sz.exact {
   146  			c.Putln("xgb.Put16(buf[b:], uint16(size / 4)) " +
   147  				"// write request size in 4-byte units")
   148  		} else {
   149  			c.Putln("blen := b")
   150  		}
   151  		c.Putln("b += 2")
   152  		c.Putln("")
   153  	}
   154  	writeSize2 := func() {
   155  		if sz.exact {
   156  			c.Putln("return buf")
   157  			return
   158  		}
   159  		c.Putln("b = xgb.Pad(b)")
   160  		c.Putln("xgb.Put16(buf[blen:], uint16(b / 4)) " +
   161  			"// write request size in 4-byte units")
   162  		c.Putln("return buf[:b]")
   163  	}
   164  	c.Putln("// Write request to wire for %s", r.SrcName())
   165  	c.Putln("// %s writes a %s request to a byte slice.",
   166  		r.ReqName(), r.SrcName())
   167  	c.Putln("func %s(c *xgb.Conn, %s) []byte {",
   168  		r.ReqName(), r.ParamNameTypes())
   169  	c.Putln("size := %s", sz)
   170  	c.Putln("b := 0")
   171  	c.Putln("buf := make([]byte, size)")
   172  	c.Putln("")
   173  	if c.protocol.isExt() {
   174  		c.Putln("c.ExtLock.RLock()")
   175  		c.Putln("buf[b] = c.Extensions[\"%s\"]", c.protocol.ExtXName)
   176  		c.Putln("c.ExtLock.RUnlock()")
   177  		c.Putln("b += 1")
   178  		c.Putln("")
   179  	}
   180  	c.Putln("buf[b] = %d // request opcode", r.Opcode)
   181  	c.Putln("b += 1")
   182  	c.Putln("")
   183  	if len(r.Fields) == 0 {
   184  		if !c.protocol.isExt() {
   185  			c.Putln("b += 1 // padding")
   186  		}
   187  		writeSize1()
   188  	} else if c.protocol.isExt() {
   189  		writeSize1()
   190  	}
   191  	for i, field := range r.Fields {
   192  		field.Write(c, "")
   193  		c.Putln("")
   194  		if i == 0 && !c.protocol.isExt() {
   195  			writeSize1()
   196  		}
   197  	}
   198  	writeSize2()
   199  	c.Putln("}")
   200  	c.Putln("")
   201  }
   202  
   203  func (r *Request) ParamNames() string {
   204  	names := make([]string, 0, len(r.Fields))
   205  	for _, field := range r.Fields {
   206  		switch f := field.(type) {
   207  		case *ValueField:
   208  			// mofos...
   209  			if r.SrcName() != "ConfigureWindow" {
   210  				names = append(names, f.MaskName)
   211  			}
   212  			names = append(names, f.ListName)
   213  		case *PadField:
   214  			continue
   215  		case *ExprField:
   216  			continue
   217  		default:
   218  			names = append(names, fmt.Sprintf("%s", field.SrcName()))
   219  		}
   220  	}
   221  	return strings.Join(names, ", ")
   222  }
   223  
   224  func (r *Request) ParamNameTypes() string {
   225  	nameTypes := make([]string, 0, len(r.Fields))
   226  	for _, field := range r.Fields {
   227  		switch f := field.(type) {
   228  		case *ValueField:
   229  			// mofos...
   230  			if r.SrcName() != "ConfigureWindow" {
   231  				nameTypes = append(nameTypes,
   232  					fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
   233  			}
   234  			nameTypes = append(nameTypes,
   235  				fmt.Sprintf("%s []uint32", f.ListName))
   236  		case *PadField:
   237  			continue
   238  		case *ExprField:
   239  			continue
   240  		default:
   241  			nameTypes = append(nameTypes,
   242  				fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))
   243  		}
   244  	}
   245  	return strings.Join(nameTypes, ", ")
   246  }