|
6 | 6 | package wire |
7 | 7 |
|
8 | 8 | import ( |
| 9 | + "bytes" |
9 | 10 | "crypto/rand" |
10 | 11 | "encoding/binary" |
11 | 12 | "fmt" |
@@ -412,60 +413,100 @@ func readElements(r io.Reader, elements ...interface{}) error { |
412 | 413 | return nil |
413 | 414 | } |
414 | 415 |
|
| 416 | +// The most common case (called through WriteMessageN) is that the writer is a |
| 417 | +// *bytes.Buffer. Optimize for that case by appending binary serializations |
| 418 | +// to its existing capacity instead of paying the synchronization cost to |
| 419 | +// serialize to temporary buffers pulled from the binary freelist. This is |
| 420 | +// wrapped by this helper function with callback as only binary encoding short |
| 421 | +// writes (<= 8 bytes) requires the append (in all other cases, Write can be |
| 422 | +// called directly). |
| 423 | +func appendWriter(w io.Writer, do func(p []byte) []byte) (rerr error) { |
| 424 | + var p []byte |
| 425 | + switch w := w.(type) { |
| 426 | + case *bytes.Buffer: |
| 427 | + p = w.Bytes()[w.Len():] |
| 428 | + defer func() { |
| 429 | + w.Write(p) |
| 430 | + }() |
| 431 | + default: |
| 432 | + p = binarySerializer.Borrow()[:0] |
| 433 | + defer func() { |
| 434 | + _, rerr = w.Write(p) |
| 435 | + binarySerializer.Return(p) |
| 436 | + }() |
| 437 | + } |
| 438 | + |
| 439 | + p = do(p) |
| 440 | + return nil |
| 441 | +} |
| 442 | + |
415 | 443 | // writeElement writes the little endian representation of element to w. |
416 | 444 | func writeElement(w io.Writer, element interface{}) error { |
417 | 445 | // Attempt to write the element based on the concrete type via fast |
418 | 446 | // type assertions first. |
419 | 447 | switch e := element.(type) { |
420 | 448 | case *uint8: |
421 | | - err := binarySerializer.PutUint8(w, *e) |
| 449 | + err := appendWriter(w, func(p []byte) []byte { |
| 450 | + return append(p, *e) |
| 451 | + }) |
422 | 452 | if err != nil { |
423 | 453 | return err |
424 | 454 | } |
425 | 455 | return nil |
426 | 456 |
|
427 | 457 | case *uint16: |
428 | | - err := binarySerializer.PutUint16(w, littleEndian, *e) |
| 458 | + err := appendWriter(w, func(p []byte) []byte { |
| 459 | + return littleEndian.AppendUint16(p, *e) |
| 460 | + }) |
429 | 461 | if err != nil { |
430 | 462 | return err |
431 | 463 | } |
432 | 464 | return nil |
433 | 465 |
|
434 | 466 | case *int32: |
435 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 467 | + err := appendWriter(w, func(p []byte) []byte { |
| 468 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 469 | + }) |
436 | 470 | if err != nil { |
437 | 471 | return err |
438 | 472 | } |
439 | 473 | return nil |
440 | 474 |
|
441 | 475 | case *uint32: |
442 | | - err := binarySerializer.PutUint32(w, littleEndian, *e) |
| 476 | + err := appendWriter(w, func(p []byte) []byte { |
| 477 | + return littleEndian.AppendUint32(p, *e) |
| 478 | + }) |
443 | 479 | if err != nil { |
444 | 480 | return err |
445 | 481 | } |
446 | 482 | return nil |
447 | 483 |
|
448 | 484 | case *int64: |
449 | | - err := binarySerializer.PutUint64(w, littleEndian, uint64(*e)) |
| 485 | + err := appendWriter(w, func(p []byte) []byte { |
| 486 | + return littleEndian.AppendUint64(p, uint64(*e)) |
| 487 | + }) |
450 | 488 | if err != nil { |
451 | 489 | return err |
452 | 490 | } |
453 | 491 | return nil |
454 | 492 |
|
455 | 493 | case *uint64: |
456 | | - err := binarySerializer.PutUint64(w, littleEndian, *e) |
| 494 | + err := appendWriter(w, func(p []byte) []byte { |
| 495 | + return littleEndian.AppendUint64(p, *e) |
| 496 | + }) |
457 | 497 | if err != nil { |
458 | 498 | return err |
459 | 499 | } |
460 | 500 | return nil |
461 | 501 |
|
462 | 502 | case *bool: |
463 | | - var err error |
464 | | - if *e { |
465 | | - err = binarySerializer.PutUint8(w, 0x01) |
466 | | - } else { |
467 | | - err = binarySerializer.PutUint8(w, 0x00) |
468 | | - } |
| 503 | + err := appendWriter(w, func(p []byte) []byte { |
| 504 | + var value byte |
| 505 | + if *e { |
| 506 | + value = 1 |
| 507 | + } |
| 508 | + return append(p, value) |
| 509 | + }) |
469 | 510 | if err != nil { |
470 | 511 | return err |
471 | 512 | } |
@@ -558,28 +599,36 @@ func writeElement(w io.Writer, element interface{}) error { |
558 | 599 | return nil |
559 | 600 |
|
560 | 601 | case *ServiceFlag: |
561 | | - err := binarySerializer.PutUint64(w, littleEndian, uint64(*e)) |
| 602 | + err := appendWriter(w, func(p []byte) []byte { |
| 603 | + return littleEndian.AppendUint64(p, uint64(*e)) |
| 604 | + }) |
562 | 605 | if err != nil { |
563 | 606 | return err |
564 | 607 | } |
565 | 608 | return nil |
566 | 609 |
|
567 | 610 | case *InvType: |
568 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 611 | + err := appendWriter(w, func(p []byte) []byte { |
| 612 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 613 | + }) |
569 | 614 | if err != nil { |
570 | 615 | return err |
571 | 616 | } |
572 | 617 | return nil |
573 | 618 |
|
574 | 619 | case *CurrencyNet: |
575 | | - err := binarySerializer.PutUint32(w, littleEndian, uint32(*e)) |
| 620 | + err := appendWriter(w, func(p []byte) []byte { |
| 621 | + return littleEndian.AppendUint32(p, uint32(*e)) |
| 622 | + }) |
576 | 623 | if err != nil { |
577 | 624 | return err |
578 | 625 | } |
579 | 626 | return nil |
580 | 627 |
|
581 | 628 | case *RejectCode: |
582 | | - err := binarySerializer.PutUint8(w, uint8(*e)) |
| 629 | + err := appendWriter(w, func(p []byte) []byte { |
| 630 | + return append(p, uint8(*e)) |
| 631 | + }) |
583 | 632 | if err != nil { |
584 | 633 | return err |
585 | 634 | } |
@@ -669,30 +718,36 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) { |
669 | 718 | // on its value. |
670 | 719 | func WriteVarInt(w io.Writer, pver uint32, val uint64) error { |
671 | 720 | if val < 0xfd { |
672 | | - return binarySerializer.PutUint8(w, uint8(val)) |
| 721 | + return appendWriter(w, func(p []byte) []byte { |
| 722 | + return append(p, uint8(val)) |
| 723 | + }) |
673 | 724 | } |
674 | 725 |
|
675 | 726 | 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)) |
| 727 | + return appendWriter(w, func(p []byte) []byte { |
| 728 | + p = append(p, 0xfd) |
| 729 | + p = littleEndian.AppendUint16(p, uint16(val)) |
| 730 | + return p |
| 731 | + }) |
681 | 732 | } |
682 | 733 |
|
683 | 734 | 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)) |
| 735 | + return appendWriter(w, func(p []byte) []byte { |
| 736 | + p = append(p, 0xfe) |
| 737 | + p = littleEndian.AppendUint32(p, uint32(val)) |
| 738 | + return p |
| 739 | + }) |
689 | 740 | } |
690 | 741 |
|
691 | | - err := binarySerializer.PutUint8(w, 0xff) |
| 742 | + err := appendWriter(w, func(p []byte) []byte { |
| 743 | + return append(p, 0xff) |
| 744 | + }) |
692 | 745 | if err != nil { |
693 | 746 | return err |
694 | 747 | } |
695 | | - return binarySerializer.PutUint64(w, littleEndian, val) |
| 748 | + return appendWriter(w, func(p []byte) []byte { |
| 749 | + return littleEndian.AppendUint64(p, val) |
| 750 | + }) |
696 | 751 | } |
697 | 752 |
|
698 | 753 | // VarIntSerializeSize returns the number of bytes it would take to serialize |
@@ -798,7 +853,13 @@ func WriteVarString(w io.Writer, pver uint32, str string) error { |
798 | 853 | if err != nil { |
799 | 854 | return err |
800 | 855 | } |
801 | | - _, err = w.Write([]byte(str)) |
| 856 | + |
| 857 | + switch w := w.(type) { |
| 858 | + case *bytes.Buffer: |
| 859 | + _, err = w.WriteString(str) |
| 860 | + default: |
| 861 | + _, err = w.Write([]byte(str)) |
| 862 | + } |
802 | 863 | return err |
803 | 864 | } |
804 | 865 |
|
|
0 commit comments