sim-lib-stream-core 0.1.3

Core stream metadata, packets, envelopes, and buffer values.
Documentation
use std::sync::Arc;

use sim_kernel::{Expr, Symbol};
use sim_shape::{
    AnyShape, ExactExprShape, ExprKind, ExprKindShape, OrShape, RepeatShape, Shape,
    TableExtraPolicy, TableFieldSpec, TableShape,
};

use crate::buffer::{BackpressureOutcome, BufferOverflowPolicy};
use crate::envelope::{
    ClockDomain, LatencyClass, STREAM_ENVELOPE_VERSION, StreamCapability,
    stream_envelope_tag_symbol,
};
use crate::metadata::{StreamDirection, StreamMedia};

pub(super) fn metadata_shape() -> Arc<dyn Shape> {
    table(vec![
        required_exact_symbol("kind", sim_kernel::stream_surface::stream_kind()),
        required("id", string_shape()),
        required("media", media_shape()),
        required("direction", direction_shape()),
        required("clock", symbol_shape()),
        required("buffer", buffer_policy_shape()),
    ])
}

pub(super) fn envelope_shape() -> Arc<dyn Shape> {
    table(vec![
        required_exact_symbol("envelope", stream_envelope_tag_symbol()),
        required_exact_string("version", STREAM_ENVELOPE_VERSION.to_string()),
        required("stream-id", symbol_shape()),
        required("packet-id", symbol_shape()),
        required("media", media_shape()),
        required("direction", direction_shape()),
        required("sequence", string_shape()),
        required("ticks", list_of(clock_shape())),
        required("clock-domain", clock_domain_shape()),
        required("clock-domains", list_of(clock_domain_shape())),
        required("profile", transport_profile_shape()),
        required("diagnostics", list_of(symbol_shape())),
        required("packet", packet_shape()),
    ])
}

pub(super) fn media_shape() -> Arc<dyn Shape> {
    exact_symbols([
        StreamMedia::Pcm.symbol(),
        StreamMedia::Midi.symbol(),
        StreamMedia::Diagnostic.symbol(),
        StreamMedia::Data.symbol(),
    ])
}

fn direction_shape() -> Arc<dyn Shape> {
    exact_symbols([
        StreamDirection::Source.symbol(),
        StreamDirection::Sink.symbol(),
        StreamDirection::Duplex.symbol(),
    ])
}

pub(super) fn clock_domain_shape() -> Arc<dyn Shape> {
    exact_symbols([
        ClockDomain::Sample.symbol(),
        ClockDomain::Block.symbol(),
        ClockDomain::Control.symbol(),
        ClockDomain::MidiTick.symbol(),
        ClockDomain::Wall.symbol(),
        ClockDomain::Transport.symbol(),
        ClockDomain::ServerFrame.symbol(),
        ClockDomain::BrowserFrame.symbol(),
        ClockDomain::TraceStep.symbol(),
        ClockDomain::Job.symbol(),
    ])
}

pub(super) fn latency_class_shape() -> Arc<dyn Shape> {
    exact_symbols([
        LatencyClass::OfflineRender.symbol(),
        LatencyClass::BlockLocal.symbol(),
        LatencyClass::Interactive.symbol(),
        LatencyClass::SampleExact.symbol(),
        LatencyClass::BufferedPreview.symbol(),
        LatencyClass::CollabBarDelay.symbol(),
        LatencyClass::RemoteCollaboration.symbol(),
    ])
}

pub(super) fn capability_shape() -> Arc<dyn Shape> {
    exact_symbols([
        StreamCapability::Exact.symbol(),
        StreamCapability::Deterministic.symbol(),
        StreamCapability::Realtime.symbol(),
        StreamCapability::Bounded.symbol(),
        StreamCapability::Remote.symbol(),
        StreamCapability::Replayable.symbol(),
        StreamCapability::Preview.symbol(),
        StreamCapability::Persistent.symbol(),
        StreamCapability::Resumable.symbol(),
        StreamCapability::Lossy.symbol(),
    ])
}

