sim-lib-server 0.1.0

SIM workspace package for sim lib server.
Documentation
use sim_kernel::{Expr, Symbol};

use crate::{EvalSite, FrameKind, ServerAddress, ServerFrame};

use super::{Arc, Mutex};

#[derive(Clone)]
pub(crate) struct LoopbackSite {
    pub(crate) address: ServerAddress,
    pub(crate) codecs: Vec<Symbol>,
}

impl EvalSite for LoopbackSite {
    fn site_kind(&self) -> &'static str {
        "loopback"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        _cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        Ok(frame)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

pub(crate) struct ResponseSite {
    pub(crate) address: ServerAddress,
    pub(crate) codecs: Vec<Symbol>,
}

impl EvalSite for ResponseSite {
    fn site_kind(&self) -> &'static str {
        "response"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        ServerFrame::from_expr(
            cx,
            frame.codec.clone(),
            FrameKind::Response,
            &Expr::Map(vec![
                (Expr::Symbol(Symbol::new("value")), Expr::Nil),
                (
                    Expr::Symbol(Symbol::new("diagnostics")),
                    Expr::List(Vec::new()),
                ),
                (Expr::Symbol(Symbol::new("trace")), Expr::Nil),
            ]),
            frame.envelope.consistency,
            Vec::new(),
            false,
        )
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

pub(crate) struct RecordingSite {
    pub(crate) address: ServerAddress,
    pub(crate) codecs: Vec<Symbol>,
    pub(crate) seen: Arc<Mutex<Vec<FrameKind>>>,
}

impl EvalSite for RecordingSite {
    fn site_kind(&self) -> &'static str {
        "recording"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        self.seen
            .lock()
            .expect("recording site mutex poisoned")
            .push(frame.kind.clone());
        ServerFrame::from_expr(
            cx,
            frame.codec.clone(),
            FrameKind::Response,
            &Expr::Map(vec![
                (Expr::Symbol(Symbol::new("value")), Expr::Nil),
                (
                    Expr::Symbol(Symbol::new("diagnostics")),
                    Expr::List(Vec::new()),
                ),
                (Expr::Symbol(Symbol::new("trace")), Expr::Nil),
            ]),
            frame.envelope.consistency,
            Vec::new(),
            false,
        )
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

pub(crate) struct TransformSite {
    pub(crate) address: ServerAddress,
    pub(crate) codecs: Vec<Symbol>,
    pub(crate) prefix: &'static str,
    pub(crate) hops: Arc<Mutex<Vec<u32>>>,
}

impl EvalSite for TransformSite {
    fn site_kind(&self) -> &'static str {
        "transform"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        self.hops
            .lock()
            .expect("transform site mutex poisoned")
            .push(frame.envelope.hop);
        let request = crate::eval_request_from_frame(cx, &frame)?;
        let Expr::String(text) = request.expr else {
            panic!("transform site expects string requests");
        };
        crate::server_frame_from_reply(
            cx,
            &frame.codec,
            sim_kernel::EvalReply {
                value: cx.factory().string(format!("{}{}", self.prefix, text))?,
                diagnostics: Vec::new(),
                trace: None,
            },
            frame.envelope.consistency,
        )
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

pub(crate) struct MultiChunkSite {
    pub(crate) address: ServerAddress,
    pub(crate) codecs: Vec<Symbol>,
}

impl EvalSite for MultiChunkSite {
    fn site_kind(&self) -> &'static str {
        "multi-chunk"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        ServerFrame::from_expr(
            cx,
            frame.codec.clone(),
            FrameKind::Response,
            &Expr::Map(vec![
                (Expr::Symbol(Symbol::new("value")), Expr::Nil),
                (
                    Expr::Symbol(Symbol::new("diagnostics")),
                    Expr::List(Vec::new()),
                ),
                (Expr::Symbol(Symbol::new("trace")), Expr::Nil),
            ]),
            frame.envelope.consistency,
            Vec::new(),
            false,
        )
    }

    fn stream(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
        sink: &mut dyn crate::StreamSink,
    ) -> sim_kernel::Result<()> {
        sink.chunk(
            cx,
            ServerFrame::new(
                frame.codec.clone(),
                FrameKind::StreamStart,
                frame.envelope.clone(),
                Vec::new(),
            ),
        )?;
        for text in ["alpha", "beta"] {
            let chunk = ServerFrame::from_expr(
                cx,
                frame.codec.clone(),
                FrameKind::StreamChunk,
                &Expr::String(text.to_owned()),
                frame.envelope.consistency,
                Vec::new(),
                false,
            )?;
            sink.chunk(cx, chunk)?;
        }
        sink.chunk(
            cx,
            ServerFrame::new(
                frame.codec,
                FrameKind::StreamEnd,
                frame.envelope,
                Vec::new(),
            ),
        )?;
        sink.end(cx)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}