|
6 | 6 | package wire |
7 | 7 |
|
8 | 8 | import ( |
| 9 | + "bytes" |
9 | 10 | "crypto/rand" |
10 | 11 | "encoding/binary" |
11 | 12 | "fmt" |
@@ -131,49 +132,6 @@ func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, |
131 | 132 | return rv, nil |
132 | 133 | } |
133 | 134 |
|
134 | | -// PutUint8 copies the provided uint8 into a buffer from the free list and |
135 | | -// writes the resulting byte to the given writer. |
136 | | -func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error { |
137 | | - buf := l.Borrow()[:1] |
138 | | - buf[0] = val |
139 | | - _, err := w.Write(buf) |
140 | | - l.Return(buf) |
141 | | - return err |
142 | | -} |
143 | | - |
144 | | -// PutUint16 serializes the provided uint16 using the given byte order into a |
145 | | -// buffer from the free list and writes the resulting two bytes to the given |
146 | | -// writer. |
147 | | -func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error { |
148 | | - buf := l.Borrow()[:2] |
149 | | - byteOrder.PutUint16(buf, val) |
150 | | - _, err := w.Write(buf) |
151 | | - l.Return(buf) |
152 | | - return err |
153 | | -} |
154 | | - |
155 | | -// PutUint32 serializes the provided uint32 using the given byte order into a |
156 | | -// buffer from the free list and writes the resulting four bytes to the given |
157 | | -// writer. |
158 | | -func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error { |
159 | | - buf := l.Borrow()[:4] |
160 | | - byteOrder.PutUint32(buf, val) |
161 | | - _, err := w.Write(buf) |
162 | | - l.Return(buf) |
163 | | - return err |
164 | | -} |
165 | | - |
166 | | -// PutUint64 serializes the provided uint64 using the given byte order into a |
167 | | -// buffer from the free list and writes the resulting eight bytes to the given |
168 | | -// writer. |
169 | | -func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error { |
170 | | - buf := l.Borrow()[:8] |
171 | | - byteOrder.PutUint64(buf, val) |
172 | | - _, err := w.Write(buf) |
173 | | - l.Return(buf) |
174 | | - return err |
175 | | -} |
176 | | - |
177 | 135 | // binarySerializer provides a free list of buffers to use for serializing and |
178 | 136 | // deserializing primitive integer values to and from io.Readers and io.Writers. |
179 | 137 | var binarySerializer binaryFreeList = make(chan []byte, binaryFreeListMaxItems) |
@@ -412,60 +370,100 @@ func readElements(r io.Reader, elements ...interface{}) error { |
412 | 370 | return nil |
413 | 371 | } |
414 | 372 |
|
| 373 | +// The most common case (called through WriteMessageN) is that the writer is a |
| 374 | +// *bytes.Buffer. Optimize for that case by appending binary serializations |
| 375 | +// to its existing capacity instead of paying the synchronization cost to |
| 376 | +// serialize to temporary buffers pulled from the binary freelist. This is |
| 377 | +// wrapped by this helper function with callback as only binary encoding short |
| 378 | +// writes (<= 8 bytes) requires the append (in all other cases, Write can be |
| 379 | +// called directly). |
| 380 | +func appendWriter(w io.Writer, do func(p []byte) []byte) (rerr error) { |
| 381 | + var p []byte |
| 382 | + switch w := w.(type) { |
| 383 | + case *bytes.Buffer: |
| 384 | + p = w.Bytes()[w.Len():] |
| 385 | + defer func() { |
| 386 | + w.Write(p) |
| 387 | + }() |
| 388 | + default: |
| 389 | + p = binarySerializer.Borrow()[:0] |
| 390 | + defer func() { |
| 391 | + _, rerr = w.Write(p) |
| 392 | + binarySerializer.Return(p) |
| 393 | + }() |
| 394 | + } |
| 395 | + |
| 396 | + p = do(p) |
| 397 | + return nil |
| 398 | +} |
| 399 | + |
415 | 400 | // writeElement writes the little endian representation of element to w. |
416 | 401 | func writeElement(w io.Writer, element interface{}) error { |
417 | 402 | // Attempt to write the element based on the concrete type via fast |
418 | 403 | // type assertions first. |
419 | 404 | switch e := element.(type) { |
420 | 405 | case *uint8: |
421 | | - err := binarySerializer.PutUint8(w, *e) |
| 406 | + err := appendWriter(w, func(p []byte) []byte { |
| 407 | + return append(p, *e) |
| 408 | + }) |
422 | 409 | if err != nil { |
423 | 410 | return err |
424 | 411 | } |
425 | 412 | return nil |
426 | 413 |
|
427 | 414 | case *uint16: |
428 | | - err := binarySerializer.PutUint16(w, littleEndian, *e) |
| 415 | + err := appendWriter(w, func(p []byte) []byte { |
| 416 | + return littleEndian.AppendUint16(p, *e) |
| 417 | + }) |
429 | 418 | if err != nil { |
430 | 419 | return err |
431 | 420 | } |
432 | 421 | return nil |
433 | 422 |
|
434 | 423 | case *int32: |
435 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 424 | + err := appendWriter(w, func(p []byte) []byte { |
| 425 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 426 | + }) |
436 | 427 | if err != nil { |
437 | 428 | return err |
438 | 429 | } |
439 | 430 | return nil |
440 | 431 |
|
441 | 432 | case *uint32: |
442 | | - err := binarySerializer.PutUint32(w, littleEndian, *e) |
| 433 | + err := appendWriter(w, func(p []byte) []byte { |
| 434 | + return littleEndian.AppendUint32(p, *e) |
| 435 | + }) |
443 | 436 | if err != nil { |
444 | 437 | return err |
445 | 438 | } |
446 | 439 | return nil |
447 | 440 |
|
448 | 441 | case *int64: |
449 | | - err := binarySerializer.PutUint64(w, littleEndian, uint64(*e)) |
| 442 | + err := appendWriter(w, func(p []byte) []byte { |
| 443 | + return littleEndian.AppendUint64(p, uint64(*e)) |
| 444 | + }) |
450 | 445 | if err != nil { |
451 | 446 | return err |
452 | 447 | } |
453 | 448 | return nil |
454 | 449 |
|
455 | 450 | case *uint64: |
456 | | - err := binarySerializer.PutUint64(w, littleEndian, *e) |
| 451 | + err := appendWriter(w, func(p []byte) []byte { |
| 452 | + return littleEndian.AppendUint64(p, *e) |
| 453 | + }) |
457 | 454 | if err != nil { |
458 | 455 | return err |
459 | 456 | } |
460 | 457 | return nil |
461 | 458 |
|
462 | 459 | case *bool: |
463 | | - var err error |
464 | | - if *e { |
465 | | - err = binarySerializer.PutUint8(w, 0x01) |
466 | | - } else { |
467 | | - err = binarySerializer.PutUint8(w, 0x00) |
468 | | - } |
| 460 | + err := appendWriter(w, func(p []byte) []byte { |
| 461 | + var value byte |
| 462 | + if *e { |
| 463 | + value = 1 |
| 464 | + } |
| 465 | + return append(p, value) |
| 466 | + }) |
469 | 467 | if err != nil { |
470 | 468 | return err |
471 | 469 | } |
@@ -558,28 +556,36 @@ func writeElement(w io.Writer, element interface{}) error { |
558 | 556 | return nil |
559 | 557 |
|
560 | 558 | case *ServiceFlag: |
561 | | - err := binarySerializer.PutUint64(w, littleEndian, uint64(*e)) |
| 559 | + err := appendWriter(w, func(p []byte) []byte { |
| 560 | + return littleEndian.AppendUint64(p, uint64(*e)) |
| 561 | + }) |
562 | 562 | if err != nil { |
563 | 563 | return err |
564 | 564 | } |
565 | 565 | return nil |
566 | 566 |
|
567 | 567 | case *InvType: |
568 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 568 | + err := appendWriter(w, func(p []byte) []byte { |
| 569 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 570 | + }) |
569 | 571 | if err != nil { |
570 | 572 | return err |
571 | 573 | } |
572 | 574 | return nil |
573 | 575 |
|
574 | 576 | case *CurrencyNet: |
575 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 577 | + err := appendWriter(w, func(p []byte) []byte { |
| 578 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 579 | + }) |
576 | 580 | if err != nil { |
577 | 581 | return err |
578 | 582 | } |
579 | 583 | return nil |
580 | 584 |
|
581 | 585 | case *RejectCode: |
582 | | - err := binarySerializer.PutUint8(w, uint8(*e)) |
| 586 | + err := appendWriter(w, func(p []byte) []byte { |
| 587 | + return append(p, uint8(*e)) |
| 588 | + }) |
583 | 589 | if err != nil { |
584 | 590 | return err |
585 | 591 | } |
@@ -669,30 +675,36 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) { |
669 | 675 | // on its value. |
670 | 676 | func WriteVarInt(w io.Writer, pver uint32, val uint64) error { |
671 | 677 | if val < 0xfd { |
672 | | - return binarySerializer.PutUint8(w, uint8(val)) |
| 678 | + return appendWriter(w, func(p []byte) []byte { |
| 679 | + return append(p, uint8(val)) |
| 680 | + }) |
673 | 681 | } |
674 | 682 |
|
675 | 683 | if val <= math.MaxUint16 { |
676 | | - err := binarySerializer.PutUint8(w, 0xfd) |
677 | | - if err != nil { |
678 | | - return err |
679 | | - } |
680 | | - return binarySerializer.PutUint16(w, littleEndian, uint16(val)) |
| 684 | + return appendWriter(w, func(p []byte) []byte { |
| 685 | + p = append(p, 0xfd) |
| 686 | + p = littleEndian.AppendUint16(p, uint16(val)) |
| 687 | + return p |
| 688 | + }) |
681 | 689 | } |
682 | 690 |
|
683 | 691 | if val <= math.MaxUint32 { |
684 | | - err := binarySerializer.PutUint8(w, 0xfe) |
685 | | - if err != nil { |
686 | | - return err |
687 | | - } |
688 | | - return binarySerializer.PutUint32(w, littleEndian, uint32(val)) |
| 692 | + return appendWriter(w, func(p []byte) []byte { |
| 693 | + p = append(p, 0xfe) |
| 694 | + p = littleEndian.AppendUint32(p, uint32(val)) |
| 695 | + return p |
| 696 | + }) |
689 | 697 | } |
690 | 698 |
|
691 | | - err := binarySerializer.PutUint8(w, 0xff) |
| 699 | + err := appendWriter(w, func(p []byte) []byte { |
| 700 | + return append(p, 0xff) |
| 701 | + }) |
692 | 702 | if err != nil { |
693 | 703 | return err |
694 | 704 | } |
695 | | - return binarySerializer.PutUint64(w, littleEndian, val) |
| 705 | + return appendWriter(w, func(p []byte) []byte { |
| 706 | + return littleEndian.AppendUint64(p, val) |
| 707 | + }) |
696 | 708 | } |
697 | 709 |
|
698 | 710 | // VarIntSerializeSize returns the number of bytes it would take to serialize |
@@ -798,7 +810,13 @@ func WriteVarString(w io.Writer, pver uint32, str string) error { |
798 | 810 | if err != nil { |
799 | 811 | return err |
800 | 812 | } |
801 | | - _, err = w.Write([]byte(str)) |
| 813 | + |
| 814 | + switch w := w.(type) { |
| 815 | + case *bytes.Buffer: |
| 816 | + _, err = w.WriteString(str) |
| 817 | + default: |
| 818 | + _, err = w.Write([]byte(str)) |
| 819 | + } |
802 | 820 | return err |
803 | 821 | } |
804 | 822 |
|
|
0 commit comments