1package flatbuffers 2 3// Builder is a state machine for creating FlatBuffer objects. 4// Use a Builder to construct object(s) starting from leaf nodes. 5// 6// A Builder constructs byte buffers in a last-first manner for simplicity and 7// performance. 8type Builder struct { 9 // `Bytes` gives raw access to the buffer. Most users will want to use 10 // FinishedBytes() instead. 11 Bytes []byte 12 13 minalign int 14 vtable []UOffsetT 15 objectEnd UOffsetT 16 vtables []UOffsetT 17 head UOffsetT 18 nested bool 19 finished bool 20 21 sharedStrings map[string]UOffsetT 22} 23 24const fileIdentifierLength = 4 25 26// NewBuilder initializes a Builder of size `initial_size`. 27// The internal buffer is grown as needed. 28func NewBuilder(initialSize int) *Builder { 29 if initialSize <= 0 { 30 initialSize = 0 31 } 32 33 b := &Builder{} 34 b.Bytes = make([]byte, initialSize) 35 b.head = UOffsetT(initialSize) 36 b.minalign = 1 37 b.vtables = make([]UOffsetT, 0, 16) // sensible default capacity 38 return b 39} 40 41// Reset truncates the underlying Builder buffer, facilitating alloc-free 42// reuse of a Builder. It also resets bookkeeping data. 43func (b *Builder) Reset() { 44 if b.Bytes != nil { 45 b.Bytes = b.Bytes[:cap(b.Bytes)] 46 } 47 48 if b.vtables != nil { 49 b.vtables = b.vtables[:0] 50 } 51 52 if b.vtable != nil { 53 b.vtable = b.vtable[:0] 54 } 55 56 b.head = UOffsetT(len(b.Bytes)) 57 b.minalign = 1 58 b.nested = false 59 b.finished = false 60} 61 62// FinishedBytes returns a pointer to the written data in the byte buffer. 63// Panics if the builder is not in a finished state (which is caused by calling 64// `Finish()`). 65func (b *Builder) FinishedBytes() []byte { 66 b.assertFinished() 67 return b.Bytes[b.Head():] 68} 69 70// StartObject initializes bookkeeping for writing a new object. 71func (b *Builder) StartObject(numfields int) { 72 b.assertNotNested() 73 b.nested = true 74 75 // use 32-bit offsets so that arithmetic doesn't overflow. 76 if cap(b.vtable) < numfields || b.vtable == nil { 77 b.vtable = make([]UOffsetT, numfields) 78 } else { 79 b.vtable = b.vtable[:numfields] 80 for i := 0; i < len(b.vtable); i++ { 81 b.vtable[i] = 0 82 } 83 } 84 85 b.objectEnd = b.Offset() 86} 87 88// WriteVtable serializes the vtable for the current object, if applicable. 89// 90// Before writing out the vtable, this checks pre-existing vtables for equality 91// to this one. If an equal vtable is found, point the object to the existing 92// vtable and return. 93// 94// Because vtable values are sensitive to alignment of object data, not all 95// logically-equal vtables will be deduplicated. 96// 97// A vtable has the following format: 98// <VOffsetT: size of the vtable in bytes, including this value> 99// <VOffsetT: size of the object in bytes, including the vtable offset> 100// <VOffsetT: offset for a field> * N, where N is the number of fields in 101// the schema for this type. Includes deprecated fields. 102// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide. 103// 104// An object has the following format: 105// <SOffsetT: offset to this object's vtable (may be negative)> 106// <byte: data>+ 107func (b *Builder) WriteVtable() (n UOffsetT) { 108 // Prepend a zero scalar to the object. Later in this function we'll 109 // write an offset here that points to the object's vtable: 110 b.PrependSOffsetT(0) 111 112 objectOffset := b.Offset() 113 existingVtable := UOffsetT(0) 114 115 // Trim vtable of trailing zeroes. 116 i := len(b.vtable) - 1 117 for ; i >= 0 && b.vtable[i] == 0; i-- { 118 } 119 b.vtable = b.vtable[:i+1] 120 121 // Search backwards through existing vtables, because similar vtables 122 // are likely to have been recently appended. See 123 // BenchmarkVtableDeduplication for a case in which this heuristic 124 // saves about 30% of the time used in writing objects with duplicate 125 // tables. 126 for i := len(b.vtables) - 1; i >= 0; i-- { 127 // Find the other vtable, which is associated with `i`: 128 vt2Offset := b.vtables[i] 129 vt2Start := len(b.Bytes) - int(vt2Offset) 130 vt2Len := GetVOffsetT(b.Bytes[vt2Start:]) 131 132 metadata := VtableMetadataFields * SizeVOffsetT 133 vt2End := vt2Start + int(vt2Len) 134 vt2 := b.Bytes[vt2Start+metadata : vt2End] 135 136 // Compare the other vtable to the one under consideration. 137 // If they are equal, store the offset and break: 138 if vtableEqual(b.vtable, objectOffset, vt2) { 139 existingVtable = vt2Offset 140 break 141 } 142 } 143 144 if existingVtable == 0 { 145 // Did not find a vtable, so write this one to the buffer. 146 147 // Write out the current vtable in reverse , because 148 // serialization occurs in last-first order: 149 for i := len(b.vtable) - 1; i >= 0; i-- { 150 var off UOffsetT 151 if b.vtable[i] != 0 { 152 // Forward reference to field; 153 // use 32bit number to assert no overflow: 154 off = objectOffset - b.vtable[i] 155 } 156 157 b.PrependVOffsetT(VOffsetT(off)) 158 } 159 160 // The two metadata fields are written last. 161 162 // First, store the object bytesize: 163 objectSize := objectOffset - b.objectEnd 164 b.PrependVOffsetT(VOffsetT(objectSize)) 165 166 // Second, store the vtable bytesize: 167 vBytes := (len(b.vtable) + VtableMetadataFields) * SizeVOffsetT 168 b.PrependVOffsetT(VOffsetT(vBytes)) 169 170 // Next, write the offset to the new vtable in the 171 // already-allocated SOffsetT at the beginning of this object: 172 objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset) 173 WriteSOffsetT(b.Bytes[objectStart:], 174 SOffsetT(b.Offset())-SOffsetT(objectOffset)) 175 176 // Finally, store this vtable in memory for future 177 // deduplication: 178 b.vtables = append(b.vtables, b.Offset()) 179 } else { 180 // Found a duplicate vtable. 181 182 objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset) 183 b.head = UOffsetT(objectStart) 184 185 // Write the offset to the found vtable in the 186 // already-allocated SOffsetT at the beginning of this object: 187 WriteSOffsetT(b.Bytes[b.head:], 188 SOffsetT(existingVtable)-SOffsetT(objectOffset)) 189 } 190 191 b.vtable = b.vtable[:0] 192 return objectOffset 193} 194 195// EndObject writes data necessary to finish object construction. 196func (b *Builder) EndObject() UOffsetT { 197 b.assertNested() 198 n := b.WriteVtable() 199 b.nested = false 200 return n 201} 202 203// Doubles the size of the byteslice, and copies the old data towards the 204// end of the new byteslice (since we build the buffer backwards). 205func (b *Builder) growByteBuffer() { 206 if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 { 207 panic("cannot grow buffer beyond 2 gigabytes") 208 } 209 newLen := len(b.Bytes) * 2 210 if newLen == 0 { 211 newLen = 1 212 } 213 214 if cap(b.Bytes) >= newLen { 215 b.Bytes = b.Bytes[:newLen] 216 } else { 217 extension := make([]byte, newLen-len(b.Bytes)) 218 b.Bytes = append(b.Bytes, extension...) 219 } 220 221 middle := newLen / 2 222 copy(b.Bytes[middle:], b.Bytes[:middle]) 223} 224 225// Head gives the start of useful data in the underlying byte buffer. 226// Note: unlike other functions, this value is interpreted as from the left. 227func (b *Builder) Head() UOffsetT { 228 return b.head 229} 230 231// Offset relative to the end of the buffer. 232func (b *Builder) Offset() UOffsetT { 233 return UOffsetT(len(b.Bytes)) - b.head 234} 235 236// Pad places zeros at the current offset. 237func (b *Builder) Pad(n int) { 238 for i := 0; i < n; i++ { 239 b.PlaceByte(0) 240 } 241} 242 243// Prep prepares to write an element of `size` after `additional_bytes` 244// have been written, e.g. if you write a string, you need to align such 245// the int length field is aligned to SizeInt32, and the string data follows it 246// directly. 247// If all you need to do is align, `additionalBytes` will be 0. 248func (b *Builder) Prep(size, additionalBytes int) { 249 // Track the biggest thing we've ever aligned to. 250 if size > b.minalign { 251 b.minalign = size 252 } 253 // Find the amount of alignment needed such that `size` is properly 254 // aligned after `additionalBytes`: 255 alignSize := (^(len(b.Bytes) - int(b.Head()) + additionalBytes)) + 1 256 alignSize &= (size - 1) 257 258 // Reallocate the buffer if needed: 259 for int(b.head) <= alignSize+size+additionalBytes { 260 oldBufSize := len(b.Bytes) 261 b.growByteBuffer() 262 b.head += UOffsetT(len(b.Bytes) - oldBufSize) 263 } 264 b.Pad(alignSize) 265} 266 267// PrependSOffsetT prepends an SOffsetT, relative to where it will be written. 268func (b *Builder) PrependSOffsetT(off SOffsetT) { 269 b.Prep(SizeSOffsetT, 0) // Ensure alignment is already done. 270 if !(UOffsetT(off) <= b.Offset()) { 271 panic("unreachable: off <= b.Offset()") 272 } 273 off2 := SOffsetT(b.Offset()) - off + SOffsetT(SizeSOffsetT) 274 b.PlaceSOffsetT(off2) 275} 276 277// PrependUOffsetT prepends an UOffsetT, relative to where it will be written. 278func (b *Builder) PrependUOffsetT(off UOffsetT) { 279 b.Prep(SizeUOffsetT, 0) // Ensure alignment is already done. 280 if !(off <= b.Offset()) { 281 panic("unreachable: off <= b.Offset()") 282 } 283 off2 := b.Offset() - off + UOffsetT(SizeUOffsetT) 284 b.PlaceUOffsetT(off2) 285} 286 287// StartVector initializes bookkeeping for writing a new vector. 288// 289// A vector has the following format: 290// <UOffsetT: number of elements in this vector> 291// <T: data>+, where T is the type of elements of this vector. 292func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT { 293 b.assertNotNested() 294 b.nested = true 295 b.Prep(SizeUint32, elemSize*numElems) 296 b.Prep(alignment, elemSize*numElems) // Just in case alignment > int. 297 return b.Offset() 298} 299 300// EndVector writes data necessary to finish vector construction. 301func (b *Builder) EndVector(vectorNumElems int) UOffsetT { 302 b.assertNested() 303 304 // we already made space for this, so write without PrependUint32 305 b.PlaceUOffsetT(UOffsetT(vectorNumElems)) 306 307 b.nested = false 308 return b.Offset() 309} 310 311// CreateSharedString Checks if the string is already written 312// to the buffer before calling CreateString 313func (b *Builder) CreateSharedString(s string) UOffsetT { 314 if b.sharedStrings == nil { 315 b.sharedStrings = make(map[string]UOffsetT) 316 } 317 if v, ok := b.sharedStrings[s]; ok { 318 return v 319 } 320 off := b.CreateString(s) 321 b.sharedStrings[s] = off 322 return off 323} 324 325// CreateString writes a null-terminated string as a vector. 326func (b *Builder) CreateString(s string) UOffsetT { 327 b.assertNotNested() 328 b.nested = true 329 330 b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte) 331 b.PlaceByte(0) 332 333 l := UOffsetT(len(s)) 334 335 b.head -= l 336 copy(b.Bytes[b.head:b.head+l], s) 337 338 return b.EndVector(len(s)) 339} 340 341// CreateByteString writes a byte slice as a string (null-terminated). 342func (b *Builder) CreateByteString(s []byte) UOffsetT { 343 b.assertNotNested() 344 b.nested = true 345 346 b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte) 347 b.PlaceByte(0) 348 349 l := UOffsetT(len(s)) 350 351 b.head -= l 352 copy(b.Bytes[b.head:b.head+l], s) 353 354 return b.EndVector(len(s)) 355} 356 357// CreateByteVector writes a ubyte vector 358func (b *Builder) CreateByteVector(v []byte) UOffsetT { 359 b.assertNotNested() 360 b.nested = true 361 362 b.Prep(int(SizeUOffsetT), len(v)*SizeByte) 363 364 l := UOffsetT(len(v)) 365 366 b.head -= l 367 copy(b.Bytes[b.head:b.head+l], v) 368 369 return b.EndVector(len(v)) 370} 371 372func (b *Builder) assertNested() { 373 // If you get this assert, you're in an object while trying to write 374 // data that belongs outside of an object. 375 // To fix this, write non-inline data (like vectors) before creating 376 // objects. 377 if !b.nested { 378 panic("Incorrect creation order: must be inside object.") 379 } 380} 381 382func (b *Builder) assertNotNested() { 383 // If you hit this, you're trying to construct a Table/Vector/String 384 // during the construction of its parent table (between the MyTableBuilder 385 // and builder.Finish()). 386 // Move the creation of these sub-objects to above the MyTableBuilder to 387 // not get this assert. 388 // Ignoring this assert may appear to work in simple cases, but the reason 389 // it is here is that storing objects in-line may cause vtable offsets 390 // to not fit anymore. It also leads to vtable duplication. 391 if b.nested { 392 panic("Incorrect creation order: object must not be nested.") 393 } 394} 395 396func (b *Builder) assertFinished() { 397 // If you get this assert, you're attempting to get access a buffer 398 // which hasn't been finished yet. Be sure to call builder.Finish() 399 // with your root table. 400 // If you really need to access an unfinished buffer, use the Bytes 401 // buffer directly. 402 if !b.finished { 403 panic("Incorrect use of FinishedBytes(): must call 'Finish' first.") 404 } 405} 406 407// PrependBoolSlot prepends a bool onto the object at vtable slot `o`. 408// If value `x` equals default `d`, then the slot will be set to zero and no 409// other data will be written. 410func (b *Builder) PrependBoolSlot(o int, x, d bool) { 411 val := byte(0) 412 if x { 413 val = 1 414 } 415 def := byte(0) 416 if d { 417 def = 1 418 } 419 b.PrependByteSlot(o, val, def) 420} 421 422// PrependByteSlot prepends a byte onto the object at vtable slot `o`. 423// If value `x` equals default `d`, then the slot will be set to zero and no 424// other data will be written. 425func (b *Builder) PrependByteSlot(o int, x, d byte) { 426 if x != d { 427 b.PrependByte(x) 428 b.Slot(o) 429 } 430} 431 432// PrependUint8Slot prepends a uint8 onto the object at vtable slot `o`. 433// If value `x` equals default `d`, then the slot will be set to zero and no 434// other data will be written. 435func (b *Builder) PrependUint8Slot(o int, x, d uint8) { 436 if x != d { 437 b.PrependUint8(x) 438 b.Slot(o) 439 } 440} 441 442// PrependUint16Slot prepends a uint16 onto the object at vtable slot `o`. 443// If value `x` equals default `d`, then the slot will be set to zero and no 444// other data will be written. 445func (b *Builder) PrependUint16Slot(o int, x, d uint16) { 446 if x != d { 447 b.PrependUint16(x) 448 b.Slot(o) 449 } 450} 451 452// PrependUint32Slot prepends a uint32 onto the object at vtable slot `o`. 453// If value `x` equals default `d`, then the slot will be set to zero and no 454// other data will be written. 455func (b *Builder) PrependUint32Slot(o int, x, d uint32) { 456 if x != d { 457 b.PrependUint32(x) 458 b.Slot(o) 459 } 460} 461 462// PrependUint64Slot prepends a uint64 onto the object at vtable slot `o`. 463// If value `x` equals default `d`, then the slot will be set to zero and no 464// other data will be written. 465func (b *Builder) PrependUint64Slot(o int, x, d uint64) { 466 if x != d { 467 b.PrependUint64(x) 468 b.Slot(o) 469 } 470} 471 472// PrependInt8Slot prepends a int8 onto the object at vtable slot `o`. 473// If value `x` equals default `d`, then the slot will be set to zero and no 474// other data will be written. 475func (b *Builder) PrependInt8Slot(o int, x, d int8) { 476 if x != d { 477 b.PrependInt8(x) 478 b.Slot(o) 479 } 480} 481 482// PrependInt16Slot prepends a int16 onto the object at vtable slot `o`. 483// If value `x` equals default `d`, then the slot will be set to zero and no 484// other data will be written. 485func (b *Builder) PrependInt16Slot(o int, x, d int16) { 486 if x != d { 487 b.PrependInt16(x) 488 b.Slot(o) 489 } 490} 491 492// PrependInt32Slot prepends a int32 onto the object at vtable slot `o`. 493// If value `x` equals default `d`, then the slot will be set to zero and no 494// other data will be written. 495func (b *Builder) PrependInt32Slot(o int, x, d int32) { 496 if x != d { 497 b.PrependInt32(x) 498 b.Slot(o) 499 } 500} 501 502// PrependInt64Slot prepends a int64 onto the object at vtable slot `o`. 503// If value `x` equals default `d`, then the slot will be set to zero and no 504// other data will be written. 505func (b *Builder) PrependInt64Slot(o int, x, d int64) { 506 if x != d { 507 b.PrependInt64(x) 508 b.Slot(o) 509 } 510} 511 512// PrependFloat32Slot prepends a float32 onto the object at vtable slot `o`. 513// If value `x` equals default `d`, then the slot will be set to zero and no 514// other data will be written. 515func (b *Builder) PrependFloat32Slot(o int, x, d float32) { 516 if x != d { 517 b.PrependFloat32(x) 518 b.Slot(o) 519 } 520} 521 522// PrependFloat64Slot prepends a float64 onto the object at vtable slot `o`. 523// If value `x` equals default `d`, then the slot will be set to zero and no 524// other data will be written. 525func (b *Builder) PrependFloat64Slot(o int, x, d float64) { 526 if x != d { 527 b.PrependFloat64(x) 528 b.Slot(o) 529 } 530} 531 532// PrependUOffsetTSlot prepends an UOffsetT onto the object at vtable slot `o`. 533// If value `x` equals default `d`, then the slot will be set to zero and no 534// other data will be written. 535func (b *Builder) PrependUOffsetTSlot(o int, x, d UOffsetT) { 536 if x != d { 537 b.PrependUOffsetT(x) 538 b.Slot(o) 539 } 540} 541 542// PrependStructSlot prepends a struct onto the object at vtable slot `o`. 543// Structs are stored inline, so nothing additional is being added. 544// In generated code, `d` is always 0. 545func (b *Builder) PrependStructSlot(voffset int, x, d UOffsetT) { 546 if x != d { 547 b.assertNested() 548 if x != b.Offset() { 549 panic("inline data write outside of object") 550 } 551 b.Slot(voffset) 552 } 553} 554 555// Slot sets the vtable key `voffset` to the current location in the buffer. 556func (b *Builder) Slot(slotnum int) { 557 b.vtable[slotnum] = UOffsetT(b.Offset()) 558} 559 560// FinishWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`. 561// as well as applys a file identifier 562func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fid []byte) { 563 if fid == nil || len(fid) != fileIdentifierLength { 564 panic("incorrect file identifier length") 565 } 566 // In order to add a file identifier to the flatbuffer message, we need 567 // to prepare an alignment and file identifier length 568 b.Prep(b.minalign, SizeInt32+fileIdentifierLength) 569 for i := fileIdentifierLength - 1; i >= 0; i-- { 570 // place the file identifier 571 b.PlaceByte(fid[i]) 572 } 573 // finish 574 b.Finish(rootTable) 575} 576 577// Finish finalizes a buffer, pointing to the given `rootTable`. 578func (b *Builder) Finish(rootTable UOffsetT) { 579 b.assertNotNested() 580 b.Prep(b.minalign, SizeUOffsetT) 581 b.PrependUOffsetT(rootTable) 582 b.finished = true 583} 584 585// vtableEqual compares an unwritten vtable to a written vtable. 586func vtableEqual(a []UOffsetT, objectStart UOffsetT, b []byte) bool { 587 if len(a)*SizeVOffsetT != len(b) { 588 return false 589 } 590 591 for i := 0; i < len(a); i++ { 592 x := GetVOffsetT(b[i*SizeVOffsetT : (i+1)*SizeVOffsetT]) 593 594 // Skip vtable entries that indicate a default value. 595 if x == 0 && a[i] == 0 { 596 continue 597 } 598 599 y := SOffsetT(objectStart) - SOffsetT(a[i]) 600 if SOffsetT(x) != y { 601 return false 602 } 603 } 604 return true 605} 606 607// PrependBool prepends a bool to the Builder buffer. 608// Aligns and checks for space. 609func (b *Builder) PrependBool(x bool) { 610 b.Prep(SizeBool, 0) 611 b.PlaceBool(x) 612} 613 614// PrependUint8 prepends a uint8 to the Builder buffer. 615// Aligns and checks for space. 616func (b *Builder) PrependUint8(x uint8) { 617 b.Prep(SizeUint8, 0) 618 b.PlaceUint8(x) 619} 620 621// PrependUint16 prepends a uint16 to the Builder buffer. 622// Aligns and checks for space. 623func (b *Builder) PrependUint16(x uint16) { 624 b.Prep(SizeUint16, 0) 625 b.PlaceUint16(x) 626} 627 628// PrependUint32 prepends a uint32 to the Builder buffer. 629// Aligns and checks for space. 630func (b *Builder) PrependUint32(x uint32) { 631 b.Prep(SizeUint32, 0) 632 b.PlaceUint32(x) 633} 634 635// PrependUint64 prepends a uint64 to the Builder buffer. 636// Aligns and checks for space. 637func (b *Builder) PrependUint64(x uint64) { 638 b.Prep(SizeUint64, 0) 639 b.PlaceUint64(x) 640} 641 642// PrependInt8 prepends a int8 to the Builder buffer. 643// Aligns and checks for space. 644func (b *Builder) PrependInt8(x int8) { 645 b.Prep(SizeInt8, 0) 646 b.PlaceInt8(x) 647} 648 649// PrependInt16 prepends a int16 to the Builder buffer. 650// Aligns and checks for space. 651func (b *Builder) PrependInt16(x int16) { 652 b.Prep(SizeInt16, 0) 653 b.PlaceInt16(x) 654} 655 656// PrependInt32 prepends a int32 to the Builder buffer. 657// Aligns and checks for space. 658func (b *Builder) PrependInt32(x int32) { 659 b.Prep(SizeInt32, 0) 660 b.PlaceInt32(x) 661} 662 663// PrependInt64 prepends a int64 to the Builder buffer. 664// Aligns and checks for space. 665func (b *Builder) PrependInt64(x int64) { 666 b.Prep(SizeInt64, 0) 667 b.PlaceInt64(x) 668} 669 670// PrependFloat32 prepends a float32 to the Builder buffer. 671// Aligns and checks for space. 672func (b *Builder) PrependFloat32(x float32) { 673 b.Prep(SizeFloat32, 0) 674 b.PlaceFloat32(x) 675} 676 677// PrependFloat64 prepends a float64 to the Builder buffer. 678// Aligns and checks for space. 679func (b *Builder) PrependFloat64(x float64) { 680 b.Prep(SizeFloat64, 0) 681 b.PlaceFloat64(x) 682} 683 684// PrependByte prepends a byte to the Builder buffer. 685// Aligns and checks for space. 686func (b *Builder) PrependByte(x byte) { 687 b.Prep(SizeByte, 0) 688 b.PlaceByte(x) 689} 690 691// PrependVOffsetT prepends a VOffsetT to the Builder buffer. 692// Aligns and checks for space. 693func (b *Builder) PrependVOffsetT(x VOffsetT) { 694 b.Prep(SizeVOffsetT, 0) 695 b.PlaceVOffsetT(x) 696} 697 698// PlaceBool prepends a bool to the Builder, without checking for space. 699func (b *Builder) PlaceBool(x bool) { 700 b.head -= UOffsetT(SizeBool) 701 WriteBool(b.Bytes[b.head:], x) 702} 703 704// PlaceUint8 prepends a uint8 to the Builder, without checking for space. 705func (b *Builder) PlaceUint8(x uint8) { 706 b.head -= UOffsetT(SizeUint8) 707 WriteUint8(b.Bytes[b.head:], x) 708} 709 710// PlaceUint16 prepends a uint16 to the Builder, without checking for space. 711func (b *Builder) PlaceUint16(x uint16) { 712 b.head -= UOffsetT(SizeUint16) 713 WriteUint16(b.Bytes[b.head:], x) 714} 715 716// PlaceUint32 prepends a uint32 to the Builder, without checking for space. 717func (b *Builder) PlaceUint32(x uint32) { 718 b.head -= UOffsetT(SizeUint32) 719 WriteUint32(b.Bytes[b.head:], x) 720} 721 722// PlaceUint64 prepends a uint64 to the Builder, without checking for space. 723func (b *Builder) PlaceUint64(x uint64) { 724 b.head -= UOffsetT(SizeUint64) 725 WriteUint64(b.Bytes[b.head:], x) 726} 727 728// PlaceInt8 prepends a int8 to the Builder, without checking for space. 729func (b *Builder) PlaceInt8(x int8) { 730 b.head -= UOffsetT(SizeInt8) 731 WriteInt8(b.Bytes[b.head:], x) 732} 733 734// PlaceInt16 prepends a int16 to the Builder, without checking for space. 735func (b *Builder) PlaceInt16(x int16) { 736 b.head -= UOffsetT(SizeInt16) 737 WriteInt16(b.Bytes[b.head:], x) 738} 739 740// PlaceInt32 prepends a int32 to the Builder, without checking for space. 741func (b *Builder) PlaceInt32(x int32) { 742 b.head -= UOffsetT(SizeInt32) 743 WriteInt32(b.Bytes[b.head:], x) 744} 745 746// PlaceInt64 prepends a int64 to the Builder, without checking for space. 747func (b *Builder) PlaceInt64(x int64) { 748 b.head -= UOffsetT(SizeInt64) 749 WriteInt64(b.Bytes[b.head:], x) 750} 751 752// PlaceFloat32 prepends a float32 to the Builder, without checking for space. 753func (b *Builder) PlaceFloat32(x float32) { 754 b.head -= UOffsetT(SizeFloat32) 755 WriteFloat32(b.Bytes[b.head:], x) 756} 757 758// PlaceFloat64 prepends a float64 to the Builder, without checking for space. 759func (b *Builder) PlaceFloat64(x float64) { 760 b.head -= UOffsetT(SizeFloat64) 761 WriteFloat64(b.Bytes[b.head:], x) 762} 763 764// PlaceByte prepends a byte to the Builder, without checking for space. 765func (b *Builder) PlaceByte(x byte) { 766 b.head -= UOffsetT(SizeByte) 767 WriteByte(b.Bytes[b.head:], x) 768} 769 770// PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for space. 771func (b *Builder) PlaceVOffsetT(x VOffsetT) { 772 b.head -= UOffsetT(SizeVOffsetT) 773 WriteVOffsetT(b.Bytes[b.head:], x) 774} 775 776// PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for space. 777func (b *Builder) PlaceSOffsetT(x SOffsetT) { 778 b.head -= UOffsetT(SizeSOffsetT) 779 WriteSOffsetT(b.Bytes[b.head:], x) 780} 781 782// PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for space. 783func (b *Builder) PlaceUOffsetT(x UOffsetT) { 784 b.head -= UOffsetT(SizeUOffsetT) 785 WriteUOffsetT(b.Bytes[b.head:], x) 786} 787