use crate::Error;
use core::fmt;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Target([u8; 32]);
impl Target {
pub const MAX: Target = Target([0xff; 32]);
pub const fn from_be_bytes(bytes: [u8; 32]) -> Self {
Target(bytes)
}
pub const fn to_be_bytes(self) -> [u8; 32] {
self.0
}
pub fn from_hex(s: &str) -> Result<Self, Error> {
crate::hash::hex32(s).map(Target).ok_or(Error::InvalidHex)
}
pub fn from_compact(bits: u32) -> Result<Self, Error> {
let exponent = (bits >> 24) as usize;
let mantissa = bits & 0x007f_ffff;
if mantissa != 0 && bits & 0x0080_0000 != 0 {
return Err(Error::CompactNegative(bits));
}
let mut out = [0u8; 32];
if exponent <= 3 {
let word = mantissa >> (8 * (3 - exponent));
out[29..].copy_from_slice(&word.to_be_bytes()[1..]);
return Ok(Target(out));
}
let shift = exponent - 3;
for i in 0..3 {
let byte = ((mantissa >> (8 * i)) & 0xff) as u8;
let pos = shift + i;
if pos > 31 {
if byte != 0 {
return Err(Error::CompactOverflow(bits));
}
} else {
out[31 - pos] = byte;
}
}
Ok(Target(out))
}
pub fn to_compact(self) -> u32 {
let first = match self.0.iter().position(|&b| b != 0) {
Some(i) => i,
None => return 0,
};
let mut size = 32 - first;
let mut compact: u32 = if size <= 3 {
let mut w = 0u32;
for &b in &self.0[first..] {
w = (w << 8) | u32::from(b);
}
w << (8 * (3 - size))
} else {
(u32::from(self.0[first]) << 16)
| (u32::from(self.0[first + 1]) << 8)
| u32::from(self.0[first + 2])
};
if compact & 0x0080_0000 != 0 {
compact >>= 8;
size += 1;
}
compact | ((size as u32) << 24)
}
pub fn is_zero(self) -> bool {
self.0.iter().all(|&b| b == 0)
}
}
impl fmt::Debug for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Target(")?;
crate::hash::fmt_hex(f, &self.0)?;
f.write_str(")")
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::hash::fmt_hex(f, &self.0)
}
}