use crate::abend::Abend;
use crate::storage::{Loc, Val};
use crate::store::{self, ProgramFacts};
use crate::taint::Taint;
use crate::vocab::Pos;
use numeric::precision::{Fixed, Places};
type R<T> = Result<T, Abend>;
pub trait Host<P: Copy> {
type Facts: ProgramFacts;
fn facts(&self) -> Self::Facts;
fn mem(&mut self) -> &mut [u8];
fn taint(&mut self) -> Option<&mut Taint>;
fn locate(&mut self, place: P, receiving: bool) -> R<Loc>;
fn integer(&mut self, place: P, pos: Pos) -> R<i64>;
fn assign(&mut self, dest: Loc, val: Val, src: Option<Loc>, pos: Pos) -> R<()>;
fn store_fixed(&mut self, dest: Loc, value: &Fixed, pos: Pos) -> R<()>;
}
pub trait Values<P: Copy, O>: Host<P> {
fn value(&mut self, operand: &O, pos: Pos) -> R<Val>;
}
pub fn write<P: Copy>(x: &mut impl Host<P>, loc: Loc, bytes: &[u8]) {
x.mem()[loc.offset..loc.offset + loc.len].copy_from_slice(bytes);
mark(x, loc.offset, loc.len);
}
pub fn unfollowed<P: Copy>(x: &mut impl Host<P>, what: &'static str) {
if let Some(t) = x.taint() {
t.unfollowed(what);
}
}
pub fn mark<P: Copy>(x: &mut impl Host<P>, offset: usize, len: usize) {
if let Some(t) = x.taint() {
let pending = t.pending();
t.set(offset, len, pending);
}
}
pub fn read<P: Copy>(x: &mut impl Host<P>, loc: Loc, pos: Pos) -> R<Val> {
store::read(&x.facts(), x.mem(), loc, pos)
}
pub fn set_integer<P: Copy>(x: &mut impl Host<P>, place: P, value: i64, pos: Pos) -> R<()> {
let dest = x.locate(place, false)?;
x.store_fixed(dest, &Fixed::new(value as i128, Places::new(19, 0)), pos)
}