diff --git a/src/status.rs b/src/status.rs index 903bd82c..53de2d1a 100644 --- a/src/status.rs +++ b/src/status.rs @@ -15,6 +15,7 @@ //! ``` use std::convert::TryFrom; +use std::num::NonZeroU16; use std::error::Error; use std::fmt; use std::str::FromStr; @@ -22,7 +23,7 @@ use std::str::FromStr; /// An HTTP status code (`status-code` in RFC 7230 et al.). /// /// This type contains constants for all common status codes. -/// It allows status codes in the range [100, 599]. +/// It allows status codes in the range [100, 999]. /// /// IANA maintain the [Hypertext Transfer Protocol (HTTP) Status Code /// Registry](http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) which is @@ -39,12 +40,12 @@ use std::str::FromStr; /// assert!(StatusCode::OK.is_success()); /// ``` #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct StatusCode(u16); +pub struct StatusCode(NonZeroU16); /// A possible error value when converting a `StatusCode` from a `u16` or `&str` /// /// This error indicates that the supplied input was not a valid number, was less -/// than 100, or was greater than 599. +/// than 100, or was greater than 999. pub struct InvalidStatusCode { _priv: (), } @@ -53,7 +54,7 @@ impl StatusCode { /// Converts a u16 to a status code. /// /// The function validates the correctness of the supplied u16. It must be - /// greater or equal to 100 but less than 600. + /// greater or equal to 100 but less than 1000. /// /// # Example /// @@ -68,11 +69,13 @@ impl StatusCode { /// ``` #[inline] pub fn from_u16(src: u16) -> Result { - if src < 100 || src >= 600 { + if src < 100 || src >= 1000 { return Err(InvalidStatusCode::new()); } - Ok(StatusCode(src)) + NonZeroU16::new(src) + .map(StatusCode) + .ok_or_else(InvalidStatusCode::new) } /// Converts a &[u8] to a status code @@ -85,12 +88,14 @@ impl StatusCode { let b = src[1].wrapping_sub(b'0') as u16; let c = src[2].wrapping_sub(b'0') as u16; - if a == 0 || a > 5 || b > 9 || c > 9 { + if a == 0 || a > 9 || b > 9 || c > 9 { return Err(InvalidStatusCode::new()); } let status = (a * 100) + (b * 10) + c; - Ok(StatusCode(status)) + NonZeroU16::new(status) + .map(StatusCode) + .ok_or_else(InvalidStatusCode::new) } /// Returns the `u16` corresponding to this `StatusCode`. @@ -126,7 +131,14 @@ impl StatusCode { /// ``` #[inline] pub fn as_str(&self) -> &str { - CODES_AS_STR[(self.0 - 100) as usize] + let offset = (self.0.get() - 100) as usize; + let offset = offset * 3; + + unsafe { + CODES_AS_STR + .get_unchecked(offset..) + .get_unchecked(..3) + } } /// Get the standardised `reason-phrase` for this status code. @@ -148,37 +160,37 @@ impl StatusCode { /// assert_eq!(status.canonical_reason(), Some("OK")); /// ``` pub fn canonical_reason(&self) -> Option<&'static str> { - canonical_reason(self.0) + canonical_reason(self.0.get()) } /// Check if status is within 100-199. #[inline] pub fn is_informational(&self) -> bool { - 200 > self.0 && self.0 >= 100 + 200 > self.0.get() && self.0.get() >= 100 } /// Check if status is within 200-299. #[inline] pub fn is_success(&self) -> bool { - 300 > self.0 && self.0 >= 200 + 300 > self.0.get() && self.0.get() >= 200 } /// Check if status is within 300-399. #[inline] pub fn is_redirection(&self) -> bool { - 400 > self.0 && self.0 >= 300 + 400 > self.0.get() && self.0.get() >= 300 } /// Check if status is within 400-499. #[inline] pub fn is_client_error(&self) -> bool { - 500 > self.0 && self.0 >= 400 + 500 > self.0.get() && self.0.get() >= 400 } /// Check if status is within 500-599. #[inline] pub fn is_server_error(&self) -> bool { - 600 > self.0 && self.0 >= 500 + 600 > self.0.get() && self.0.get() >= 500 } } @@ -231,7 +243,7 @@ impl PartialEq for u16 { impl From for u16 { #[inline] fn from(status: StatusCode) -> u16 { - status.0 + status.0.get() } } @@ -287,7 +299,7 @@ macro_rules! status_codes { impl StatusCode { $( $(#[$docs])* - pub const $konst: StatusCode = StatusCode($num); + pub const $konst: StatusCode = StatusCode(unsafe { NonZeroU16::new_unchecked($num) }); )+ } @@ -523,7 +535,11 @@ impl Error for InvalidStatusCode {} macro_rules! status_code_strs { ($($num:expr,)+) => { - const CODES_AS_STR: [&'static str; 500] = [ $( stringify!($num), )+ ]; + const CODES_AS_STR: &'static str = concat!( + $( + stringify!($num) , + )+ + ); } } @@ -557,4 +573,28 @@ status_code_strs!( 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, + + 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, + 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, + 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, + 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, + 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, + + 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, + 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, + 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, + 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, + 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, + + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, + 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, + 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, + 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, + 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, + + 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, + 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, + 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, + 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, + 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, ); diff --git a/tests/status_code.rs b/tests/status_code.rs index 80df748e..9dda9bd1 100644 --- a/tests/status_code.rs +++ b/tests/status_code.rs @@ -3,13 +3,13 @@ use http::*; #[test] fn from_bytes() { for ok in &[ - "100", "101", "199", "200", "250", "299", "321", "399", "499", "599", + "100", "101", "199", "200", "250", "299", "321", "399", "499", "599", "600", "999" ] { assert!(StatusCode::from_bytes(ok.as_bytes()).is_ok()); } for not_ok in &[ - "0", "00", "10", "40", "99", "000", "010", "099", "600", "610", "999", + "0", "00", "10", "40", "99", "000", "010", "099", "1000", "1999", ] { assert!(StatusCode::from_bytes(not_ok.as_bytes()).is_err()); } @@ -66,4 +66,28 @@ test_round_trip!( 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, + + 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, + 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, + 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, + 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, + 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, + + 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, + 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, + 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, + 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, + 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, + + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, + 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, + 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, + 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, + 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, + + 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, + 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, + 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, + 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, + 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, );