use std::any::Any;
use std::fmt::Debug;
use std::rc::Rc;
use crate::checker::runtime::{Runtime, Stop};
use crate::checker::value::Value;
pub trait ForeignValue: Debug {
fn eq_value(&self, other: &dyn ForeignValue) -> bool;
fn hash_value(&self) -> u64 {
0
}
fn display(&self) -> String {
format!("{:?}", self)
}
fn as_any(&self) -> &dyn Any;
}
pub fn foreign(v: impl ForeignValue + 'static) -> Value {
Value::Foreign(Rc::new(v))
}
#[derive(Debug)]
pub enum ForeignError {
Exception(String, String),
Stopped(Stop),
}
impl From<Stop> for ForeignError {
fn from(s: Stop) -> Self {
ForeignError::Stopped(s)
}
}
pub struct ForeignCx<'a, 'p> {
pub(crate) rt: &'a mut Runtime<'p>,
pub(crate) machine: Option<usize>,
}
impl ForeignCx<'_, '_> {
pub fn machine_name(&self) -> Option<String> {
self.machine.map(|m| self.rt.machines[m].name.to_string())
}
pub fn log_line(&mut self, text: &str) {
self.rt.log(|_| format!("<PrintLog> {}", text));
if self.rt.json_enabled() {
self.rt.jlog(
"Print",
crate::checker::jsonlog::Details { log: Some(text.to_string()), ..Default::default() },
false,
);
}
}
pub fn random_int(&mut self, max: i32) -> Result<i32, ForeignError> {
if max < 0 {
return Err(ForeignError::Exception(
"System.ArgumentOutOfRangeException".into(),
format!(
"maxValue ('{}') must be a non-negative value. (Parameter 'maxValue')\nActual value was {}.",
max, max
),
));
}
let caller = self.machine_name().unwrap_or_default();
Ok(self.rt.choose_int(max, &caller)?)
}
pub fn random_bool(&mut self) -> Result<bool, ForeignError> {
let caller = self.machine_name().unwrap_or_default();
Ok(self.rt.choose_bool(2, &caller)?)
}
}
pub trait ForeignFunctions {
fn call(
&self,
name: &str,
owner: Option<&str>,
args: &[Value],
cx: &mut ForeignCx,
) -> Option<Result<Value, ForeignError>>;
}