@@ -259,26 +259,7 @@ func (vr *valueReader) readBytes(length int32) ([]byte, error) {
259
259
return nil , fmt .Errorf ("invalid length: %d" , length )
260
260
}
261
261
262
- // If we can peek and discard the bytes, we can avoid an allocation.
263
- if buf , err := vr .src .peek (int (length )); err == nil {
264
- _ , _ = vr .src .discard (int (length )) // Discard the bytes from the source.
265
- return buf , nil
266
- }
267
-
268
- data := make ([]byte , length )
269
- reader , ok := vr .src .(io.Reader )
270
- if ! ok {
271
- return nil , fmt .Errorf ("source does not implement io.Reader: %T" , vr .src )
272
- }
273
-
274
- if _ , err := io .ReadFull (reader , data ); err != nil {
275
- if errors .Is (err , io .ErrUnexpectedEOF ) {
276
- err = io .EOF // Convert io.ErrUnexpectedEOF to io.EOF for consistency.
277
- }
278
- return nil , err
279
- }
280
-
281
- return data , nil
262
+ return fetchBytes (vr .src , int (length ))
282
263
}
283
264
284
265
func (vr * valueReader ) typeError (t Type ) error {
@@ -900,32 +881,25 @@ func (vr *valueReader) readString() (string, error) {
900
881
return "" , fmt .Errorf ("invalid string length: %d" , length )
901
882
}
902
883
903
- // Peek the next length bytes without advancing.
904
- buf , err := vr .src .peek (int (length ))
884
+ raw , err := fetchBytes (vr .src , int (length ))
905
885
if err != nil {
906
886
return "" , err
907
887
}
908
888
909
889
// Check that the last byte is the NUL terminator.
910
- if buf [len (buf )- 1 ] != 0x00 {
911
- return "" , fmt .Errorf ("string does not end with null byte, but with %v" , buf [len (buf )- 1 ])
912
- }
913
-
914
- // Advance past the length bytes.
915
- if _ , err := vr .src .discard (int (length )); err != nil {
916
- return "" , err
890
+ if raw [len (raw )- 1 ] != 0x00 {
891
+ return "" , fmt .Errorf ("string does not end with null byte, but with %v" , raw [len (raw )- 1 ])
917
892
}
918
893
919
894
// Convert and strip the trailing NUL.
920
- return string (buf [:len (buf )- 1 ]), nil
895
+ return string (raw [:len (raw )- 1 ]), nil
921
896
}
922
897
923
898
func (vr * valueReader ) peekLength () (int32 , error ) {
924
899
buf , err := vr .src .peek (4 )
925
900
if err != nil {
926
901
return 0 , err
927
902
}
928
-
929
903
return int32 (binary .LittleEndian .Uint32 (buf )), nil
930
904
}
931
905
@@ -934,57 +908,62 @@ func (vr *valueReader) readLength() (int32, error) {
934
908
}
935
909
936
910
func (vr * valueReader ) readi32 () (int32 , error ) {
937
- buf , err := vr .src . peek ( 4 )
911
+ raw , err := fetchBytes ( vr .src , 4 )
938
912
if err != nil {
939
913
return 0 , err
940
914
}
941
915
942
- // Advance the cursor past the 4 bytes.
943
- if _ , err := vr .src .discard (4 ); err != nil {
944
- return 0 , err
945
- }
946
-
947
- return int32 (binary .LittleEndian .Uint32 (buf )), nil
916
+ return int32 (binary .LittleEndian .Uint32 (raw )), nil
948
917
}
949
918
950
919
func (vr * valueReader ) readu32 () (uint32 , error ) {
951
- buf , err := vr .src . peek ( 4 )
920
+ raw , err := fetchBytes ( vr .src , 4 )
952
921
if err != nil {
953
922
return 0 , err
954
923
}
955
924
956
- // Advance the cursor past the 4 bytes.
957
- if _ , err := vr .src .discard (4 ); err != nil {
958
- return 0 , err
959
- }
960
-
961
- return binary .LittleEndian .Uint32 (buf ), nil
925
+ return binary .LittleEndian .Uint32 (raw ), nil
962
926
}
963
927
964
928
func (vr * valueReader ) readi64 () (int64 , error ) {
965
- buf , err := vr .src . peek ( 8 )
929
+ raw , err := fetchBytes ( vr .src , 8 )
966
930
if err != nil {
967
931
return 0 , err
968
932
}
969
933
970
- // Advance the cursor past the 8 bytes.
971
- if _ , err := vr .src .discard (8 ); err != nil {
972
- return 0 , err
973
- }
974
-
975
- return int64 (binary .LittleEndian .Uint64 (buf )), nil
934
+ return int64 (binary .LittleEndian .Uint64 (raw )), nil
976
935
}
977
936
978
937
func (vr * valueReader ) readu64 () (uint64 , error ) {
979
- buf , err := vr .src . peek ( 8 )
938
+ raw , err := fetchBytes ( vr .src , 8 )
980
939
if err != nil {
981
940
return 0 , err
982
941
}
983
942
984
- // Advance the cursor past the 8 bytes.
985
- if _ , err := vr .src .discard (8 ); err != nil {
986
- return 0 , err
943
+ return binary .LittleEndian .Uint64 (raw ), nil
944
+ }
945
+
946
+ // fetchBytes tries to grab the next n bytes zero-allocation using peek+discard.
947
+ // If peek fails (e.g. bufio buffer full), it falls back to io.ReadFull.
948
+ func fetchBytes (src valueReaderByteSrc , n int ) ([]byte , error ) {
949
+ if src .streamable () {
950
+ data := make ([]byte , n )
951
+ if _ , err := io .ReadFull (src , data ); err != nil {
952
+ if errors .Is (err , io .ErrUnexpectedEOF ) {
953
+ err = io .EOF // Convert io.ErrUnexpectedEOF to io.EOF for consistency.
954
+ }
955
+ return nil , err
956
+ }
957
+
958
+ return data , nil
959
+ }
960
+
961
+ // Zero-allocation path.
962
+ buf , err := src .peek (n )
963
+ if err != nil {
964
+ return nil , err
987
965
}
988
966
989
- return binary .LittleEndian .Uint64 (buf ), nil
967
+ _ , _ = src .discard (n ) // Discard the bytes from the source.
968
+ return buf , nil
990
969
}
0 commit comments