use super::algebraic::{EffectusAlgebraicus, TractatorAlgebraicus};
use super::continuation_v2::ContinuatioSemel;
use alloc::vec::Vec;
use core::marker::PhantomData;
#[derive(Debug, Clone)]
pub enum StatusOp<S> {
Get,
Put(S),
}
impl<S: Clone + Send + Sync + 'static> EffectusAlgebraicus for StatusOp<S> {
type Result = S;
}
pub struct StatusHandler<S> {
pub state: S,
}
impl<S> StatusHandler<S> {
#[inline]
pub fn new(initial: S) -> Self {
StatusHandler { state: initial }
}
#[inline]
pub fn get_state(&self) -> &S {
&self.state
}
#[inline]
pub fn get_state_mut(&mut self) -> &mut S {
&mut self.state
}
}
impl<S: Clone + Send + Sync + 'static> TractatorAlgebraicus<StatusOp<S>> for StatusHandler<S> {
type Output = S;
#[inline]
fn handle_return(&self, value: S) -> S {
value
}
#[inline]
fn handle_operation(&mut self, op: StatusOp<S>, cont: ContinuatioSemel<S, S>) -> S {
match op {
StatusOp::Get => cont.resume(self.state.clone()),
StatusOp::Put(s) => {
self.state = s.clone();
cont.resume(s)
}
}
}
}
#[derive(Debug, Clone)]
pub enum LectorOp<R> {
Ask,
#[doc(hidden)]
_Phantom(PhantomData<R>, core::convert::Infallible),
}
impl<R: Clone + Send + Sync + 'static> EffectusAlgebraicus for LectorOp<R> {
type Result = R;
}
pub struct LectorHandler<R> {
env: R,
}
impl<R> LectorHandler<R> {
#[inline]
pub fn new(env: R) -> Self {
LectorHandler { env }
}
#[inline]
pub fn env(&self) -> &R {
&self.env
}
}
impl<R: Clone + Send + Sync + 'static> TractatorAlgebraicus<LectorOp<R>> for LectorHandler<R> {
type Output = R;
#[inline]
fn handle_return(&self, value: R) -> R {
value
}
#[inline]
fn handle_operation(&mut self, op: LectorOp<R>, cont: ContinuatioSemel<R, R>) -> R {
match op {
LectorOp::Ask => cont.resume(self.env.clone()),
LectorOp::_Phantom(_, never) => match never {},
}
}
}
#[derive(Debug, Clone)]
pub enum ScriptorOp<W> {
Tell(W),
}
impl<W: Clone + Send + Sync + 'static> EffectusAlgebraicus for ScriptorOp<W> {
type Result = ();
}
pub struct ScriptorHandler<W> {
output: Vec<W>,
}
impl<W> ScriptorHandler<W> {
#[inline]
pub fn new() -> Self {
ScriptorHandler { output: Vec::new() }
}
#[inline]
pub fn output(&self) -> &[W] {
&self.output
}
#[inline]
pub fn into_output(self) -> Vec<W> {
self.output
}
#[inline]
pub fn clear(&mut self) {
self.output.clear();
}
}
impl<W> Default for ScriptorHandler<W> {
fn default() -> Self {
Self::new()
}
}
impl<W: Clone + Send + Sync + 'static> TractatorAlgebraicus<ScriptorOp<W>> for ScriptorHandler<W> {
type Output = ();
#[inline]
fn handle_return(&self, _value: ()) {}
#[inline]
fn handle_operation(&mut self, op: ScriptorOp<W>, cont: ContinuatioSemel<(), ()>) {
match op {
ScriptorOp::Tell(w) => {
self.output.push(w);
cont.resume(());
}
}
}
}
#[derive(Debug, Clone)]
pub enum ErrorOp<E> {
Raise(E),
}
impl<E: Clone + Send + Sync + 'static> EffectusAlgebraicus for ErrorOp<E> {
type Result = core::convert::Infallible;
}
pub struct ErrorHandler<E, A> {
_error: PhantomData<E>,
_output: PhantomData<A>,
}
impl<E, A> ErrorHandler<E, A> {
#[inline]
pub fn new() -> Self {
ErrorHandler {
_error: PhantomData,
_output: PhantomData,
}
}
}
impl<E, A> Default for ErrorHandler<E, A> {
fn default() -> Self {
Self::new()
}
}
impl<E: Clone + Send + Sync + 'static, A: 'static> TractatorAlgebraicus<ErrorOp<E>>
for ErrorHandler<E, A>
{
type Output = Result<A, E>;
#[inline]
fn handle_return(&self, value: Result<A, E>) -> Result<A, E> {
value
}
#[inline]
fn handle_operation(
&mut self,
op: ErrorOp<E>,
_cont: ContinuatioSemel<core::convert::Infallible, Result<A, E>>,
) -> Result<A, E> {
match op {
ErrorOp::Raise(e) => Err(e),
}
}
}
#[derive(Debug, Clone)]
pub enum ElectioOp<A> {
Choose(Vec<A>),
Fail,
}
impl<A: Clone + Send + Sync + 'static> EffectusAlgebraicus for ElectioOp<A> {
type Result = A;
}
pub struct ElectioHandler<A> {
results: Vec<A>,
}
impl<A> ElectioHandler<A> {
#[inline]
pub fn new() -> Self {
ElectioHandler {
results: Vec::new(),
}
}
#[inline]
pub fn results(&self) -> &[A] {
&self.results
}
#[inline]
pub fn into_results(self) -> Vec<A> {
self.results
}
}
impl<A> Default for ElectioHandler<A> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub enum AsyncOp {
Yield,
}
impl EffectusAlgebraicus for AsyncOp {
type Result = ();
}
#[derive(Debug, Clone)]
pub enum ConsolaOp {
PrintLine(alloc::string::String),
ReadLine,
}
impl EffectusAlgebraicus for ConsolaOp {
type Result = alloc::string::String;
}
pub struct MockConsolaHandler {
inputs: Vec<alloc::string::String>,
input_index: usize,
outputs: Vec<alloc::string::String>,
}
impl MockConsolaHandler {
#[inline]
pub fn new(inputs: Vec<alloc::string::String>) -> Self {
MockConsolaHandler {
inputs,
input_index: 0,
outputs: Vec::new(),
}
}
#[inline]
pub fn outputs(&self) -> &[alloc::string::String] {
&self.outputs
}
#[inline]
pub fn into_outputs(self) -> Vec<alloc::string::String> {
self.outputs
}
}
impl TractatorAlgebraicus<ConsolaOp> for MockConsolaHandler {
type Output = alloc::string::String;
fn handle_return(&self, value: alloc::string::String) -> alloc::string::String {
value
}
fn handle_operation(
&mut self,
op: ConsolaOp,
cont: ContinuatioSemel<alloc::string::String, alloc::string::String>,
) -> alloc::string::String {
match op {
ConsolaOp::PrintLine(s) => {
self.outputs.push(s);
cont.resume(alloc::string::String::new())
}
ConsolaOp::ReadLine => {
let input = if self.input_index < self.inputs.len() {
let s = self.inputs[self.input_index].clone();
self.input_index += 1;
s
} else {
alloc::string::String::new()
};
cont.resume(input)
}
}
}
}
#[cfg(test)]
mod tests {
use super::super::algebraic::run_with_handler;
use super::*;
use crate::effects::ComputatioStatus;
use alloc::string::ToString;
use alloc::vec;
#[test]
fn test_status_handler_get() {
let mut handler = StatusHandler::new(42);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: StatusOp::Get,
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, 42);
}
#[test]
fn test_status_handler_put() {
let mut handler = StatusHandler::new(0);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: StatusOp::Put(42),
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, 42);
assert_eq!(handler.state, 42);
}
#[test]
fn test_lector_handler() {
let mut handler = LectorHandler::new("test_env".to_string());
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: LectorOp::Ask,
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, "test_env");
}
#[test]
fn test_scriptor_handler() {
let mut handler: ScriptorHandler<&str> = ScriptorHandler::new();
let _: () = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: ScriptorOp::Tell("log1"),
continuatio: ContinuatioSemel::new(|()| ComputatioStatus::Completus(())),
});
assert_eq!(handler.output(), &["log1"]);
}
#[test]
fn test_error_handler() {
let mut handler: ErrorHandler<&str, i32> = ErrorHandler::new();
let result: Result<i32, &str> =
run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: ErrorOp::Raise("error!"),
continuatio: ContinuatioSemel::new(|_: core::convert::Infallible| unreachable!()),
});
assert_eq!(result, Err("error!"));
}
#[test]
fn test_mock_console_print() {
let mut handler = MockConsolaHandler::new(vec![]);
let _ = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: ConsolaOp::PrintLine("Hello!".to_string()),
continuatio: ContinuatioSemel::new(|_| ComputatioStatus::Completus("done".to_string())),
});
assert_eq!(handler.outputs(), &["Hello!"]);
}
#[test]
fn test_mock_console_read() {
let mut handler = MockConsolaHandler::new(vec!["user_input".to_string()]);
let result = run_with_handler(&mut handler, || ComputatioStatus::Suspensus {
operatio: ConsolaOp::ReadLine,
continuatio: ContinuatioSemel::new(ComputatioStatus::Completus),
});
assert_eq!(result, "user_input");
}
#[test]
fn test_choice_effect() {
let choose_op = ElectioOp::Choose(vec![1, 2, 3]);
match choose_op {
ElectioOp::Choose(v) => assert_eq!(v, vec![1, 2, 3]),
ElectioOp::Fail => panic!("Unexpected Fail"),
}
}
#[test]
fn test_async_op() {
let _ = AsyncOp::Yield;
}
}