github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/xgbgen/go_union.go (about)

     1  package main
     2  
     3  // Union types
     4  func (u *Union) Define(c *Context) {
     5  	c.Putln("// %s is a represention of the %s union type.",
     6  		u.SrcName(), u.SrcName())
     7  	c.Putln("// Note that to *create* a Union, you should *never* create")
     8  	c.Putln("// this struct directly (unless you know what you're doing).")
     9  	c.Putln("// Instead use one of the following constructors for '%s':",
    10  		u.SrcName())
    11  	for _, field := range u.Fields {
    12  		c.Putln("//     %s%sNew(%s %s) %s", u.SrcName(), field.SrcName(),
    13  			field.SrcName(), field.SrcType(), u.SrcName())
    14  	}
    15  
    16  	c.Putln("type %s struct {", u.SrcName())
    17  	for _, field := range u.Fields {
    18  		field.Define(c)
    19  	}
    20  	c.Putln("}")
    21  	c.Putln("")
    22  
    23  	// Write functions for each field that create instances of this
    24  	// union using the corresponding field.
    25  	u.New(c)
    26  
    27  	// Write function that reads bytes and produces this union.
    28  	u.Read(c)
    29  
    30  	// Write function that reads bytes and produces a list of this union.
    31  	u.ReadList(c)
    32  
    33  	// Write function that writes bytes given this union.
    34  	u.Write(c)
    35  
    36  	// Write function that writes a list of this union.
    37  	u.WriteList(c)
    38  }
    39  
    40  func (u *Union) New(c *Context) {
    41  	for _, field := range u.Fields {
    42  		c.Putln("// %s%sNew constructs a new %s union type with the %s field.",
    43  			u.SrcName(), field.SrcName(), u.SrcName(), field.SrcName())
    44  		c.Putln("func %s%sNew(%s %s) %s {",
    45  			u.SrcName(), field.SrcName(), field.SrcName(),
    46  			field.SrcType(), u.SrcName())
    47  		c.Putln("var b int")
    48  		c.Putln("buf := make([]byte, %s)", u.Size())
    49  		c.Putln("")
    50  		field.Write(c, "")
    51  		c.Putln("")
    52  		c.Putln("// Create the Union type")
    53  		c.Putln("v := %s{}", u.SrcName())
    54  		c.Putln("")
    55  		c.Putln("// Now copy buf into all fields")
    56  		c.Putln("")
    57  		for _, field2 := range u.Fields {
    58  			c.Putln("b = 0 // always read the same bytes")
    59  			field2.Read(c, "v.")
    60  			c.Putln("")
    61  		}
    62  		c.Putln("return v")
    63  		c.Putln("}")
    64  		c.Putln("")
    65  	}
    66  }
    67  
    68  func (u *Union) Read(c *Context) {
    69  	c.Putln("// %sRead reads a byte slice into a %s value.",
    70  		u.SrcName(), u.SrcName())
    71  	c.Putln("func %sRead(buf []byte, v *%s) int {", u.SrcName(), u.SrcName())
    72  	c.Putln("var b int")
    73  	c.Putln("")
    74  	for _, field := range u.Fields {
    75  		c.Putln("b = 0 // re-read the same bytes")
    76  		field.Read(c, "v.")
    77  		c.Putln("")
    78  	}
    79  	c.Putln("return %s", u.Size())
    80  	c.Putln("}")
    81  	c.Putln("")
    82  }
    83  
    84  func (u *Union) ReadList(c *Context) {
    85  	c.Putln("// %sReadList reads a byte slice into a list of %s values.",
    86  		u.SrcName(), u.SrcName())
    87  	c.Putln("func %sReadList(buf []byte, dest []%s) int {",
    88  		u.SrcName(), u.SrcName())
    89  	c.Putln("b := 0")
    90  	c.Putln("for i := 0; i < len(dest); i++ {")
    91  	c.Putln("dest[i] = %s{}", u.SrcName())
    92  	c.Putln("b += %sRead(buf[b:], &dest[i])", u.SrcName())
    93  	c.Putln("}")
    94  	c.Putln("return xgb.Pad(b)")
    95  	c.Putln("}")
    96  	c.Putln("")
    97  }
    98  
    99  // This is a bit tricky since writing from a Union implies that only
   100  // the data inside ONE of the elements is actually written.
   101  // However, we only currently support unions where every field has the
   102  // *same* *fixed* size. Thus, we make sure to always read bytes into
   103  // every field which allows us to simply pick the first field and write it.
   104  func (u *Union) Write(c *Context) {
   105  	c.Putln("// Bytes writes a %s value to a byte slice.", u.SrcName())
   106  	c.Putln("// Each field in a union must contain the same data.")
   107  	c.Putln("// So simply pick the first field and write that to the wire.")
   108  	c.Putln("func (v %s) Bytes() []byte {", u.SrcName())
   109  	c.Putln("buf := make([]byte, %s)", u.Size().Reduce("v."))
   110  	c.Putln("b := 0")
   111  	c.Putln("")
   112  	u.Fields[0].Write(c, "v.")
   113  	c.Putln("return buf")
   114  	c.Putln("}")
   115  	c.Putln("")
   116  }
   117  
   118  func (u *Union) WriteList(c *Context) {
   119  	c.Putln("// %sListBytes writes a list of %s values to a byte slice.",
   120  		u.SrcName(), u.SrcName())
   121  	c.Putln("func %sListBytes(buf []byte, list []%s) int {",
   122  		u.SrcName(), u.SrcName())
   123  	c.Putln("b := 0")
   124  	c.Putln("var unionBytes []byte")
   125  	c.Putln("for _, item := range list {")
   126  	c.Putln("unionBytes = item.Bytes()")
   127  	c.Putln("copy(buf[b:], unionBytes)")
   128  	c.Putln("b += xgb.Pad(len(unionBytes))")
   129  	c.Putln("}")
   130  	c.Putln("return b")
   131  	c.Putln("}")
   132  	c.Putln("")
   133  }
   134  
   135  func (u *Union) WriteListSize(c *Context) {
   136  	c.Putln("// Union list size %s", u.SrcName())
   137  	c.Putln("// %sListSize computes the size (bytes) of a list of %s values.",
   138  		u.SrcName())
   139  	c.Putln("func %sListSize(list []%s) int {", u.SrcName(), u.SrcName())
   140  	c.Putln("size := 0")
   141  	c.Putln("for _, item := range list {")
   142  	c.Putln("size += %s", u.Size().Reduce("item."))
   143  	c.Putln("}")
   144  	c.Putln("return size")
   145  	c.Putln("}")
   146  	c.Putln("")
   147  }