66package wire
77
88import (
9+ "bytes"
910 "crypto/rand"
1011 "encoding/binary"
1112 "fmt"
@@ -131,49 +132,6 @@ func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64,
131132 return rv , nil
132133}
133134
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-
177135// binarySerializer provides a free list of buffers to use for serializing and
178136// deserializing primitive integer values to and from io.Readers and io.Writers.
179137var binarySerializer binaryFreeList = make (chan []byte , binaryFreeListMaxItems )
@@ -412,48 +370,108 @@ func readElements(r io.Reader, elements ...interface{}) error {
412370 return nil
413371}
414372
373+ // shortWrite optimizes short (<= 8 byte) writes to w by special casing
374+ // buffer allocations for specific writer types.
375+ //
376+ // The callback returns a short buffer to 8 bytes in length and a size
377+ // specifying how much of the buffer to write.
378+ //
379+ // For longer writes and writes of byte arrays, dynamic dispatch to w.Write
380+ // should be used instead.
381+ func shortWrite (w io.Writer , cb func () (data [8 ]byte , size int )) error {
382+ data , size := cb ()
383+
384+ switch w := w .(type ) {
385+ // The most common case (called through WriteMessageN) is that the writer is a
386+ // *bytes.Buffer. Optimize for that case by appending binary serializations
387+ // to its existing capacity instead of paying the synchronization cost to
388+ // serialize to temporary buffers pulled from the binary freelist.
389+ case * bytes.Buffer :
390+ w .Write (data [:size ])
391+ return nil
392+
393+ default :
394+ p := binarySerializer .Borrow ()[:size ]
395+ copy (p , data [:size ])
396+ _ , err := w .Write (p )
397+ return err
398+ }
399+ }
400+
401+ // writeUint8 writes the byte value to the writer.
402+ func writeUint8 (w io.Writer , value uint8 ) error {
403+ return shortWrite (w , func () (buf [8 ]byte , size int ) {
404+ buf [0 ] = value
405+ return buf , 1
406+ })
407+ }
408+
409+ // writeUint16 writes the little endian encoding of value to the writer.
410+ func writeUint16 (w io.Writer , value uint16 ) error {
411+ return shortWrite (w , func () (buf [8 ]byte , size int ) {
412+ littleEndian .PutUint16 (buf [:], value )
413+ return buf , 2
414+ })
415+ }
416+
417+ // writeUint32 writes the little endian encoding of value to the writer.
418+ func writeUint32 (w io.Writer , value uint32 ) error {
419+ return shortWrite (w , func () (buf [8 ]byte , size int ) {
420+ littleEndian .PutUint32 (buf [:], value )
421+ return buf , 4
422+ })
423+ }
424+
425+ // writeUint64 writes the little endian encoding of value to the writer.
426+ func writeUint64 (w io.Writer , value uint64 ) error {
427+ return shortWrite (w , func () (buf [8 ]byte , size int ) {
428+ littleEndian .PutUint64 (buf [:], value )
429+ return buf , 8
430+ })
431+ }
432+
415433// writeElement writes the little endian representation of element to w.
416434func writeElement (w io.Writer , element interface {}) error {
417435 // Attempt to write the element based on the concrete type via fast
418436 // type assertions first.
419437 switch e := element .(type ) {
420438 case * uint8 :
421- err := binarySerializer . PutUint8 (w , * e )
439+ err := writeUint8 (w , * e )
422440 if err != nil {
423441 return err
424442 }
425443 return nil
426444
427445 case * uint16 :
428- err := binarySerializer . PutUint16 ( w , littleEndian , * e )
446+ err := writeUint16 ( w , * e )
429447 if err != nil {
430448 return err
431449 }
432450 return nil
433451
434452 case * int32 :
435- err := binarySerializer . PutUint32 ( w , littleEndian , uint32 (* e ))
453+ err := writeUint32 ( w , uint32 (* e ))
436454 if err != nil {
437455 return err
438456 }
439457 return nil
440458
441459 case * uint32 :
442- err := binarySerializer . PutUint32 ( w , littleEndian , * e )
460+ err := writeUint32 ( w , * e )
443461 if err != nil {
444462 return err
445463 }
446464 return nil
447465
448466 case * int64 :
449- err := binarySerializer . PutUint64 ( w , littleEndian , uint64 (* e ))
467+ err := writeUint64 ( w , uint64 (* e ))
450468 if err != nil {
451469 return err
452470 }
453471 return nil
454472
455473 case * uint64 :
456- err := binarySerializer . PutUint64 ( w , littleEndian , * e )
474+ err := writeUint64 ( w , * e )
457475 if err != nil {
458476 return err
459477 }
@@ -462,9 +480,9 @@ func writeElement(w io.Writer, element interface{}) error {
462480 case * bool :
463481 var err error
464482 if * e {
465- err = binarySerializer . PutUint8 (w , 0x01 )
483+ err = writeUint8 (w , 0x01 )
466484 } else {
467- err = binarySerializer . PutUint8 (w , 0x00 )
485+ err = writeUint8 (w , 0x00 )
468486 }
469487 if err != nil {
470488 return err
@@ -558,28 +576,28 @@ func writeElement(w io.Writer, element interface{}) error {
558576 return nil
559577
560578 case * ServiceFlag :
561- err := binarySerializer . PutUint64 ( w , littleEndian , uint64 (* e ))
579+ err := writeUint64 ( w , uint64 (* e ))
562580 if err != nil {
563581 return err
564582 }
565583 return nil
566584
567585 case * InvType :
568- err := binarySerializer . PutUint32 ( w , littleEndian , uint32 (* e ))
586+ err := writeUint32 ( w , uint32 (* e ))
569587 if err != nil {
570588 return err
571589 }
572590 return nil
573591
574592 case * CurrencyNet :
575- err := binarySerializer . PutUint32 ( w , littleEndian , uint32 (* e ))
593+ err := writeUint32 ( w , uint32 (* e ))
576594 if err != nil {
577595 return err
578596 }
579597 return nil
580598
581599 case * RejectCode :
582- err := binarySerializer . PutUint8 (w , uint8 (* e ))
600+ err := writeUint8 (w , uint8 (* e ))
583601 if err != nil {
584602 return err
585603 }
@@ -669,30 +687,34 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
669687// on its value.
670688func WriteVarInt (w io.Writer , pver uint32 , val uint64 ) error {
671689 if val < 0xfd {
672- return binarySerializer .PutUint8 (w , uint8 (val ))
690+ return shortWrite (w , func () (p [8 ]byte , size int ) {
691+ p [0 ] = uint8 (val )
692+ return p , 1
693+ })
673694 }
674695
675696 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 ) )
697+ return shortWrite (w , func () ( p [ 8 ] byte , size int ) {
698+ p [ 0 ] = 0xfd
699+ littleEndian . PutUint16 ( p [ 1 :], uint16 ( val ))
700+ return p , 3
701+ } )
681702 }
682703
683704 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 ) )
705+ return shortWrite (w , func () ( p [ 8 ] byte , size int ) {
706+ p [ 0 ] = 0xfe
707+ littleEndian . PutUint32 ( p [ 1 :], uint32 ( val ))
708+ return p , 5
709+ } )
689710 }
690711
691- err := binarySerializer .PutUint8 (w , 0xff )
712+ // shortWrite is not designed for writes > 8 bytes.
713+ err := writeUint8 (w , 0xff )
692714 if err != nil {
693715 return err
694716 }
695- return binarySerializer . PutUint64 ( w , littleEndian , val )
717+ return writeUint64 ( w , val )
696718}
697719
698720// VarIntSerializeSize returns the number of bytes it would take to serialize
@@ -798,7 +820,13 @@ func WriteVarString(w io.Writer, pver uint32, str string) error {
798820 if err != nil {
799821 return err
800822 }
801- _ , err = w .Write ([]byte (str ))
823+
824+ switch w := w .(type ) {
825+ case * bytes.Buffer :
826+ _ , err = w .WriteString (str )
827+ default :
828+ _ , err = w .Write ([]byte (str ))
829+ }
802830 return err
803831}
804832
0 commit comments