aboutsummaryrefslogtreecommitdiff
path: root/src/utils.rs
blob: fcfcb70f6666bf0d16ebb0033575220d7be64c0e (plain)
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
110
111
112
113
114
115
116
117
118
119
120
use crate::{DeserializeErr, DeserializeResult, Deserialized};
use alloc::string::String;

pub fn read_one_byte(data: &[u8]) -> DeserializeResult<u8> {
    match data.split_first() {
        Some((byte, rest)) => Deserialized::ok(*byte, rest),
        None => Err(DeserializeErr::Eof),
    }
}

pub fn take(amount: usize) -> impl for<'b> Fn(&'b [u8]) -> DeserializeResult<'b, &'b [u8]> {
    move |data| {
        if data.len() < amount {
            Err(DeserializeErr::Eof)
        } else {
            Ok(data.split_at(amount).into())
        }
    }
}

pub fn read_long(data: &[u8]) -> DeserializeResult<u64> {
    Ok(take(8)(data)?.map(move |bytes| {
        (bytes[0] as u64) << 56
            | (bytes[1] as u64) << 48
            | (bytes[2] as u64) << 40
            | (bytes[3] as u64) << 32
            | (bytes[4] as u64) << 24
            | (bytes[5] as u64) << 16
            | (bytes[6] as u64) << 8
            | (bytes[7] as u64)
    }))
}

pub fn write_long(v: u64) -> [u8; 8] {
    [
        (v >> 56) as u8,
        (v >> 48) as u8,
        (v >> 40) as u8,
        (v >> 32) as u8,
        (v >> 24) as u8,
        (v >> 16) as u8,
        (v >> 8) as u8,
        v as u8,
    ]
}

pub fn read_int(data: &[u8]) -> DeserializeResult<u32> {
    Ok(take(4)(data)?.map(move |bytes| {
        (bytes[0] as u32) << 24
            | (bytes[1] as u32) << 16
            | (bytes[2] as u32) << 8
            | (bytes[3] as u32)
    }))
}

pub fn write_int(v: u32) -> [u8; 4] {
    [(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, v as u8]
}

pub fn read_short(data: &[u8]) -> DeserializeResult<u16> {
    Ok(take(2)(data)?.map(move |bytes| (bytes[0] as u16) << 8 | (bytes[1] as u16)))
}

pub fn write_short(v: u16) -> [u8; 2] {
    [(v >> 8) as u8, v as u8]
}

pub fn hex(data: &[u8]) -> String {
    let mut str = String::with_capacity(data.len() * 2);
    for byte_ref in data {
        let byte = *byte_ref;
        str.push(hex_char_for(byte >> 4));
        str.push(hex_char_for(byte & 0xF));
    }
    str
}

const ZERO_ASCII_CODE: u8 = 48;
const LOWER_A_ASCII_CODE: u8 = 97;

fn hex_char_for(half: u8) -> char {
    if half > 0xF {
        panic!("not defined for > 0xF (operates on half a byte)");
    }

    if half < 10 {
        (half + ZERO_ASCII_CODE) as char
    } else {
        (half + (LOWER_A_ASCII_CODE - 10)) as char
    }
}

pub fn parse_hex_char(data: u8) -> Option<u8> {
    const UPPER_A_ASCII_CODE: u8 = 65;
    const LOWER_F_ASCII_CODE: u8 = 102;
    const UPPER_F_ASCII_CODE: u8 = 70;
    const NINE_ASCII_CODE: u8 = 57;

    if data >= LOWER_A_ASCII_CODE {
        if data > LOWER_F_ASCII_CODE {
            None
        } else {
            Some(10 + (data - LOWER_A_ASCII_CODE))
        }
    } else if data >= UPPER_A_ASCII_CODE {
        if data > UPPER_F_ASCII_CODE {
            None
        } else {
            Some(10 + (data - UPPER_A_ASCII_CODE))
        }
    } else if data >= ZERO_ASCII_CODE {
        if data > NINE_ASCII_CODE {
            None
        } else {
            Some(data - ZERO_ASCII_CODE)
        }
    } else {
        None
    }
}