AUDIO
Source snapshot · 12 October 2026

API reference / ravet_graph::TypedChain

Struct TypedChain 

pub struct TypedChain<S: GraphSample, T: StageTuple<S>> { /* private fields */ }
Expand description

Typed, effect-only serial Graph with 1..8 sealed concrete stages.

Record-Vec payload is checked against 4MiB before/after reservation; existing Graph allocations and arbitrary processor-owned storage have separate limits. The internal graph drops before the stable cells, including during unwind. Readonly and stopped-exclusive getters derive from the same cell provenance as callbacks. No references are retained across callback/getter boundaries. Bypass freezes a child but retains its declared latency/tail: audible bypass is not latency compensated. Generated output events and auxiliary buses are rejected; accepted input events use canonical Graph broadcast.

§Audio sessions: prefer the guard

The inherent start_audio() returns a non-Send guard that stops the owner on drop (reverse stage order) on the starting thread. Prefer it. A forgotten guard (mem::forget, a leak) is misuse, not valid use: it leaves the audio owner live exactly like an unpaired manual start (see below), and the guard that would have stopped it no longer exists.

§Manual Processor hooks are a caller obligation

Processor::start_audio on this chain is the canonical manual hook; it returns no guard. The caller must pair it with Processor::stop_audio on the thread that started it before transfer to another thread, deactivate, into_stages or drop. Unlike the guard, nothing stops a manual owner automatically: the facade adds no owner-thread cleanup, no thread check at process, and a manually started chain is Send. While a manual owner (or a forgotten guard) is live:

  • prepare and stage_mut_stopped refuse with AudioSessionActive;
  • deactivate (inherent and Processor), into_stages and Drop do not refuse: they panic through the canonical Graph assertion;
  • Processor::stop_audio called on another thread panics and leaves the owner live, so it can still be stopped on the owning thread afterwards;
  • process, reset, getters and bypass flags keep working.

Unwind caveats, with no safeguard claimed. A caught deactivate panic happens before any state change: the chain stays prepared with the owner live, and the owner thread can still stop_audio. A panic from into_stages or Drop destroys the facade while unwinding: the Graph is dropped, then each stage is dropped exactly once by field drop glue, without stop_audio or deactivate, and no owners are returned. If that panic happens while the thread is already unwinding, the second panic aborts the process; the facade does not prevent that.

§Compile-time exclusions

Unsupported static index:

use ravet_graph::TypedChain;
use ravet_gain::GainProcessor;
let chain = TypedChain::<f32,_>::new((GainProcessor::new(0.).unwrap(),),1,64,0).ok().unwrap();
chain.stage::<1>(); // tuple1 has index0 only

Positive companion (valid index):

use ravet_graph::TypedChain;
use ravet_gain::GainProcessor;
let chain = TypedChain::<f32,_>::new((GainProcessor::new(0.).unwrap(),),1,64,0).ok().unwrap();
let _ = chain.stage::<0>();

A readonly stage borrow excludes set_bypassed:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::Processor;
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>) {
    let stage=chain.stage::<0>();
    chain.set_bypassed::<0>(true);
    let _=stage.latency_samples();
}

A readonly stage borrow excludes process:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::{ProcessBlock,Processor};
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>, block:&mut ProcessBlock<'_,'_,'_,f32>) {
    let stage=chain.stage::<0>();
    let _=chain.process(block);
    let _=stage.latency_samples();
}

Positive companion: finish the readonly borrow before mutating or rendering.

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::{ProcessBlock,Processor};
fn ordered<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>, block:&mut ProcessBlock<'_,'_,'_,f32>) {
    let latency=chain.stage::<0>().latency_samples();
    chain.set_bypassed::<0>(true);
    let _=chain.process(block);
    let _=latency;
}

A live audio session excludes the stopped mutable getter:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::Processor;
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>) {
    let session=chain.start_audio().ok().unwrap();
    let _=chain.stage_mut_stopped::<0>();
    drop(session);
}

Positive companion: drop the session first.

use ravet_graph::{StageAt,TypedChain};
fn ordered<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>) {
    let session=chain.start_audio().ok().unwrap();
    drop(session);
    let _=chain.stage_mut_stopped::<0>();
}

A live &mut P from the stopped getter excludes process:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::{ProcessBlock,Processor};
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>, block:&mut ProcessBlock<'_,'_,'_,f32>) {
    let stage=chain.stage_mut_stopped::<0>().ok().unwrap();
    let _=chain.process(block);
    let _=stage.latency_samples();
}

… excludes a second stage borrow:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::Processor;
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>) {
    let stage=chain.stage_mut_stopped::<0>().ok().unwrap();
    let _=chain.stage::<0>();
    let _=stage.latency_samples();
}

… and excludes prepare:

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::{ProcessConfig,Processor};
fn overlap<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>, config:ProcessConfig) {
    let stage=chain.stage_mut_stopped::<0>().ok().unwrap();
    let _=chain.prepare(config);
    let _=stage.latency_samples();
}

Positive companion: use the exclusive stage, then prepare.

use ravet_graph::{StageAt,TypedChain};
use ravet_foundation::{ProcessConfig,Processor};
fn ordered<T: StageAt<f32,0>>(chain:&mut TypedChain<f32,T>, config:ProcessConfig) {
    let stage=chain.stage_mut_stopped::<0>().ok().unwrap();
    let _=stage.latency_samples();
    let _=chain.prepare(config);
}

