@@ -110,7 +110,9 @@ impl Expect<u8> for u8 {
110110 }
111111}
112112
113- fn decode_impl < ' a > (
113+ /// When `BORROW` is true, Binary/Text values borrow from the input slice (zero-copy).
114+ /// When `BORROW` is false, Binary/Text values are owned copies (for `Decode for Vec<u8>`).
115+ fn decode_impl < ' a , const BORROW : bool > (
114116 vector : & ' a [ u8 ] ,
115117 start : usize ,
116118) -> Result < ( BencodexValue < ' a > , usize ) , DecodeError > {
@@ -119,11 +121,11 @@ fn decode_impl<'a>(
119121 }
120122
121123 match vector[ start] {
122- b'd' => decode_dict_impl ( vector, start) ,
123- b'l' => decode_list_impl ( vector, start) ,
124- b'u' => decode_unicode_string_impl ( vector, start) ,
124+ b'd' => decode_dict_impl :: < BORROW > ( vector, start) ,
125+ b'l' => decode_list_impl :: < BORROW > ( vector, start) ,
126+ b'u' => decode_unicode_string_impl :: < BORROW > ( vector, start) ,
125127 b'i' => decode_number_impl ( vector, start) ,
126- b'0' ..=b'9' => decode_byte_string_impl ( vector, start) ,
128+ b'0' ..=b'9' => decode_byte_string_impl :: < BORROW > ( vector, start) ,
127129 b't' => Ok ( ( BencodexValue :: Boolean ( true ) , 1 ) ) ,
128130 b'f' => Ok ( ( BencodexValue :: Boolean ( false ) , 1 ) ) ,
129131 b'n' => Ok ( ( BencodexValue :: Null , 1 ) ) ,
@@ -134,8 +136,26 @@ fn decode_impl<'a>(
134136 }
135137}
136138
139+ #[ inline( always) ]
140+ fn cow_binary < ' a , const BORROW : bool > ( data : & ' a [ u8 ] ) -> Cow < ' a , [ u8 ] > {
141+ if BORROW {
142+ Cow :: Borrowed ( data)
143+ } else {
144+ Cow :: Owned ( data. to_vec ( ) )
145+ }
146+ }
147+
148+ #[ inline( always) ]
149+ fn cow_text < ' a , const BORROW : bool > ( text : & ' a str ) -> Cow < ' a , str > {
150+ if BORROW {
151+ Cow :: Borrowed ( text)
152+ } else {
153+ Cow :: Owned ( text. to_string ( ) )
154+ }
155+ }
156+
137157// start must be on 'd'
138- fn decode_dict_impl < ' a > (
158+ fn decode_dict_impl < ' a , const BORROW : bool > (
139159 vector : & ' a [ u8 ] ,
140160 start : usize ,
141161) -> Result < ( BencodexValue < ' a > , usize ) , DecodeError > {
@@ -148,15 +168,15 @@ fn decode_dict_impl<'a>(
148168 let mut index = start + tsize;
149169 let mut map = BTreeMap :: new ( ) ;
150170 while vector. get ( index) . should_not_be_none ( ) ? != b'e' {
151- let ( value, size) = decode_impl ( vector, index) ?;
171+ let ( value, size) = decode_impl :: < BORROW > ( vector, index) ?;
152172 let key = match value {
153173 BencodexValue :: Text ( s) => BencodexKey :: Text ( s) ,
154174 BencodexValue :: Binary ( b) => BencodexKey :: Binary ( b) ,
155175 _ => return Err ( DecodeError :: InvalidBencodexValueError ) ,
156176 } ;
157177 tsize += size;
158178 index = start + tsize;
159- let ( value, size) = decode_impl ( vector, index) ?;
179+ let ( value, size) = decode_impl :: < BORROW > ( vector, index) ?;
160180
161181 match map. insert ( key, value) {
162182 None => ( ) ,
@@ -176,7 +196,7 @@ fn decode_dict_impl<'a>(
176196}
177197
178198// start must be on 'l'
179- fn decode_list_impl < ' a > (
199+ fn decode_list_impl < ' a , const BORROW : bool > (
180200 vector : & ' a [ u8 ] ,
181201 start : usize ,
182202) -> Result < ( BencodexValue < ' a > , usize ) , DecodeError > {
@@ -189,7 +209,7 @@ fn decode_list_impl<'a>(
189209 let mut list = Vec :: new ( ) ;
190210 let mut index = start + tsize;
191211 while vector. get ( index) . should_not_be_none ( ) ? != b'e' {
192- let ( value, size) = decode_impl ( vector, index) ?;
212+ let ( value, size) = decode_impl :: < BORROW > ( vector, index) ?;
193213 list. push ( value) ;
194214 tsize += size;
195215 index = start + tsize
@@ -205,7 +225,7 @@ fn decode_list_impl<'a>(
205225 Ok ( ( BencodexValue :: List ( list) , tsize) )
206226}
207227
208- fn decode_byte_string_impl < ' a > (
228+ fn decode_byte_string_impl < ' a , const BORROW : bool > (
209229 vector : & ' a [ u8 ] ,
210230 start : usize ,
211231) -> Result < ( BencodexValue < ' a > , usize ) , DecodeError > {
@@ -226,15 +246,15 @@ fn decode_byte_string_impl<'a>(
226246 return Err ( DecodeError :: InvalidBencodexValueError ) ;
227247 }
228248 Ok ( (
229- BencodexValue :: Binary ( Cow :: Borrowed (
249+ BencodexValue :: Binary ( cow_binary :: < BORROW > (
230250 & vector[ start + tsize..start + tsize + length] ,
231251 ) ) ,
232252 tsize + length,
233253 ) )
234254}
235255
236256// start must be on 'u'
237- fn decode_unicode_string_impl < ' a > (
257+ fn decode_unicode_string_impl < ' a , const BORROW : bool > (
238258 vector : & ' a [ u8 ] ,
239259 start : usize ,
240260) -> Result < ( BencodexValue < ' a > , usize ) , DecodeError > {
@@ -273,7 +293,7 @@ fn decode_unicode_string_impl<'a>(
273293 Err ( _) => return Err ( DecodeError :: InvalidBencodexValueError ) ,
274294 } ;
275295 tsize += length;
276- Ok ( ( BencodexValue :: Text ( Cow :: Borrowed ( text) ) , tsize) )
296+ Ok ( ( BencodexValue :: Text ( cow_text :: < BORROW > ( text) ) , tsize) )
277297}
278298
279299// start must be on 'i'
@@ -386,7 +406,7 @@ fn read_number(s: &[u8]) -> Option<(BigInt, usize)> {
386406/// assert_eq!(value, BencodexValue::Text("hello".into()));
387407/// ```
388408pub fn decode_borrowed ( input : & [ u8 ] ) -> Result < BencodexValue < ' _ > , DecodeError > {
389- Ok ( decode_impl ( input, 0 ) ?. 0 )
409+ Ok ( decode_impl :: < true > ( input, 0 ) ?. 0 )
390410}
391411
392412impl Decode for Vec < u8 > {
@@ -400,7 +420,11 @@ impl Decode for Vec<u8> {
400420 /// assert_eq!(dictionary, BencodexValue::Dictionary(BTreeMap::new()));
401421 /// ```
402422 fn decode ( self ) -> Result < BencodexValue < ' static > , DecodeError > {
403- Ok ( decode_impl ( & self , 0 ) ?. 0 . into_owned ( ) )
423+ let value = decode_impl :: < false > ( & self , 0 ) ?. 0 ;
424+ // SAFETY: With BORROW=false, all Cow values in the tree are Cow::Owned,
425+ // so no references with the local lifetime exist. The lifetime parameter
426+ // is purely phantom, making the transmute to 'static sound.
427+ Ok ( unsafe { core:: mem:: transmute :: < BencodexValue < ' _ > , BencodexValue < ' static > > ( value) } )
404428 }
405429
406430 #[ cfg( feature = "simd" ) ]
@@ -417,9 +441,9 @@ mod tests {
417441 #[ test]
418442 fn should_return_error_with_overflowed_start ( ) {
419443 let expected_error = DecodeError :: InvalidBencodexValueError ;
420- assert_eq ! ( expected_error, decode_impl( & [ ] , 1 ) . unwrap_err( ) ) ;
421- assert_eq ! ( expected_error, decode_impl( b"12" , 2 ) . unwrap_err( ) ) ;
422- assert_eq ! ( expected_error, decode_impl( b"12" , 20 ) . unwrap_err( ) ) ;
444+ assert_eq ! ( expected_error, decode_impl:: < true > ( & [ ] , 1 ) . unwrap_err( ) ) ;
445+ assert_eq ! ( expected_error, decode_impl:: < true > ( b"12" , 2 ) . unwrap_err( ) ) ;
446+ assert_eq ! ( expected_error, decode_impl:: < true > ( b"12" , 20 ) . unwrap_err( ) ) ;
423447 }
424448
425449 #[ test]
@@ -429,14 +453,14 @@ mod tests {
429453 token: b'x' ,
430454 point: 0 ,
431455 } ,
432- decode_impl( b"x" , 0 ) . unwrap_err( )
456+ decode_impl:: < true > ( b"x" , 0 ) . unwrap_err( )
433457 ) ;
434458 assert_eq ! (
435459 DecodeError :: UnexpectedTokenError {
436460 token: b'k' ,
437461 point: 4 ,
438462 } ,
439- decode_impl( b"xyzok" , 4 ) . unwrap_err( )
463+ decode_impl:: < true > ( b"xyzok" , 4 ) . unwrap_err( )
440464 ) ;
441465 }
442466 }
@@ -447,24 +471,48 @@ mod tests {
447471 #[ test]
448472 fn should_return_error_with_insufficient_length_source ( ) {
449473 let expected_error = DecodeError :: InvalidBencodexValueError ;
450- assert_eq ! ( expected_error, decode_dict_impl( b"d" , 0 ) . unwrap_err( ) ) ;
451- assert_eq ! ( expected_error, decode_dict_impl( b"d" , 2 ) . unwrap_err( ) ) ;
452- assert_eq ! ( expected_error, decode_dict_impl( & [ ] , 0 ) . unwrap_err( ) ) ;
474+ assert_eq ! (
475+ expected_error,
476+ decode_dict_impl:: <true >( b"d" , 0 ) . unwrap_err( )
477+ ) ;
478+ assert_eq ! (
479+ expected_error,
480+ decode_dict_impl:: <true >( b"d" , 2 ) . unwrap_err( )
481+ ) ;
482+ assert_eq ! (
483+ expected_error,
484+ decode_dict_impl:: <true >( & [ ] , 0 ) . unwrap_err( )
485+ ) ;
453486 }
454487
455488 #[ test]
456489 fn should_return_error_with_source_having_incorrect_key ( ) {
457490 let expected_error = DecodeError :: InvalidBencodexValueError ;
458491 // { 0: null }
459- assert_eq ! ( expected_error, decode_dict_impl( b"di0ene" , 0 ) . unwrap_err( ) ) ;
492+ assert_eq ! (
493+ expected_error,
494+ decode_dict_impl:: <true >( b"di0ene" , 0 ) . unwrap_err( )
495+ ) ;
460496 // { null: null }
461- assert_eq ! ( expected_error, decode_dict_impl( b"dnne" , 0 ) . unwrap_err( ) ) ;
497+ assert_eq ! (
498+ expected_error,
499+ decode_dict_impl:: <true >( b"dnne" , 0 ) . unwrap_err( )
500+ ) ;
462501 // { list: null }
463- assert_eq ! ( expected_error, decode_dict_impl( b"dlene" , 0 ) . unwrap_err( ) ) ;
502+ assert_eq ! (
503+ expected_error,
504+ decode_dict_impl:: <true >( b"dlene" , 0 ) . unwrap_err( )
505+ ) ;
464506 // { dictionary: null }
465- assert_eq ! ( expected_error, decode_dict_impl( b"ddene" , 0 ) . unwrap_err( ) ) ;
507+ assert_eq ! (
508+ expected_error,
509+ decode_dict_impl:: <true >( b"ddene" , 0 ) . unwrap_err( )
510+ ) ;
466511 // { boolean: null }
467- assert_eq ! ( expected_error, decode_dict_impl( b"dtene" , 0 ) . unwrap_err( ) ) ;
512+ assert_eq ! (
513+ expected_error,
514+ decode_dict_impl:: <true >( b"dtene" , 0 ) . unwrap_err( )
515+ ) ;
468516 }
469517
470518 #[ test]
@@ -474,14 +522,14 @@ mod tests {
474522 token: b'k' ,
475523 point: 1 ,
476524 } ,
477- decode_dict_impl( b"dkne" , 0 ) . unwrap_err( )
525+ decode_dict_impl:: < true > ( b"dkne" , 0 ) . unwrap_err( )
478526 ) ;
479527 assert_eq ! (
480528 DecodeError :: UnexpectedTokenError {
481529 token: b'k' ,
482530 point: 4 ,
483531 } ,
484- decode_dict_impl( b"d1:ake" , 0 ) . unwrap_err( )
532+ decode_dict_impl:: < true > ( b"d1:ake" , 0 ) . unwrap_err( )
485533 ) ;
486534 }
487535 }
@@ -492,9 +540,18 @@ mod tests {
492540 #[ test]
493541 fn should_return_error_with_insufficient_length_source ( ) {
494542 let expected_error = DecodeError :: InvalidBencodexValueError ;
495- assert_eq ! ( expected_error, decode_list_impl( b"l" , 0 ) . unwrap_err( ) ) ;
496- assert_eq ! ( expected_error, decode_list_impl( b"l" , 2 ) . unwrap_err( ) ) ;
497- assert_eq ! ( expected_error, decode_list_impl( & [ ] , 0 ) . unwrap_err( ) ) ;
543+ assert_eq ! (
544+ expected_error,
545+ decode_list_impl:: <true >( b"l" , 0 ) . unwrap_err( )
546+ ) ;
547+ assert_eq ! (
548+ expected_error,
549+ decode_list_impl:: <true >( b"l" , 2 ) . unwrap_err( )
550+ ) ;
551+ assert_eq ! (
552+ expected_error,
553+ decode_list_impl:: <true >( & [ ] , 0 ) . unwrap_err( )
554+ ) ;
498555 }
499556
500557 #[ test]
@@ -504,7 +561,7 @@ mod tests {
504561 token: b'k' ,
505562 point: 1 ,
506563 } ,
507- decode_list_impl( b"lke" , 0 ) . unwrap_err( )
564+ decode_list_impl:: < true > ( b"lke" , 0 ) . unwrap_err( )
508565 ) ;
509566 }
510567 }
@@ -517,17 +574,20 @@ mod tests {
517574 let expected_error = DecodeError :: InvalidBencodexValueError ;
518575 assert_eq ! (
519576 expected_error,
520- decode_byte_string_impl( b"1" , 0 ) . unwrap_err( )
577+ decode_byte_string_impl:: <true >( b"1" , 0 ) . unwrap_err( )
578+ ) ;
579+ assert_eq ! (
580+ expected_error,
581+ decode_byte_string_impl:: <true >( b"1:" , 0 ) . unwrap_err( )
521582 ) ;
522583 assert_eq ! (
523584 expected_error,
524- decode_byte_string_impl( b"1: " , 0 ) . unwrap_err( )
585+ decode_byte_string_impl:: < true > ( b"2:a " , 0 ) . unwrap_err( )
525586 ) ;
526587 assert_eq ! (
527588 expected_error,
528- decode_byte_string_impl( b"2:a" , 0 ) . unwrap_err( )
589+ decode_byte_string_impl:: < true > ( & [ ] , 0 ) . unwrap_err( )
529590 ) ;
530- assert_eq ! ( expected_error, decode_byte_string_impl( & [ ] , 0 ) . unwrap_err( ) ) ;
531591 }
532592
533593 #[ test]
@@ -537,7 +597,7 @@ mod tests {
537597 token: b'k' ,
538598 point: 1 ,
539599 } ,
540- decode_byte_string_impl( b"1ka" , 0 ) . unwrap_err( )
600+ decode_byte_string_impl:: < true > ( b"1ka" , 0 ) . unwrap_err( )
541601 ) ;
542602 }
543603 }
@@ -550,26 +610,26 @@ mod tests {
550610 let expected_error = DecodeError :: InvalidBencodexValueError ;
551611 assert_eq ! (
552612 expected_error,
553- decode_unicode_string_impl( b"u" , 0 ) . unwrap_err( )
613+ decode_unicode_string_impl:: < true > ( b"u" , 0 ) . unwrap_err( )
554614 ) ;
555615 assert_eq ! (
556616 expected_error,
557- decode_unicode_string_impl( b"u1" , 0 ) . unwrap_err( )
617+ decode_unicode_string_impl:: < true > ( b"u1" , 0 ) . unwrap_err( )
558618 ) ;
559619 assert_eq ! (
560620 expected_error,
561- decode_unicode_string_impl( b"u2:a" , 0 ) . unwrap_err( )
621+ decode_unicode_string_impl:: < true > ( b"u2:a" , 0 ) . unwrap_err( )
562622 ) ;
563623 assert_eq ! (
564624 DecodeError :: UnexpectedTokenError {
565625 token: b'k' ,
566626 point: 1 ,
567627 } ,
568- decode_unicode_string_impl( b"uk" , 0 ) . unwrap_err( )
628+ decode_unicode_string_impl:: < true > ( b"uk" , 0 ) . unwrap_err( )
569629 ) ;
570630 assert_eq ! (
571631 expected_error,
572- decode_unicode_string_impl( & [ ] , 0 ) . unwrap_err( )
632+ decode_unicode_string_impl:: < true > ( & [ ] , 0 ) . unwrap_err( )
573633 ) ;
574634 }
575635
@@ -580,7 +640,7 @@ mod tests {
580640 token: b'k' ,
581641 point: 2
582642 } ,
583- decode_unicode_string_impl( b"u1ka" , 0 ) . unwrap_err( )
643+ decode_unicode_string_impl:: < true > ( b"u1ka" , 0 ) . unwrap_err( )
584644 ) ;
585645 }
586646
@@ -591,15 +651,15 @@ mod tests {
591651 token: b'-' ,
592652 point: 1 ,
593653 } ,
594- decode_unicode_string_impl( b"u-1:a" , 0 ) . unwrap_err( )
654+ decode_unicode_string_impl:: < true > ( b"u-1:a" , 0 ) . unwrap_err( )
595655 ) ;
596656 }
597657
598658 #[ test]
599659 fn should_return_error_with_invalid_source_having_invalid_unicode_string ( ) {
600660 assert_eq ! (
601661 DecodeError :: InvalidBencodexValueError ,
602- decode_unicode_string_impl( & [ b'u' , b'1' , b':' , 0x90 ] , 0 ) . unwrap_err( )
662+ decode_unicode_string_impl:: < true > ( & [ b'u' , b'1' , b':' , 0x90 ] , 0 ) . unwrap_err( )
603663 ) ;
604664 }
605665 }
0 commit comments