proxmox/proxmox-tools/src/lib.rs
Wolfgang Bumiller 09d84f6634 [clippy] tools: lifetimes and constants
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
2019-08-22 09:42:05 +02:00

167 lines
4.0 KiB
Rust

//! This is a general utility crate used by all our rust projects.
use failure::*;
use lazy_static::lazy_static;
pub mod borrow;
pub mod common_regex;
pub mod fd;
pub mod fs;
pub mod io;
pub mod serde;
pub mod vec;
/// Evaluates to the offset (in bytes) of a given member within a struct
#[macro_export]
macro_rules! offsetof {
($ty:ty, $field:ident) => {
unsafe { &(*(0 as *const $ty)).$field as *const _ as usize }
};
}
/// Macro to write error-handling blocks (like perl eval {})
///
/// #### Example:
/// ```
/// # use proxmox_tools::try_block;
/// # use failure::*;
/// # let some_condition = false;
/// let result = try_block!({
/// if (some_condition) {
/// bail!("some error");
/// }
/// Ok(())
/// })
/// .map_err(|e| format_err!("my try block returned an error - {}", e));
/// ```
#[macro_export]
macro_rules! try_block {
{ $($token:tt)* } => {{ (|| -> Result<_,_> { $($token)* })() }}
}
const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
pub fn digest_to_hex(digest: &[u8]) -> String {
bin_to_hex(digest)
}
/// Convert a byte slice to a string of hexadecimal digits.
///
/// ```
/// # use proxmox_tools::bin_to_hex;
///
/// let text = bin_to_hex(&[1, 2, 0xff]);
/// assert_eq!(text, "0102ff");
/// ```
pub fn bin_to_hex(digest: &[u8]) -> String {
let mut buf = Vec::<u8>::with_capacity(digest.len() * 2);
for i in 0..digest.len() {
buf.push(HEX_CHARS[(digest[i] >> 4) as usize]);
buf.push(HEX_CHARS[(digest[i] & 0xf) as usize]);
}
unsafe { String::from_utf8_unchecked(buf) }
}
/// Convert a string of hexadecimal digits to a byte vector. Any non-digits are treated as an
/// error, so when there is possible whitespace in the string it must be stripped by the caller
/// first. Also, only full bytes are allowed, so the input must consist of an even number of
/// digits.
///
/// ```
/// # use proxmox_tools::hex_to_bin;
///
/// let data = hex_to_bin("aabb0123").unwrap();
/// assert_eq!(&data, &[0xaa, 0xbb, 0x01, 0x23]);
/// ```
pub fn hex_to_bin(hex: &str) -> Result<Vec<u8>, Error> {
let mut result = vec![];
let bytes = hex.as_bytes();
if (bytes.len() % 2) != 0 {
bail!("hex_to_bin: got wrong input length.");
}
let val = |c| {
if c >= b'0' && c <= b'9' {
return Ok(c - b'0');
}
if c >= b'a' && c <= b'f' {
return Ok(c - b'a' + 10);
}
if c >= b'A' && c <= b'F' {
return Ok(c - b'A' + 10);
}
bail!("found illegal hex character.");
};
for pair in bytes.chunks(2) {
let h = val(pair[0])?;
let l = val(pair[1])?;
result.push((h << 4) | l);
}
Ok(result)
}
// FIXME: This should be renamed to contain the digest algorithm, so that the array's size makes
// sense.
pub fn hex_to_digest(hex: &str) -> Result<[u8; 32], Error> {
let mut digest = [0u8; 32];
let bytes = hex.as_bytes();
if bytes.len() != 64 {
bail!("got wrong digest length.");
}
let val = |c| {
if c >= b'0' && c <= b'9' {
return Ok(c - b'0');
}
if c >= b'a' && c <= b'f' {
return Ok(c - b'a' + 10);
}
if c >= b'A' && c <= b'F' {
return Ok(c - b'A' + 10);
}
bail!("found illegal hex character.");
};
let mut pos = 0;
for pair in bytes.chunks(2) {
if pos >= digest.len() {
bail!("hex digest too long.");
}
let h = val(pair[0])?;
let l = val(pair[1])?;
digest[pos] = (h << 4) | l;
pos += 1;
}
if pos != digest.len() {
bail!("hex digest too short.");
}
Ok(digest)
}
/// Returns the hosts node name (UTS node name)
pub fn nodename() -> &'static str {
lazy_static! {
static ref NODENAME: String = {
nix::sys::utsname::uname()
.nodename()
.split('.')
.next()
.unwrap()
.to_owned()
};
}
&NODENAME
}