pub(super) fn backpressure_shape() -> Arc<dyn Shape> {
    exact_symbols([
        BackpressureOutcome::Accepted.symbol(),
        BackpressureOutcome::DroppedNewest.symbol(),
        BackpressureOutcome::DroppedOldest.symbol(),
        BackpressureOutcome::Blocked.symbol(),
        BackpressureOutcome::TimedOut.symbol(),
        BackpressureOutcome::Rejected.symbol(),
        BackpressureOutcome::Closed.symbol(),
    ])
}

pub(super) fn clock_shape() -> Arc<dyn Shape> {
    table(vec![
        required("clock", symbol_shape()),
        required("index", any_shape()),
    ])
}

pub(super) fn tempo_shape() -> Arc<dyn Shape> {
    table(vec![required("segments", list_shape())])
}

pub(super) fn buffer_policy_shape() -> Arc<dyn Shape> {
    table(vec![
        required("capacity", string_shape()),
        required("overflow", buffer_overflow_shape()),
    ])
}

fn buffer_overflow_shape() -> Arc<dyn Shape> {
    exact_symbols([
        BufferOverflowPolicy::DropNewest.symbol(),
        BufferOverflowPolicy::DropOldest.symbol(),
        BufferOverflowPolicy::Error.symbol(),
    ])
}

pub(super) fn packet_shape() -> Arc<dyn Shape> {
    table(vec![required("packet", packet_tag_shape())])
}

pub(super) fn data_packet_shape() -> Arc<dyn Shape> {
    table(vec![
        required_exact_symbol("packet", Symbol::qualified("stream/packet", "data")),
        required("kind", symbol_shape()),
        required("payload", any_shape()),
    ])
}

pub(super) fn diagnostic_shape() -> Arc<dyn Shape> {
    table(vec![
        required_exact_symbol("packet", Symbol::qualified("stream/packet", "diagnostic")),
        required("kind", symbol_shape()),
        required("message", string_shape()),
    ])
}

fn packet_tag_shape() -> Arc<dyn Shape> {
    exact_symbols([
        Symbol::qualified("stream/packet", "pcm"),
        Symbol::qualified("stream/packet", "midi"),
        Symbol::qualified("stream/packet", "diagnostic"),
        Symbol::qualified("stream/packet", "data"),
    ])
}

fn transport_profile_shape() -> Arc<dyn Shape> {
    table(vec![
        required("name", symbol_shape()),
        required("latency-class", latency_class_shape()),
        required("capabilities", list_of(capability_shape())),
    ])
}

fn table(fields: Vec<TableFieldSpec>) -> Arc<dyn Shape> {
    Arc::new(TableShape::new(fields, TableExtraPolicy::Allow))
}

fn required(key: &str, shape: Arc<dyn Shape>) -> TableFieldSpec {
    TableFieldSpec {
        key: Symbol::new(key),
        shape,
        required: true,
    }
}

fn required_exact_symbol(key: &str, symbol: Symbol) -> TableFieldSpec {
    required(key, exact_symbol(symbol))
}

fn required_exact_string(key: &str, value: String) -> TableFieldSpec {
    required(key, Arc::new(ExactExprShape::new(Expr::String(value))))
}

fn exact_symbols(symbols: impl IntoIterator<Item = Symbol>) -> Arc<dyn Shape> {
    let choices = symbols.into_iter().map(exact_symbol).collect();
    Arc::new(OrShape::new(choices))
}

fn exact_symbol(symbol: Symbol) -> Arc<dyn Shape> {
    Arc::new(ExactExprShape::new(Expr::Symbol(symbol)))
}

fn any_shape() -> Arc<dyn Shape> {
    Arc::new(AnyShape)
}

fn symbol_shape() -> Arc<dyn Shape> {
    Arc::new(ExprKindShape::new(ExprKind::Symbol))
}

fn string_shape() -> Arc<dyn Shape> {
    Arc::new(ExprKindShape::new(ExprKind::String))
}

fn list_shape() -> Arc<dyn Shape> {
    Arc::new(ExprKindShape::new(ExprKind::List))
}

fn list_of(item: Arc<dyn Shape>) -> Arc<dyn Shape> {
    Arc::new(RepeatShape::new(item))
}