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