The chain is Send (for Send stages) but not Sync:

use ravet_graph::TypedChain;
use ravet_gain::GainProcessor;
fn sync<T:Sync>() {}
sync::<TypedChain<f32,(GainProcessor,)>>();
use ravet_graph::TypedChain;
use ravet_gain::GainProcessor;
fn send<T:Send>() {}
send::<TypedChain<f32,(GainProcessor,)>>();

Implementations§

§

impl<S: GraphSample, T: StageTuple<S>> TypedChain<S, T>

pub fn new( stages: T, channels: usize, maximum_frames: usize, maximum_events: usize, ) -> Result<Self, TypedChainFailure<T>>
where S: From<f32>,

Admission checks return the original tuple before any processor is moved. The Graph::new error recovery below is not reachable for at most eight nodes and 576 connections; it is retained as defensive recovery and has no dedicated test.

pub fn stage<const I: usize>(&self) -> &<T as StageAt<S, I>>::Processor
where T: StageAt<S, I>,

Borrow a concrete stage. This borrow excludes all rendering and mutation.

pub fn stage_mut_stopped<const I: usize>( &mut self, ) -> Result<&mut <T as StageAt<S, I>>::Processor, PrepareError>
where T: StageAt<S, I>,

Deactivate CONTROL first; successful reprepare is required after mutation. Refuses (AudioSessionActive) while a manual or forgotten audio owner is live.

pub fn set_bypassed<const I: usize>(&mut self, value: bool)
where T: StageAt<S, I>,

pub fn is_bypassed<const I: usize>(&self) -> bool
where T: StageAt<S, I>,

pub fn prepare(&mut self, c: ProcessConfig) -> Result<(), PrepareError>

Refuses (AudioSessionActive) while a manual or forgotten audio owner is live.

pub fn first_fault(&self) -> Option<GraphStatus>

Original first executed-node fault, until reset/reprepare/deactivation.

pub fn process(&mut self, b: &mut ProcessBlock<'_, '_, '_, S>) -> GraphStatus

pub fn reset(&mut self)

pub fn try_reset(&mut self) -> Result<(), GraphStatus>

Forward refusal through the canonical Graph and retain its node identity.

pub fn deactivate(&mut self)

CONTROL only. Panics (canonical Graph assertion) while a manual or forgotten audio owner is live; it does not refuse. A caught panic leaves the chain prepared with the owner live (nothing is changed before the assertion), so the owner thread can still call Processor::stop_audio.

pub fn latency_samples(&self) -> u32

pub fn tail(&self) -> Tail

pub fn start_audio( &mut self, ) -> Result<TypedChainAudioSession<'_, S, T>, GraphStatus>

pub fn into_stages(self) -> T

CONTROL only. Drop graph/wrappers first, then recover the original tuple. The Graph is only dropped: nothing calls stop_audio here. With a manual or forgotten audio owner live this panics inside the Graph drop, each stage is dropped once during the unwind without stop_audio/deactivate, and the original tuple is not returned. Stop the owner on its thread first.

Trait Implementations§

§

impl<S: GraphSample, T: StageTuple<S>> Processor<S> for TypedChain<S, T>

§

fn start_audio(&mut self) -> Result<(), ProcessError>

Manual hook: the caller must call stop_audio on this thread before transfer, deactivate, into_stages or drop (see the type docs). Failure maps Fault { error, .. } to that error (a retry on a faulted graph is NotPrepared); the original first fault remains in first_fault().

§

fn stop_audio(&mut self)

Must run on the thread that started the manual owner; a different thread panics through the canonical assertion and leaves the owner live.

§

fn deactivate(&mut self)

Panics while a manual audio owner is live (see TypedChain::deactivate).

§

fn prepare(&mut self, c: ProcessConfig) -> Result<(), PrepareError>

§

fn process(&mut self, b: &mut ProcessBlock<'_, '_, '_, S>) -> ProcessStatus

§

fn reset(&mut self)

§

fn try_reset(&mut self) -> Result<(), ProcessError>

Attempt history reset without allocating or changing configuration. Existing processors delegate to their successful legacy reset by default. A refusal may follow earlier reset work; consumers must remain faulted.
§

fn latency_samples(&self) -> u32

Prepared algorithmic latency in samples. Changes are advertised by adapters using their format’s restart/latency protocol outside the audio callback.
§

fn tail(&self) -> Tail

Decay policy after input stops. Adapters must map this to the host protocol.

Auto Trait Implementations§

§

impl<S, T> !RefUnwindSafe for TypedChain<S, T>

§

impl<S, T> !Sync for TypedChain<S, T>

§

impl<S, T> !UnwindSafe for TypedChain<S, T>

§

impl<S, T> Freeze for TypedChain<S, T>
where <T as Tuple<S>>::Storage: Freeze,

§

impl<S, T> Send for TypedChain<S, T>
where <T as Tuple<S>>::Storage: Send,

§

impl<S, T> Unpin for TypedChain<S, T>
where <T as Tuple<S>>::Storage: Unpin, S: Unpin,

§

impl<S, T> UnsafeUnpin for TypedChain<S, T>
where <T as Tuple<S>>::Storage: UnsafeUnpin,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.