use alloc::{vec, vec::Vec};
use miden_core::EventName;
use miden_processor::{AdviceMutation, EventError, ProcessState};
use crate::handlers::u64_to_u32_elements;
pub const U64_DIV_EVENT_NAME: EventName = EventName::new("stdlib::math::u64::u64_div");
pub fn handle_u64_div(process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError> {
let divisor = {
let divisor_hi = process.get_stack_item(1).as_int();
let divisor_lo = process.get_stack_item(2).as_int();
if divisor_hi > u32::MAX.into() {
return Err(U64DivError::NotU32Value {
value: divisor_hi,
position: "divisor_hi",
}
.into());
}
if divisor_lo > u32::MAX.into() {
return Err(U64DivError::NotU32Value {
value: divisor_lo,
position: "divisor_lo",
}
.into());
}
let divisor = (divisor_hi << 32) + divisor_lo;
if divisor == 0 {
return Err(U64DivError::DivideByZero.into());
}
divisor
};
let dividend = {
let dividend_hi = process.get_stack_item(3).as_int();
let dividend_lo = process.get_stack_item(4).as_int();
if dividend_hi > u32::MAX.into() {
return Err(U64DivError::NotU32Value {
value: dividend_hi,
position: "dividend_hi",
}
.into());
}
if dividend_lo > u32::MAX.into() {
return Err(U64DivError::NotU32Value {
value: dividend_lo,
position: "dividend_lo",
}
.into());
}
(dividend_hi << 32) + dividend_lo
};
let quotient = dividend / divisor;
let remainder = dividend - quotient * divisor;
let (q_hi, q_lo) = u64_to_u32_elements(quotient);
let (r_hi, r_lo) = u64_to_u32_elements(remainder);
let mutation = AdviceMutation::extend_stack([r_hi, r_lo, q_hi, q_lo]);
Ok(vec![mutation])
}
#[derive(Debug, thiserror::Error)]
pub enum U64DivError {
#[error("division by zero")]
DivideByZero,
#[error("value {value} at {position} is not a valid u32")]
NotU32Value { value: u64, position: &'static str },
}