init
This commit is contained in:
commit
017fa39dc1
|
@ -0,0 +1 @@
|
|||
/target
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.1.0"
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "hex"
|
||||
version = "0.1.0"
|
||||
authors = ["phyto <phyto@disroot.org>"]
|
||||
edition = "2021"
|
||||
description = "A hexadecimal (de)serialiser"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
#![warn(clippy::nursery)]
|
||||
#![warn(clippy::panic_in_result_fn)]
|
||||
|
||||
fn unsigned_to_hex(mut x: u128) -> Option<String> {
|
||||
let mut r = String::new();
|
||||
|
||||
while x > 0 {
|
||||
let digit = x % 0x10;
|
||||
|
||||
r.push(int_to_char(digit as u8)?);
|
||||
x /= 0x10;
|
||||
}
|
||||
|
||||
Some(r.chars().rev().collect())
|
||||
}
|
||||
|
||||
fn unsigned_from_hex(strn: &str) -> Option<u128> {
|
||||
let mut r = 0;
|
||||
|
||||
let mut inp_str = strn.chars().rev().collect::<String>();
|
||||
|
||||
while !inp_str.is_empty() {
|
||||
let digit = char_to_int(inp_str.pop().expect("we just checked it's not empty"))?;
|
||||
r <<= 4;
|
||||
r += u128::from(digit);
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
||||
|
||||
pub fn to_hex(x: i128) -> Option<String> {
|
||||
let mut r = unsigned_to_hex(x.unsigned_abs())?;
|
||||
|
||||
if x < 0 {
|
||||
r.insert(0, '-');
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
||||
|
||||
/// Convert a hexadecimal string into a signed integer.
|
||||
/// A `-` for a negative can be before or after the optional `0x`.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use hex::from_hex;
|
||||
/// assert_eq!( from_hex("e"), Some(14) );
|
||||
/// assert_eq!( from_hex("0xA3"), Some(163) );
|
||||
/// assert_eq!( from_hex("-0xabCdef"), Some(-11259375) );
|
||||
/// assert_eq!( from_hex("-abcdef"), Some(-11259375) );
|
||||
/// assert_eq!( from_hex("0x-ABCDEF"), from_hex("-0xabcdef") );
|
||||
///
|
||||
/// assert_eq!( from_hex("abcdefG"), None );
|
||||
/// assert_eq!( from_hex("ab cd ef"), None );
|
||||
/// assert_eq!( from_hex(" 0011"), None );
|
||||
///
|
||||
/// ```
|
||||
pub fn from_hex(mut strn: &str) -> Option<i128> {
|
||||
let mut is_positive = true;
|
||||
{
|
||||
if let Some(s) = strn.strip_prefix('-') {
|
||||
strn = s;
|
||||
is_positive = false;
|
||||
}
|
||||
|
||||
if let Some(s) = strn.strip_prefix("0x-") {
|
||||
strn = s;
|
||||
is_positive = false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut r = unsigned_from_hex(strn)? as i128;
|
||||
|
||||
if !is_positive {
|
||||
r = -r;
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod _test {
|
||||
#[test]
|
||||
fn to_hex() {
|
||||
use super::*;
|
||||
let pairs = [("3039", 12345), ("4", 4), ("cffee", 851_950), ("-ae", -174)];
|
||||
|
||||
for (lhs, rhs) in pairs {
|
||||
println!("{lhs} == {rhs} ?");
|
||||
assert_eq!(lhs.to_string(), to_hex(rhs).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_hex() {
|
||||
use super::*;
|
||||
let pairs = [("3039", 12345), ("4", 4), ("cffee", 851_950), ("-ae", -174)];
|
||||
|
||||
println!("Hex == Deniary ?");
|
||||
for (lhs, rhs) in pairs {
|
||||
println!("{lhs} == {rhs} ?");
|
||||
assert_eq!(from_hex(lhs).unwrap(), rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn char_to_int(chr: char) -> Option<u8> {
|
||||
const UNCONVERTABLE: u8 = core::u8::MAX;
|
||||
|
||||
let r = match chr.to_ascii_lowercase() {
|
||||
'0' => 0,
|
||||
'1' => 1,
|
||||
'2' => 2,
|
||||
'3' => 3,
|
||||
'4' => 4,
|
||||
'5' => 5,
|
||||
'6' => 6,
|
||||
'7' => 7,
|
||||
'8' => 8,
|
||||
'9' => 9,
|
||||
'a' => 10,
|
||||
'b' => 11,
|
||||
'c' => 12,
|
||||
'd' => 13,
|
||||
'e' => 14,
|
||||
'f' => 15,
|
||||
_ => UNCONVERTABLE,
|
||||
};
|
||||
|
||||
if r == UNCONVERTABLE {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
||||
|
||||
const fn int_to_char(i: u8) -> Option<char> {
|
||||
const UNCONVERTABLE: char = '\0';
|
||||
|
||||
let r = match i {
|
||||
0 => '0',
|
||||
1 => '1',
|
||||
2 => '2',
|
||||
3 => '3',
|
||||
4 => '4',
|
||||
5 => '5',
|
||||
6 => '6',
|
||||
7 => '7',
|
||||
8 => '8',
|
||||
9 => '9',
|
||||
10 => 'a',
|
||||
11 => 'b',
|
||||
12 => 'c',
|
||||
13 => 'd',
|
||||
14 => 'e',
|
||||
15 => 'f',
|
||||
_ => UNCONVERTABLE,
|
||||
};
|
||||
|
||||
if r == UNCONVERTABLE {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
Loading…
Reference in New Issue