Skip to content

Commit f932f7f

Browse files
committed
Add Method::from_static
Allows creating constant `Method` instances, e.g.: const PROPFIND: Method = Method::from_static(b"PROPFIND"); Fixes: #587
1 parent a912445 commit f932f7f

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

src/method.rs

+100
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,29 @@ impl Method {
134134
}
135135
}
136136

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+
137160
fn extension_inline(src: &[u8]) -> Result<Method, InvalidMethod> {
138161
let inline = InlineExtension::new(src)?;
139162

@@ -316,6 +339,9 @@ mod extension {
316339
// Invariant: self.0 contains valid UTF-8.
317340
pub struct AllocatedExtension(Box<[u8]>);
318341

342+
#[derive(Clone, PartialEq, Eq, Hash)]
343+
pub struct StaticExtension(&'static [u8]);
344+
319345
impl InlineExtension {
320346
// Method::from_bytes() assumes this is at least 7
321347
pub const MAX: usize = 15;
@@ -330,6 +356,34 @@ mod extension {
330356
Ok(InlineExtension(data, src.len() as u8))
331357
}
332358

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+
333387
pub fn as_str(&self) -> &str {
334388
let InlineExtension(ref data, len) = self;
335389
// Safety: the invariant of InlineExtension ensures that the first
@@ -436,6 +490,43 @@ mod test {
436490
assert_eq!(Method::GET, &Method::GET);
437491
}
438492

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+
439530
#[test]
440531
fn test_invalid_method() {
441532
assert!(Method::from_str("").is_err());
@@ -497,4 +588,13 @@ mod test {
497588
);
498589
}
499590
}
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+
}
500600
}

0 commit comments

Comments
 (0)