1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
macro_rules! parse_signed {
    ($t:ty) => {
        impl Integer for $t {
            fn parse(mut x: &[u8]) -> (Self, usize) {
                let first = match x.first() {
                    Some(x) => *x,
                    None => return (0, 0),
                };
                let len = x.len();
                let mut pos = true;
                if first == b'-' {
                    unsafe {
                        x = x.get_unchecked(1..);
                    }
                    pos = false;
                } else if first == b'+' {
                    unsafe {
                        x = x.get_unchecked(1..);
                    }
                }
                let mut out: $t = 0;
                if pos {
                    match x.split_first() {
                        Some((&dig @ b'0'..=b'9', y)) => {
                            x = y;
                            out = out.wrapping_mul(10).wrapping_add((dig - b'0') as _);
                        }
                        _ => return (0, 0),
                    }
                    while let Some((&dig @ b'0'..=b'9', y)) = x.split_first() {
                        x = y;
                        out = out.wrapping_mul(10).wrapping_add((dig - b'0') as _);
                    }
                } else {
                    match x.split_first() {
                        Some((&dig @ b'0'..=b'9', y)) => {
                            x = y;
                            out = out.wrapping_mul(10).wrapping_sub((dig - b'0') as _);
                        }
                        _ => return (0, 0),
                    }
                    while let Some((&dig @ b'0'..=b'9', y)) = x.split_first() {
                        x = y;
                        out = out.wrapping_mul(10).wrapping_sub((dig - b'0') as _);
                    }
                }
                (out, len - x.len())
            }
        }
    };
}

macro_rules! parse_unsigned {
    ($t:ty) => {
        impl Integer for $t {
            fn parse(mut x: &[u8]) -> (Self, usize) {
                let first = match x.first() {
                    Some(x) => *x,
                    None => return (0, 0),
                };
                let len = x.len();
                if first == b'+' {
                    unsafe {
                        x = x.get_unchecked(1..);
                    }
                }
                let mut out: $t = 0;
                match x.split_first() {
                    Some((&dig @ b'0'..=b'9', y)) => {
                        x = y;
                        out = out.wrapping_mul(10).wrapping_add((dig - b'0') as _);
                    }
                    _ => return (0, 0),
                }
                while let Some((&dig @ b'0'..=b'9', y)) = x.split_first() {
                    x = y;
                    out = out.wrapping_mul(10).wrapping_add((dig - b'0') as _);
                }
                (out, len - x.len())
            }
        }
    };
}

pub trait Integer: Copy {
    fn parse(buf: &[u8]) -> (Self, usize);
}

pub fn parse_int<T: Integer>(n: &[u8]) -> (T, usize) {
    T::parse(n)
}

parse_signed!(i8);
parse_signed!(i16);
parse_signed!(i32);
parse_signed!(i64);
parse_unsigned!(u8);
parse_unsigned!(u16);
parse_unsigned!(u32);
parse_unsigned!(u64);

#[test]
fn test() {
    assert_eq!(parse_int(b"1004"), (1004, 4));
    assert_eq!(parse_int(b"-44a"), (-44, 3));
    assert_eq!(parse_int(b"+142"), (142, 4));
    assert_eq!(parse_int(b"+4544["), (4544, 5));
    assert_eq!(parse_int(b"++4544["), (0, 0));
}