@@ -134,6 +134,29 @@ impl Method {
134
134
}
135
135
}
136
136
137
+ /// Convert static bytes into a `Method`.
138
+ ///
139
+ /// # Panics
140
+ ///
141
+ /// If the input bytes are not a valid method name or if the method name is over 15 bytes.
142
+ pub const fn from_static ( src : & ' static [ u8 ] ) -> Method {
143
+ match src {
144
+ b"OPTIONS" => Method :: OPTIONS ,
145
+ b"GET" => Method :: GET ,
146
+ b"POST" => Method :: POST ,
147
+ b"PUT" => Method :: PUT ,
148
+ b"DELETE" => Method :: DELETE ,
149
+ b"HEAD" => Method :: HEAD ,
150
+ b"TRACE" => Method :: TRACE ,
151
+ b"CONNECT" => Method :: CONNECT ,
152
+ b"PATCH" => Method :: PATCH ,
153
+ src => {
154
+ let inline = InlineExtension :: from_static ( src) ;
155
+ Method ( ExtensionInline ( inline) )
156
+ }
157
+ }
158
+ }
159
+
137
160
fn extension_inline ( src : & [ u8 ] ) -> Result < Method , InvalidMethod > {
138
161
let inline = InlineExtension :: new ( src) ?;
139
162
@@ -316,6 +339,9 @@ mod extension {
316
339
// Invariant: self.0 contains valid UTF-8.
317
340
pub struct AllocatedExtension ( Box < [ u8 ] > ) ;
318
341
342
+ #[ derive( Clone , PartialEq , Eq , Hash ) ]
343
+ pub struct StaticExtension ( & ' static [ u8 ] ) ;
344
+
319
345
impl InlineExtension {
320
346
// Method::from_bytes() assumes this is at least 7
321
347
pub const MAX : usize = 15 ;
@@ -330,6 +356,34 @@ mod extension {
330
356
Ok ( InlineExtension ( data, src. len ( ) as u8 ) )
331
357
}
332
358
359
+ /// Convert static bytes into an `InlineExtension`.
360
+ ///
361
+ /// # Panics
362
+ ///
363
+ /// If the input bytes are not a valid method name or if the method name is over 15 bytes.
364
+ pub const fn from_static ( src : & ' static [ u8 ] ) -> InlineExtension {
365
+ let mut i = 0 ;
366
+ let mut dst = [ 0u8 ; 15 ] ;
367
+ if src. len ( ) > 15 {
368
+ // panicking in const requires Rust 1.57.0
369
+ #[ allow( unconditional_panic) ]
370
+ ( [ ] as [ u8 ; 0 ] ) [ 0 ] ;
371
+ }
372
+ while i < src. len ( ) {
373
+ let byte = src[ i] ;
374
+ let v = METHOD_CHARS [ byte as usize ] ;
375
+ if v == 0 {
376
+ // panicking in const requires Rust 1.57.0
377
+ #[ allow( unconditional_panic) ]
378
+ ( [ ] as [ u8 ; 0 ] ) [ 0 ] ;
379
+ }
380
+ dst[ i] = byte;
381
+ i += 1 ;
382
+ }
383
+
384
+ InlineExtension ( dst, i as u8 )
385
+ }
386
+
333
387
pub fn as_str ( & self ) -> & str {
334
388
let InlineExtension ( ref data, len) = self ;
335
389
// Safety: the invariant of InlineExtension ensures that the first
@@ -436,6 +490,43 @@ mod test {
436
490
assert_eq ! ( Method :: GET , & Method :: GET ) ;
437
491
}
438
492
493
+ #[ test]
494
+ fn test_from_static ( ) {
495
+ // First class variant
496
+ assert_eq ! (
497
+ Method :: from_static( b"GET" ) ,
498
+ Method :: from_bytes( b"GET" ) . unwrap( )
499
+ ) ;
500
+ // Inline, len < 15
501
+ assert_eq ! (
502
+ Method :: from_static( b"PROPFIND" ) ,
503
+ Method :: from_bytes( b"PROPFIND" ) . unwrap( )
504
+ ) ;
505
+ // Inline, len == 15
506
+ assert_eq ! ( Method :: from_static( b"GET" ) , Method :: GET ) ;
507
+ assert_eq ! (
508
+ Method :: from_static( b"123456789012345" ) . to_string( ) ,
509
+ "123456789012345" . to_string( )
510
+ ) ;
511
+ }
512
+
513
+ #[ test]
514
+ #[ should_panic]
515
+ fn test_from_static_too_long ( ) {
516
+ // Ref, len > 15
517
+ Method :: from_static ( b"1234567890123456" ) ;
518
+ assert_eq ! (
519
+ Method :: from_static( b"1234567890123456" ) . to_string( ) ,
520
+ "1234567890123456" . to_string( )
521
+ ) ;
522
+ }
523
+
524
+ #[ test]
525
+ #[ should_panic]
526
+ fn test_from_static_bad ( ) {
527
+ Method :: from_static ( b"\0 " ) ;
528
+ }
529
+
439
530
#[ test]
440
531
fn test_invalid_method ( ) {
441
532
assert ! ( Method :: from_str( "" ) . is_err( ) ) ;
@@ -497,4 +588,13 @@ mod test {
497
588
) ;
498
589
}
499
590
}
591
+
592
+ #[ test]
593
+ fn test_extension_comparison ( ) {
594
+ const REPORT : Method = Method :: from_static ( b"REPORT" ) ;
595
+
596
+ let m = Method :: from_bytes ( b"REPORT" ) . unwrap ( ) ;
597
+
598
+ assert ! ( matches!( m, REPORT ) ) ;
599
+ }
500
600
}
0 commit comments