use alloy_primitives::U256;
pub(crate) fn signed_div(a: U256, b: U256) -> U256 {
if b.is_zero() {
return U256::ZERO;
}
let negative = is_negative(a) != is_negative(b);
let quotient = signed_abs(a) / signed_abs(b);
if negative { U256::ZERO.wrapping_sub(quotient) } else { quotient }
}
pub(crate) fn signed_mod(a: U256, b: U256) -> U256 {
if b.is_zero() {
return U256::ZERO;
}
let remainder = signed_abs(a) % signed_abs(b);
if is_negative(a) { U256::ZERO.wrapping_sub(remainder) } else { remainder }
}
pub(crate) fn signed_lt(a: U256, b: U256) -> bool {
match (is_negative(a), is_negative(b)) {
(true, false) => true,
(false, true) => false,
_ => a < b,
}
}
pub(crate) fn signed_gt(a: U256, b: U256) -> bool {
signed_lt(b, a)
}
pub(crate) fn sar(value: U256, shift: U256) -> U256 {
let negative = is_negative(value);
if shift >= U256::from(256) {
return if negative { U256::MAX } else { U256::ZERO };
}
let shift = shift.to::<usize>();
if shift == 0 || !negative {
return value >> shift;
}
let low_mask = (U256::from(1) << (256 - shift)) - U256::from(1);
(value >> shift) | !low_mask
}
pub(crate) fn byte(index: U256, value: U256) -> U256 {
if index >= U256::from(32) {
U256::ZERO
} else {
let shift = 8 * (31 - index.to::<usize>());
(value >> shift) & U256::from(0xff)
}
}
pub(crate) fn signextend(size: U256, value: U256) -> U256 {
if size >= U256::from(31) {
return value;
}
let bit = size.to::<usize>() * 8 + 7;
let sign_bit = U256::from(1) << bit;
let mask = sign_bit - U256::from(1);
if (value & sign_bit).is_zero() { value & mask } else { value | !mask }
}
fn is_negative(value: U256) -> bool {
value.bit(255)
}
fn signed_abs(value: U256) -> U256 {
if is_negative(value) { U256::ZERO.wrapping_sub(value) } else { value }
}