Skip to main content

Workspace

Struct Workspace 

Source
pub struct Workspace<CS: StateStoreBackend, A: AgentBackend, X: ActionBackend = NoActions, C: ConditionBackend = NoConditions, T: StateTyping = JsonState, H: LifecycleHooks = NoHooks, E: ChildExecutor = InlineExecutor> { /* private fields */ }
Expand description

An application workspace handle.

A typed projection into the owning App generation. Dropping it does not delete or close lower workspaces. Replacement uses a complete configuration and a revision fence; successful deletion revokes this projection. Retained terminal history can still be opened through its workflow after workspace deletion.

§Workspace lifecycle

Replacement and deletion use the latest observed revision as their fence. This example uses real process-local storage without configuring Agents or workflows.

use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use storage_kit::{StateStore, state::config::{LanceStateStoreConfig, StateStoreConfig}};
use std::{num::NonZeroUsize, time::Duration};
let store = StateStore::connect(
    StateStoreConfig::lance(LanceStateStoreConfig::memory()),
).await?;
let mut app = App::open(AppConfig::<_, Agent>::new(store, Vec::new(), Vec::new())).await?;
let outcome = async {
    let root = std::env::current_dir()?;
    let mut workspace = app.create_workspace(WorkspaceConfig {
        name: Some("draft".into()), root: root.clone(),
    }).await?;
    let before = workspace.snapshot().await?;
    let reopened = app.workspace(workspace.id().clone()).await?;
    assert_eq!(reopened.snapshot().await?.revision, before.revision);
    let updated = workspace.replace(before.revision, WorkspaceConfig {
        name: Some("reviewed".into()), root,
    }).await?;
    assert!(updated.revision > before.revision);
    assert_eq!(updated.config.name.as_deref(), Some("reviewed"));
    workspace.delete(updated.revision).await?;
    assert!(app.list_workspaces(None, NonZeroUsize::new(10).unwrap()).await?.is_empty());
    Ok::<(), Box<dyn std::error::Error>>(())
}.await;
let cleanup = app.shutdown(Shutdown::CancelAndDrain {
    timeout: Duration::from_secs(5),
}).await;
if let Err(error) = &cleanup { eprintln!("App shutdown: {error}"); }
outcome?;
cleanup?;

Implementations§

Source§

impl<CS: StateStoreBackend, A: AgentBackend, X: ActionBackend, C: ConditionBackend, T: StateTyping, H: LifecycleHooks, E: ChildExecutor> Workspace<CS, A, X, C, T, H, E>

Source

pub fn id(&self) -> &WorkspaceId

Returns this workspace’s stable identity.

See the workspace lifecycle.

Examples found in repository?
examples/performance.rs (line 462)
390    async fn seed(
391        &self,
392        app: &App<StateStore, Agent, WorkloadAction>,
393        actions: u64,
394        linear: bool,
395    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
396        let workspace = app
397            .create_workspace(WorkspaceConfig {
398                name: Some("performance consumer".into()),
399                root: self.root.join("workspace"),
400            })
401            .await?;
402        let workflow = workspace.workflow("performance".parse()?).await?;
403        let mut run = workflow.prepare(WorkflowState::default()).await?;
404        let mut execution = run
405            .execution(ExecutionOptions {
406                halt_after: if linear {
407                    Vec::new()
408                } else {
409                    vec!["count".into()]
410                },
411                ..ExecutionOptions::default()
412            })
413            .await?;
414        let mut samples = Vec::with_capacity(actions as usize);
415        let started = Instant::now();
416        for ordinal in 0..actions {
417            let step_started = Instant::now();
418            let event = execution.step().await?;
419            samples.push(step_started.elapsed());
420            let Some(ExecutionEvent::Committed { outcomes, .. }) = event else {
421                panic!("each serial workload step must commit one action");
422            };
423            assert_eq!(outcomes.len(), 1);
424            assert_eq!(outcomes[0].ordinal, ordinal);
425            assert_eq!(
426                outcomes[0].node,
427                if linear {
428                    format!("n{ordinal:04}")
429                } else {
430                    "count".into()
431                }
432            );
433            assert!(outcomes[0].result.is_empty());
434            if !linear && ordinal == 0 {
435                // One public halt and explicit resume add two control rows to
436                // Initial + three checkpoints per action + Terminal.
437                let halted = execution.finish().await?;
438                assert!(matches!(&halted.status, RunStatus::Halted { node, result }
439                    if node == "count" && result == &Some(Map::new())));
440                assert_eq!(halted.checkpoint, 4);
441                assert_eq!(
442                    halted.state.values(),
443                    &Map::from_iter([("count".into(), json!(1))])
444                );
445                assert_eq!(halted.last_action_ordinal, Some(0));
446                assert!(halted.outcomes == outcomes);
447                assert!(halted.interactions.is_empty());
448                execution = run.execution(ExecutionOptions::default()).await?;
449            }
450        }
451        let snapshot = execution.finish().await?;
452        Self::verify_snapshot(&snapshot, actions);
453        let execution_elapsed = started.elapsed();
454        let history = self
455            .history(&run, actions, linear, snapshot.checkpoint)
456            .await?;
457        if let Command::SeedHistory { rows } = self.command {
458            assert_eq!(history["rows"], rows);
459        }
460        Ok(
461            json!({"dataset":if linear {"linear"} else {"history"},"actions":actions,
462            "workspace":workspace.id().to_string(),"run":run.id().to_string(),
463            "occurrence":snapshot.occurrence,
464            "expected_state":snapshot.state.values(),"last_action_ordinal":snapshot.last_action_ordinal,
465            "terminal_checkpoint":snapshot.checkpoint,"retained_rows":history["rows"],
466            "execution_ns":execution_elapsed.as_nanos(),
467            "actions_per_second":actions as f64 / execution_elapsed.as_secs_f64(),
468            "step_latency":Self::samples(samples),"history":history}),
469        )
470    }
More examples
Hide additional examples
examples/history_and_recovery.rs (line 146)
63    async fn create_fork(
64        &self,
65        app: &App<StateStore, Agent>,
66    ) -> Result<(WorkspaceId, RunSelector, RunSelector), Box<dyn Error + Send + Sync>> {
67        let workspace = app
68            .create_workspace(WorkspaceConfig {
69                name: Some("history example".into()),
70                root: std::env::current_dir()?,
71            })
72            .await?;
73        let workflow = workspace.workflow("history-counter".parse()?).await?;
74        let mut source = workflow.prepare(WorkflowState::default()).await?;
75        let completed = source
76            .execution(ExecutionOptions::default())
77            .await?
78            .finish()
79            .await?;
80        if !matches!(completed.status, RunStatus::Succeeded)
81            || completed.state.values()["count"] != 2
82        {
83            return Err(
84                AppError::Integration("source did not complete both increments".into()).into(),
85            );
86        }
87
88        // An action ordinal selects the whole committed boundary containing it;
89        // it is independent of the checkpoint sequence and storage revision.
90        let first = source.checkpoint(CheckpointSelector::Action(0)).await?;
91        if !matches!(first.kind, CheckpointKind::Action)
92            || first.position.as_deref() != Some("first")
93            || first.state.values()["count"] != 1
94        {
95            return Err(
96                AppError::Integration("first action history is inconsistent".into()).into(),
97            );
98        }
99        let source_selector = RunSelector::Exact {
100            id: source.id().clone(),
101            occurrence: first.occurrence.clone(),
102        };
103        let mut fork = workflow
104            .restore(RestoreOptions {
105                source: source_selector.clone(),
106                checkpoint: CheckpointSelector::Action(0),
107                overrides: WorkflowState::new(Map::from_iter([("count".into(), json!(40))]))?,
108                position: ResumePosition::AfterCompleted,
109                fallback: None,
110            })
111            .await?;
112        let parked = fork.snapshot().await?;
113        if !matches!(parked.status, RunStatus::Paused)
114            || parked.checkpoint != 0
115            || parked.state.values()["count"] != 40
116            || !parked.outcomes.is_empty()
117        {
118            return Err(
119                AppError::Integration("restore did not create a parked clean copy".into()).into(),
120            );
121        }
122
123        source.delete(completed.checkpoint).await?;
124        if !matches!(source.snapshot().await, Err(AppError::NotFound(_))) {
125            return Err(
126                AppError::Integration("explicit source deletion did not finish".into()).into(),
127            );
128        }
129        // Deletion does not invalidate the copied state. AfterCompleted skips
130        // the first increment, so only the second changes the override: 40 -> 41.
131        let completed = fork
132            .execution(ExecutionOptions::default())
133            .await?
134            .finish()
135            .await?;
136        if !matches!(completed.status, RunStatus::Succeeded)
137            || completed.state.values()["count"] != 41
138            || completed.last_action_ordinal != Some(1)
139        {
140            return Err(
141                AppError::Integration("fork resumed from the wrong boundary".into()).into(),
142            );
143        }
144        println!("Source count: 2; copied count: 40; completed fork count: 41");
145        Ok((
146            workspace.id().clone(),
147            source_selector,
148            RunSelector::Exact {
149                id: fork.id().clone(),
150                occurrence: completed.occurrence,
151            },
152        ))
153    }
Source

pub async fn snapshot(&self) -> Result<WorkspaceSnapshot, AppError>

Loads the current workspace snapshot.

§Errors

Returns Closed after revocation or sealing, NotFound for absent coordination, Conflict during unresolved lifecycle progress, or Integration for unreadable committed evidence. A history-only workspace has no configuration snapshot.

See the workspace lifecycle.

Source

pub async fn replace( &self, expected_revision: u64, config: WorkspaceConfig, ) -> Result<WorkspaceSnapshot, AppError>

Atomically replaces the complete workspace configuration.

This is full replacement, including the name and root. Preflight checks all lower workspaces before fan-out. A partial lower failure retains the old App revision and durable reverse compensation; preflight never reserves a revision.

§Errors

Returns Conflict for a stale revision, a nonterminal run pinned to the current revision, or partial lower fan-out (even if compensation succeeds). Invalid configuration, capacity, revocation, storage/lower failures and bounded waits report InvalidInput, Busy, Closed, Integration, or Timeout.

See the workspace lifecycle.

Source

pub async fn workflow( &self, id: WorkflowId, ) -> Result<Workflow<CS, A, X, C, T, H, E>, AppError>

Opens a configured workflow in this workspace.

Selects the current configured definition for new work. A deleted workspace may retain a history-only workflow when exact terminal evidence still exists.

§Errors

Returns NotFound for an unavailable definition or retained scope, Closed for revoked admission, or Integration for inconsistent durable evidence.

See the local workflow.

Examples found in repository?
examples/performance.rs (line 402)
390    async fn seed(
391        &self,
392        app: &App<StateStore, Agent, WorkloadAction>,
393        actions: u64,
394        linear: bool,
395    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
396        let workspace = app
397            .create_workspace(WorkspaceConfig {
398                name: Some("performance consumer".into()),
399                root: self.root.join("workspace"),
400            })
401            .await?;
402        let workflow = workspace.workflow("performance".parse()?).await?;
403        let mut run = workflow.prepare(WorkflowState::default()).await?;
404        let mut execution = run
405            .execution(ExecutionOptions {
406                halt_after: if linear {
407                    Vec::new()
408                } else {
409                    vec!["count".into()]
410                },
411                ..ExecutionOptions::default()
412            })
413            .await?;
414        let mut samples = Vec::with_capacity(actions as usize);
415        let started = Instant::now();
416        for ordinal in 0..actions {
417            let step_started = Instant::now();
418            let event = execution.step().await?;
419            samples.push(step_started.elapsed());
420            let Some(ExecutionEvent::Committed { outcomes, .. }) = event else {
421                panic!("each serial workload step must commit one action");
422            };
423            assert_eq!(outcomes.len(), 1);
424            assert_eq!(outcomes[0].ordinal, ordinal);
425            assert_eq!(
426                outcomes[0].node,
427                if linear {
428                    format!("n{ordinal:04}")
429                } else {
430                    "count".into()
431                }
432            );
433            assert!(outcomes[0].result.is_empty());
434            if !linear && ordinal == 0 {
435                // One public halt and explicit resume add two control rows to
436                // Initial + three checkpoints per action + Terminal.
437                let halted = execution.finish().await?;
438                assert!(matches!(&halted.status, RunStatus::Halted { node, result }
439                    if node == "count" && result == &Some(Map::new())));
440                assert_eq!(halted.checkpoint, 4);
441                assert_eq!(
442                    halted.state.values(),
443                    &Map::from_iter([("count".into(), json!(1))])
444                );
445                assert_eq!(halted.last_action_ordinal, Some(0));
446                assert!(halted.outcomes == outcomes);
447                assert!(halted.interactions.is_empty());
448                execution = run.execution(ExecutionOptions::default()).await?;
449            }
450        }
451        let snapshot = execution.finish().await?;
452        Self::verify_snapshot(&snapshot, actions);
453        let execution_elapsed = started.elapsed();
454        let history = self
455            .history(&run, actions, linear, snapshot.checkpoint)
456            .await?;
457        if let Command::SeedHistory { rows } = self.command {
458            assert_eq!(history["rows"], rows);
459        }
460        Ok(
461            json!({"dataset":if linear {"linear"} else {"history"},"actions":actions,
462            "workspace":workspace.id().to_string(),"run":run.id().to_string(),
463            "occurrence":snapshot.occurrence,
464            "expected_state":snapshot.state.values(),"last_action_ordinal":snapshot.last_action_ordinal,
465            "terminal_checkpoint":snapshot.checkpoint,"retained_rows":history["rows"],
466            "execution_ns":execution_elapsed.as_nanos(),
467            "actions_per_second":actions as f64 / execution_elapsed.as_secs_f64(),
468            "step_latency":Self::samples(samples),"history":history}),
469        )
470    }
471
472    async fn reopen(
473        &self,
474        app: &App<StateStore, Agent, WorkloadAction>,
475        manifest: &Value,
476        actions: u64,
477        open_only: bool,
478    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
479        let started = Instant::now();
480        let workspace: WorkspaceId = manifest["workspace"]
481            .as_str()
482            .ok_or("missing workspace ID")?
483            .parse()?;
484        let run_id: RunId = manifest["run"].as_str().ok_or("missing run ID")?.parse()?;
485        let occurrence = manifest["occurrence"]
486            .as_str()
487            .ok_or("missing run occurrence")?
488            .to_owned();
489        let workspace = app.workspace(workspace).await?;
490        let workflow = workspace.workflow("performance".parse()?).await?;
491        let run = workflow
492            .open_run(RunSelector::Exact {
493                id: run_id,
494                occurrence: occurrence.clone(),
495            })
496            .await?;
497        let snapshot = run.snapshot().await?;
498        Self::verify_snapshot(&snapshot, actions);
499        assert_eq!(snapshot.occurrence, occurrence);
500        assert_eq!(json!(snapshot.checkpoint), manifest["terminal_checkpoint"]);
501        assert_eq!(json!(snapshot.state.values()), manifest["expected_state"]);
502        assert_eq!(
503            json!(snapshot.last_action_ordinal),
504            manifest["last_action_ordinal"]
505        );
506        let lookup = started.elapsed();
507        if open_only {
508            return Ok(
509                json!({"dataset":"history","actions":actions,"mode":"open-only",
510                "lookup_and_snapshot_ns":lookup.as_nanos(),
511                "seed_retained_rows":manifest["retained_rows"],"observed_history_rows":null}),
512            );
513        }
514        let history = self
515            .history(&run, actions, false, snapshot.checkpoint)
516            .await?;
517        assert_eq!(history["rows"], manifest["retained_rows"]);
518        Ok(
519            json!({"dataset":"history","actions":actions,"mode":"full-history",
520            "lookup_and_snapshot_ns":lookup.as_nanos(),"history":history}),
521        )
522    }
523
524    fn definitions(&self, actions: u64) -> Result<(Vec<WorkflowDefinition>, usize), AppError> {
525        if matches!(
526            self.command,
527            Command::Linear | Command::SeedHistory { .. } | Command::ReopenHistory { .. }
528        ) {
529            let (definition, bytes) =
530                Self::definition(matches!(self.command, Command::Linear), actions)?;
531            return Ok((vec![definition], bytes));
532        }
533        let leaf = json!({
534            "schema":"app-kit.workflow/v2","id":"performance-leaf","revision":"r1",
535            "state":{"value":0,"result":0},"required":["value","result"],
536            "reducers":{"value":"reject_concurrent","result":"reject_concurrent"},
537            "entry":"work","nodes":[{"id":"work","deadline_ms":NODE_DEADLINE_MS,
538                "step":{"kind":"action","action":"performance-action","revision":"r1"}}],"routes":{}
539        });
540        let documents = match self.command {
541            Command::Ready => {
542                let mut nodes = vec![json!({"id":"fork","step":{"kind":"state","mutations":[]}})];
543                let mut branches = Vec::new();
544                for index in 0..32 {
545                    let node = format!("n{index:02}");
546                    nodes.push(json!({"id":node,"deadline_ms":NODE_DEADLINE_MS,
547                        "step":{"kind":"action","action":"performance-action","revision":"r1"}}));
548                    branches.push(json!({"target":{"kind":"node","id":node}}));
549                }
550                vec![json!({
551                    "schema":"app-kit.workflow/v2","id":"performance","revision":"r1",
552                    "state":{"value":0,"result":0},"required":["value","result"],
553                    "reducers":{"value":"reject_concurrent","result":"collect"},
554                    "entry":"fork","nodes":nodes,
555                    "routes":{"fork":{"mode":"broadcast","branches":branches}}
556                })]
557            }
558            Command::Map | Command::NestedCancel => {
559                let nested = matches!(self.command, Command::NestedCancel);
560                let items = if nested { 2 } else { 4_096 };
561                let mut documents = vec![
562                    json!({
563                        "schema":"app-kit.workflow/v2","id":"performance","revision":"r1",
564                        "state":{"value":0,"result":0},"required":["value","result"],
565                        "reducers":{"value":"reject_concurrent","result":"sum_integer"},
566                        "entry":"map","nodes":[{"id":"map","deadline_ms":if nested {NODE_DEADLINE_MS} else {WORKLOAD_BUDGET.as_millis() as u64},
567                            "step":{"kind":"map","workflow":if nested {"performance-mid"} else {"performance-leaf"},
568                            "items":{"kind":"literal","value":(0..items).collect::<Vec<_>>()},
569                            "input_key":"value","max_parallel":if nested {2} else {8},
570                            "reductions":[{"source":"result","target":"result","reducer":"sum_integer"}]}}],"routes":{}
571                    }),
572                    leaf,
573                ];
574                if nested {
575                    documents.push(json!({
576                        "schema":"app-kit.workflow/v2","id":"performance-mid","revision":"r1",
577                        "state":{"value":0,"result":0},"required":["value","result"],
578                        "reducers":{"value":"reject_concurrent","result":"sum_integer"},
579                        "entry":"map","nodes":[{"id":"map","deadline_ms":NODE_DEADLINE_MS,
580                            "step":{"kind":"map","workflow":"performance-leaf",
581                            "items":{"kind":"literal","value":(0..8).collect::<Vec<_>>()},
582                            "input_key":"value","max_parallel":8,
583                            "reductions":[{"source":"result","target":"result","reducer":"sum_integer"}]}}],"routes":{}
584                    }));
585                }
586                documents
587            }
588            Command::Repeated | Command::DelayedObserver => vec![leaf],
589            Command::Linear | Command::SeedHistory { .. } | Command::ReopenHistory { .. } => {
590                unreachable!()
591            }
592        };
593        let mut bytes = 0;
594        let mut definitions = Vec::with_capacity(documents.len());
595        for document in documents {
596            let source = document.to_string();
597            assert!(source.len() <= 1_048_576);
598            bytes += source.len();
599            definitions.push(WorkflowDefinition::parse(&source)?);
600        }
601        Ok((definitions, bytes))
602    }
603
604    async fn ready(
605        &self,
606        app: &App<StateStore, Agent, WorkloadAction>,
607        probe: &WorkloadProbe,
608    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
609        let workspace = app
610            .create_workspace(WorkspaceConfig {
611                name: None,
612                root: self.root.join("workspace"),
613            })
614            .await?;
615        let workflow = workspace.workflow("performance".parse()?).await?;
616        let mut waves = Vec::with_capacity(32);
617        let mut releases = Vec::with_capacity(32 * 31);
618        let mut barriers = Vec::with_capacity(32);
619        let started = Instant::now();
620        for permutation in 0..32 {
621            probe.assert_idle();
622            let mut run = workflow.prepare(WorkflowState::default()).await?;
623            let observer = workflow
624                .open_run(RunSelector::Latest(run.id().clone()))
625                .await?;
626            let mut execution = run.execution(ExecutionOptions::default()).await?;
627            let Some(ExecutionEvent::Committed { outcomes, .. }) = execution.step().await? else {
628                panic!("the native fork must commit before the ready wave");
629            };
630            assert_eq!(outcomes.len(), 1);
631            assert_eq!(
632                (outcomes[0].node.as_str(), outcomes[0].ordinal),
633                ("fork", 0)
634            );
635            let wave = Instant::now();
636            let mut finish = Box::pin(execution.finish());
637            tokio::select! {
638                _ = probe.wait_for(&probe.constructed, (permutation + 1) * 32) => {}
639                result = &mut finish => panic!("gated ready wave finished before admission: {}", result.is_ok()),
640            }
641            assert_eq!(probe.active.load(Ordering::SeqCst), 32);
642            let order = (0..32)
643                .map(|offset| (permutation + 31 - offset) % 32)
644                .collect::<Vec<_>>();
645            for (released, index) in order.iter().take(31).enumerate() {
646                let releasing = Instant::now();
647                probe.release(*index);
648                tokio::select! {
649                    _ = probe.wait_for(&probe.completed, permutation * 32 + released + 1) => {}
650                    result = &mut finish => panic!("a partial ready wave committed: {}", result.is_ok()),
651                }
652                releases.push(releasing.elapsed());
653                let visible = observer.snapshot().await?;
654                assert_eq!(
655                    visible.state.values()["result"],
656                    0,
657                    "staged siblings cannot expose a partial barrier"
658                );
659                assert_eq!(visible.last_action_ordinal, Some(0));
660            }
661            let barrier = Instant::now();
662            probe.release(order[31]);
663            let snapshot = finish.await?;
664            barriers.push(barrier.elapsed());
665            waves.push(wave.elapsed());
666            assert!(matches!(snapshot.status, RunStatus::Succeeded));
667            assert!(snapshot.interactions.is_empty());
668            assert_eq!(
669                snapshot.state.values()["result"],
670                json!((1..=32).collect::<Vec<_>>())
671            );
672            assert_eq!(snapshot.last_action_ordinal, Some(32));
673            assert_eq!(snapshot.outcomes.len(), 32);
674            for (index, outcome) in snapshot.outcomes.iter().enumerate() {
675                assert_eq!(outcome.node, format!("n{index:02}"));
676                assert_eq!(outcome.ordinal, index as u64 + 1);
677                assert_eq!(
678                    outcome.result,
679                    Map::from_iter([("value".into(), json!(index + 1))])
680                );
681            }
682            assert_eq!(std::mem::take(&mut *probe.order.lock().unwrap()), order);
683            assert_eq!(
684                probe.completed.load(Ordering::SeqCst),
685                (permutation + 1) * 32
686            );
687            probe.assert_idle();
688        }
689        assert_eq!(probe.peak.load(Ordering::SeqCst), 32);
690        let elapsed = started.elapsed();
691        Ok(
692            json!({"dataset":"ready32","permutations":32,"ready_actions_per_wave":32,
693            "caller_action_commits":1024,"native_fork_commits":32,
694            "execution_ns":elapsed.as_nanos(),"caller_actions_per_second":1024.0 / elapsed.as_secs_f64(),
695            "wave_latency_including_snapshot_probes":Self::samples(waves),
696            "release_to_source_completion_latency":Self::samples(releases),
697            "last_release_to_committed_barrier_latency":Self::samples(barriers)}),
698        )
699    }
700
701    async fn mapped(
702        &self,
703        app: &App<StateStore, Agent, WorkloadAction>,
704        probe: &WorkloadProbe,
705    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
706        let workspace = app
707            .create_workspace(WorkspaceConfig {
708                name: None,
709                root: self.root.join("workspace"),
710            })
711            .await?;
712        let workflow = workspace.workflow("performance".parse()?).await?;
713        let mut run = workflow.prepare(WorkflowState::default()).await?;
714        let observer = workflow
715            .open_run(RunSelector::Latest(run.id().clone()))
716            .await?;
717        let started = Instant::now();
718        let mut finish = Box::pin(run.execution(ExecutionOptions::default()).await?.finish());
719        tokio::select! {
720            _ = probe.wait_for(&probe.constructed, 8) => {}
721            result = &mut finish => panic!("map finished before its first eight blocked sources: {}", result.is_ok()),
722        }
723        assert_eq!(probe.active.load(Ordering::SeqCst), 8);
724        assert_eq!(probe.constructed.load(Ordering::SeqCst), 8);
725        let unchanged = observer.snapshot().await?;
726        assert_eq!(unchanged.state.values()["result"], 0);
727        assert!(unchanged.last_action_ordinal.is_none());
728        probe.release_all();
729        let snapshot = finish.await?;
730        let elapsed = started.elapsed();
731        assert!(matches!(snapshot.status, RunStatus::Succeeded));
732        assert!(snapshot.interactions.is_empty());
733        assert_eq!(snapshot.state.values()["result"], 4_096_u64 * 4_097 / 2);
734        assert_eq!(snapshot.last_action_ordinal, Some(0));
735        assert_eq!(snapshot.outcomes.len(), 1);
736        assert_eq!(snapshot.outcomes[0].node, "map");
737        assert_eq!(probe.constructed.load(Ordering::SeqCst), 4_096);
738        assert_eq!(probe.completed.load(Ordering::SeqCst), 4_096);
739        assert_eq!(probe.peak.load(Ordering::SeqCst), 8);
740        probe.assert_idle();
741        let child = workspace.workflow("performance-leaf".parse()?).await?;
742        let mut cursor = None;
743        let mut values = BTreeSet::new();
744        let verifying = Instant::now();
745        loop {
746            let page = child
747                .list_runs(cursor, NonZeroUsize::new(PAGE_SIZE).unwrap())
748                .await?;
749            assert!(page.len() <= PAGE_SIZE);
750            if page.is_empty() {
751                break;
752            }
753            for row in &page {
754                assert!(matches!(row.status, RunStatus::Succeeded));
755                let value = row.state.values()["value"].as_u64().unwrap();
756                assert!(
757                    value < 4_096 && values.insert(value),
758                    "every mapped input has exactly one retained child"
759                );
760                assert_eq!(row.state.values()["result"], value + 1);
761                assert_eq!(row.last_action_ordinal, Some(0));
762                assert_eq!(row.outcomes.len(), 1);
763                assert_eq!(row.outcomes[0].node, "work");
764            }
765            let last = page.last().unwrap();
766            cursor = Some(RunSelector::Exact {
767                id: last.id.clone(),
768                occurrence: last.occurrence.clone(),
769            });
770            assert!(values.len() <= 4_096);
771        }
772        assert_eq!(values.len(), 4_096);
773        Ok(json!({"dataset":"map4096","items":4096,"max_parallel":8,
774            "parent_node_deadline_ms":WORKLOAD_BUDGET.as_millis(),
775            "execution_ns":elapsed.as_nanos(),"child_actions_per_second":4096.0 / elapsed.as_secs_f64(),
776            "map_completion_latency":Self::samples(vec![elapsed]),
777            "child_inventory_verification_ns":verifying.elapsed().as_nanos(),"verified_children":values.len()}))
778    }
779
780    async fn repeated(
781        &self,
782        app: &App<StateStore, Agent, WorkloadAction>,
783        probe: &WorkloadProbe,
784    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
785        let workspace = app
786            .create_workspace(WorkspaceConfig {
787                name: None,
788                root: self.root.join("workspace"),
789            })
790            .await?;
791        let workflow = workspace.workflow("performance-leaf".parse()?).await?;
792        let started = Instant::now();
793        // Admit one run at a time, then directly poll at most 16 original
794        // executions together. No consumer task is spawned or detached.
795        let mut runs = std::pin::pin!(
796            stream::iter(0..100_u64)
797                .then(|value| {
798                    let workflow = &workflow;
799                    async move {
800                        let started = Instant::now();
801                        let run = workflow
802                            .prepare(WorkflowState::new(Map::from_iter([(
803                                "value".into(),
804                                json!(value),
805                            )]))?)
806                            .await?;
807                        Ok::<_, AppError>((value, run, started))
808                    }
809                })
810                .map(|prepared| async move {
811                    let (value, mut run, started) = prepared?;
812                    let snapshot = run
813                        .execution(ExecutionOptions::default())
814                        .await?
815                        .finish()
816                        .await?;
817                    assert!(matches!(snapshot.status, RunStatus::Succeeded));
818                    assert!(snapshot.interactions.is_empty());
819                    assert_eq!(snapshot.state.values()["value"], value);
820                    assert_eq!(snapshot.state.values()["result"], value + 1);
821                    assert_eq!(snapshot.last_action_ordinal, Some(0));
822                    assert_eq!(snapshot.outcomes.len(), 1);
823                    Ok::<_, AppError>((run.id().clone(), started.elapsed()))
824                })
825                .buffer_unordered(16)
826        );
827        tokio::select! {
828            _ = probe.wait_for(&probe.constructed, 16) => {}
829            result = runs.next() => panic!(
830                "run finished before the first 16 blocked sources: {:?}",
831                result.map(|result| result.map(|_| ())),
832            ),
833        }
834        assert_eq!(probe.active.load(Ordering::SeqCst), 16);
835        assert_eq!(probe.constructed.load(Ordering::SeqCst), 16);
836        probe.release_all();
837        let mut ids = BTreeSet::new();
838        let mut samples = Vec::with_capacity(100);
839        while let Some(result) = runs.next().await {
840            let (id, elapsed) = result?;
841            assert!(ids.insert(id));
842            samples.push(elapsed);
843        }
844        assert_eq!(ids.len(), 100);
845        assert_eq!(probe.constructed.load(Ordering::SeqCst), 100);
846        assert_eq!(probe.completed.load(Ordering::SeqCst), 100);
847        assert_eq!(probe.peak.load(Ordering::SeqCst), 16);
848        probe.assert_idle();
849        let rows = workflow
850            .list_runs(None, NonZeroUsize::new(128).unwrap())
851            .await?;
852        assert_eq!(rows.len(), 100);
853        assert_eq!(
854            rows.iter()
855                .map(|row| row.id.clone())
856                .collect::<BTreeSet<_>>(),
857            ids
858        );
859        assert!(
860            rows.iter()
861                .all(|row| matches!(row.status, RunStatus::Succeeded))
862        );
863        let elapsed = started.elapsed();
864        Ok(
865            json!({"dataset":"repeated100","runs":100,"caller_in_flight_limit":16,"admission":"sequential",
866            "production_active_limit":"unchanged; this measures only the caller's 16-journey envelope",
867            "execution_ns":elapsed.as_nanos(),"runs_per_second":100.0 / elapsed.as_secs_f64(),
868            "run_latency_including_admission":Self::samples(samples),"indefinite_stability_proof":false}),
869        )
870    }
871
872    async fn nested_cancel(
873        &self,
874        app: &App<StateStore, Agent, WorkloadAction>,
875        probe: &WorkloadProbe,
876    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
877        let workspace = app
878            .create_workspace(WorkspaceConfig {
879                name: None,
880                root: self.root.join("workspace"),
881            })
882            .await?;
883        let workflow = workspace.workflow("performance".parse()?).await?;
884        let run = workflow.start(ExecutionOptions::default()).await?;
885        tokio::select! {
886            _ = probe.wait_for(&probe.constructed, 16) => {}
887            result = run.wait() => panic!("nested run ended before its held leaf sources: {}", result.is_ok()),
888        }
889        assert_eq!(probe.active.load(Ordering::SeqCst), 16);
890        let cancelling = Instant::now();
891        let snapshot = tokio::time::timeout(Duration::from_secs(30), async {
892            loop {
893                let before = run.snapshot().await?;
894                assert_eq!(before.state.values()["result"], 0);
895                assert!(before.outcomes.is_empty() && before.last_action_ordinal.is_none());
896                match run.cancel(before.checkpoint).await {
897                    Ok(_) => break,
898                    Err(AppError::Conflict(_)) => tokio::task::yield_now().await,
899                    Err(error) => return Err(error),
900                }
901            }
902            run.wait().await
903        })
904        .await
905        .map_err(|_| {
906            AppError::Timeout("nested cancellation exceeded its declared 30-second grace".into())
907        })??;
908        let elapsed = cancelling.elapsed();
909        assert!(matches!(snapshot.status, RunStatus::Cancelled));
910        assert!(snapshot.interactions.is_empty() && snapshot.outcomes.is_empty());
911        assert!(snapshot.last_action_ordinal.is_none());
912        assert_eq!(snapshot.state.values()["result"], 0);
913        assert_eq!(probe.constructed.load(Ordering::SeqCst), 16);
914        assert_eq!(probe.completed.load(Ordering::SeqCst), 0);
915        probe.assert_idle();
916        for (id, count) in [
917            ("performance", 1),
918            ("performance-mid", 2),
919            ("performance-leaf", 16),
920        ] {
921            let child = workspace.workflow(id.parse()?).await?;
922            let rows = child
923                .list_runs(None, NonZeroUsize::new(128).unwrap())
924                .await?;
925            assert_eq!(rows.len(), count);
926            for row in rows {
927                assert!(matches!(row.status, RunStatus::Cancelled));
928                assert!(row.outcomes.is_empty() && row.last_action_ordinal.is_none());
929                assert_eq!(row.state.values()["result"], 0);
930            }
931        }
932        Ok(
933            json!({"dataset":"nested-cancel","depth":2,"intermediate_children":2,"leaf_children":16,
934            "cooperative_cancel_grace_ms":30_000,"cancellation_latency":Self::samples(vec![elapsed]),
935            "source_replays":0,"caller_sources_dropped":16,"agent_unknown_replay":"not applicable: no Agent attempt"}),
936        )
937    }
938
939    async fn delayed_observer(
940        &self,
941        app: &App<StateStore, Agent, WorkloadAction>,
942        probe: &WorkloadProbe,
943    ) -> Result<Value, Box<dyn Error + Send + Sync>> {
944        let workspace = app
945            .create_workspace(WorkspaceConfig {
946                name: None,
947                root: self.root.join("workspace"),
948            })
949            .await?;
950        let workflow = workspace.workflow("performance-leaf".parse()?).await?;
951        let run = workflow.start(ExecutionOptions::default()).await?;
952        let observer = workflow
953            .open_run(RunSelector::Latest(run.id().clone()))
954            .await?;
955        // This public observation is deliberately never polled while the source
956        // produces its 256 partials and commits. It owns no execution work.
957        let delayed = observer.wait();
958        let produced = run.wait().await?;
959        assert!(matches!(produced.status, RunStatus::Succeeded));
960        assert_eq!(probe.completed.load(Ordering::SeqCst), 1);
961        probe.assert_idle();
962        tokio::time::sleep(Duration::from_secs(2)).await;
963        let observing = Instant::now();
964        let snapshot = delayed.await?;
965        let elapsed = observing.elapsed();
966        assert!(matches!(snapshot.status, RunStatus::Succeeded));
967        assert_eq!(snapshot.checkpoint, produced.checkpoint);
968        assert_eq!(snapshot.state.values()["result"], 1);
969        assert_eq!(snapshot.last_action_ordinal, Some(0));
970        assert_eq!(snapshot.outcomes.len(), 1);
971        assert_eq!(
972            snapshot.outcomes[0].result,
973            Map::from_iter([("value".into(), json!(1))])
974        );
975        assert_eq!(probe.constructed.load(Ordering::SeqCst), 1);
976        assert_eq!(probe.partials.load(Ordering::SeqCst), 256);
977        probe.assert_idle();
978        let terminal = run.snapshot().await?;
979        assert_eq!(terminal.checkpoint, snapshot.checkpoint);
980        assert_eq!(terminal.state, snapshot.state);
981        let mut cursor = None;
982        let mut actions = 0;
983        let mut rows = 0;
984        loop {
985            let page = run
986                .history(cursor, NonZeroUsize::new(PAGE_SIZE).unwrap())
987                .await?;
988            for row in &page.checkpoints {
989                rows += 1;
990                assert!(rows <= 32);
991                if matches!(row.kind, CheckpointKind::Action) {
992                    actions += 1;
993                    assert_eq!(row.action_ordinal, Some(0));
994                    assert_eq!(row.outcomes.len(), 1);
995                }
996            }
997            cursor = page.next;
998            if cursor.is_none() {
999                break;
1000            }
1001        }
1002        assert_eq!(
1003            actions, 1,
1004            "partials cannot become extra durable action commits"
1005        );
1006        Ok(
1007            json!({"dataset":"delayed-observer","unobserved_partial_events":256,"delay_after_terminal_confirmation_ms":2_000,
1008            "observation_latency":Self::samples(vec![elapsed]),"retained_rows":rows,
1009            "memory_scope":"external process RSS; this consumer retains no partial payloads"}),
1010        )
1011    }
More examples
Hide additional examples
examples/history_and_recovery.rs (line 73)
63    async fn create_fork(
64        &self,
65        app: &App<StateStore, Agent>,
66    ) -> Result<(WorkspaceId, RunSelector, RunSelector), Box<dyn Error + Send + Sync>> {
67        let workspace = app
68            .create_workspace(WorkspaceConfig {
69                name: Some("history example".into()),
70                root: std::env::current_dir()?,
71            })
72            .await?;
73        let workflow = workspace.workflow("history-counter".parse()?).await?;
74        let mut source = workflow.prepare(WorkflowState::default()).await?;
75        let completed = source
76            .execution(ExecutionOptions::default())
77            .await?
78            .finish()
79            .await?;
80        if !matches!(completed.status, RunStatus::Succeeded)
81            || completed.state.values()["count"] != 2
82        {
83            return Err(
84                AppError::Integration("source did not complete both increments".into()).into(),
85            );
86        }
87
88        // An action ordinal selects the whole committed boundary containing it;
89        // it is independent of the checkpoint sequence and storage revision.
90        let first = source.checkpoint(CheckpointSelector::Action(0)).await?;
91        if !matches!(first.kind, CheckpointKind::Action)
92            || first.position.as_deref() != Some("first")
93            || first.state.values()["count"] != 1
94        {
95            return Err(
96                AppError::Integration("first action history is inconsistent".into()).into(),
97            );
98        }
99        let source_selector = RunSelector::Exact {
100            id: source.id().clone(),
101            occurrence: first.occurrence.clone(),
102        };
103        let mut fork = workflow
104            .restore(RestoreOptions {
105                source: source_selector.clone(),
106                checkpoint: CheckpointSelector::Action(0),
107                overrides: WorkflowState::new(Map::from_iter([("count".into(), json!(40))]))?,
108                position: ResumePosition::AfterCompleted,
109                fallback: None,
110            })
111            .await?;
112        let parked = fork.snapshot().await?;
113        if !matches!(parked.status, RunStatus::Paused)
114            || parked.checkpoint != 0
115            || parked.state.values()["count"] != 40
116            || !parked.outcomes.is_empty()
117        {
118            return Err(
119                AppError::Integration("restore did not create a parked clean copy".into()).into(),
120            );
121        }
122
123        source.delete(completed.checkpoint).await?;
124        if !matches!(source.snapshot().await, Err(AppError::NotFound(_))) {
125            return Err(
126                AppError::Integration("explicit source deletion did not finish".into()).into(),
127            );
128        }
129        // Deletion does not invalidate the copied state. AfterCompleted skips
130        // the first increment, so only the second changes the override: 40 -> 41.
131        let completed = fork
132            .execution(ExecutionOptions::default())
133            .await?
134            .finish()
135            .await?;
136        if !matches!(completed.status, RunStatus::Succeeded)
137            || completed.state.values()["count"] != 41
138            || completed.last_action_ordinal != Some(1)
139        {
140            return Err(
141                AppError::Integration("fork resumed from the wrong boundary".into()).into(),
142            );
143        }
144        println!("Source count: 2; copied count: 40; completed fork count: 41");
145        Ok((
146            workspace.id().clone(),
147            source_selector,
148            RunSelector::Exact {
149                id: fork.id().clone(),
150                occurrence: completed.occurrence,
151            },
152        ))
153    }
154
155    async fn read_reopened(
156        &self,
157        app: &App<StateStore, Agent>,
158        workspace: WorkspaceId,
159        source: RunSelector,
160        fork: RunSelector,
161    ) -> Result<(), AppError> {
162        let workspace = app.workspace(workspace).await?;
163        let workflow = workspace.workflow("history-counter".parse()?).await?;
164        let fork = workflow.open_run(fork).await?;
165        let committed = fork.checkpoint(CheckpointSelector::Action(1)).await?;
166        let lineage = committed
167            .lineage
168            .as_ref()
169            .ok_or_else(|| AppError::Integration("reopened fork lost its source lineage".into()))?;
170        if committed.state.values()["count"] != 41
171            || !matches!(&source, RunSelector::Exact { id, occurrence }
172                if &lineage.source == id && &lineage.source_occurrence == occurrence)
173            || lineage.action_ordinal != Some(0)
174        {
175            return Err(AppError::Integration(
176                "reopened fork history changed".into(),
177            ));
178        }
179        println!(
180            "Reopened fork {} at count 41; source lineage remains readable",
181            fork.id()
182        );
183        Ok(())
184    }
examples/actions_and_inputs.rs (line 51)
23    async fn run() -> Result<(), Box<dyn Error + Send + Sync>> {
24        let definition = WorkflowDefinition::parse(
25            &json!({
26                "schema":"app-kit.workflow/v2", "id":"invoice", "revision":"r1",
27                "state":{"unit_price":7,"total":0}, "required":["unit_price","total"],
28                "reducers":{"unit_price":"reject_concurrent","total":"reject_concurrent"},
29                "entry":"calculate",
30                "nodes":[{"id":"calculate","step":{
31                    "kind":"action","action":"invoice","revision":"r1","project_result":false
32                }}], "routes":{}
33            })
34            .to_string(),
35        )?;
36        let store =
37            StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
38        // Native caller actions need no Agent value or provider service.
39        let mut app = App::open(
40            AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition])
41                .with_actions(vec![InvoiceAction::new()]),
42        )
43        .await?;
44        let observed = tokio::time::timeout(Duration::from_secs(15), async {
45            let workspace = app
46                .create_workspace(WorkspaceConfig {
47                    name: Some("invoice example".into()),
48                    root: PathBuf::from(env!("CARGO_MANIFEST_DIR")),
49                })
50                .await?;
51            let workflow = workspace.workflow("invoice".parse()?).await?;
52            let mut run = workflow.prepare(WorkflowState::default()).await?;
53            let mut execution = run
54                .execution(ExecutionOptions {
55                    inputs: Map::from_iter([
56                        ("quantity".into(), json!(6)),
57                        ("trace".into(), json!("sample")),
58                    ]),
59                    ..ExecutionOptions::default()
60                })
61                .await?;
62            let Some(ExecutionEvent::Partial { result, .. }) = execution.next().await? else {
63                return Err(AppError::Integration(
64                    "expected the real action partial".into(),
65                ));
66            };
67            if result.get("progress") != Some(&json!("calculated")) {
68                return Err(AppError::Integration("partial changed".into()));
69            }
70            let Some(ExecutionEvent::Committed { outcomes, .. }) = execution.step().await? else {
71                return Err(AppError::Integration(
72                    "expected one committed boundary".into(),
73                ));
74            };
75            let expected =
76                json!({"quantity":6,"label":"order","currency":"USD","trace":"sample","total":42});
77            if outcomes.len() != 1 || Value::Object(outcomes[0].result.clone()) != expected {
78                return Err(AppError::Integration(
79                    "resolved inputs or action result changed".into(),
80                ));
81            }
82            let terminal = execution.finish().await?;
83            if !matches!(terminal.status, RunStatus::Succeeded)
84                || terminal.state.values()
85                    != json!({"unit_price":7,"total":42}).as_object().unwrap()
86            {
87                return Err(AppError::Integration(
88                    "only the explicit total write should persist".into(),
89                ));
90            }
91            println!(
92                "Partial: calculated; committed total: 42; transient inputs stayed out of state"
93            );
94            Ok::<(), AppError>(())
95        })
96        .await;
97        let closed = tokio::time::timeout(
98            Duration::from_secs(15),
99            app.shutdown(Shutdown::CancelAndDrain {
100                timeout: Duration::from_secs(10),
101            }),
102        )
103        .await;
104        drop(app);
105        observed.map_err(|_| AppError::Timeout("invoice execution timed out".into()))??;
106        closed.map_err(|_| AppError::Timeout("invoice cleanup timed out".into()))??;
107        Ok(())
108    }
Source

pub async fn delete(&mut self, expected_revision: u64) -> Result<(), AppError>

Deletes this workspace after proving its revision fence.

Seals new admission, requests cancellation, and deletes lower workspaces only after every run is terminal with no unresolved effect. Progress is durable and resumable; terminal run history is retained until explicit run deletion.

§Errors

Returns Conflict for a stale revision or incompatible deletion intent, Busy while unresolved work prevents deletion, and Closed for revoked ownership. Invalid fences, storage/lower failures, or expired observation return InvalidInput, Integration, or Timeout.

See the workspace lifecycle.

Auto Trait Implementations§

§

impl<CS, A, X = NoActions, C = NoConditions, T = JsonState, H = NoHooks, E = InlineExecutor> !RefUnwindSafe for Workspace<CS, A, X, C, T, H, E>

§

impl<CS, A, X = NoActions, C = NoConditions, T = JsonState, H = NoHooks, E = InlineExecutor> !UnwindSafe for Workspace<CS, A, X, C, T, H, E>

§

impl<CS, A, X, C, T, H, E> Freeze for Workspace<CS, A, X, C, T, H, E>
where WorkspaceRuntime<CS, A, X, C, T, H, E>: Freeze,

§

impl<CS, A, X, C, T, H, E> Send for Workspace<CS, A, X, C, T, H, E>
where WorkspaceRuntime<CS, A, X, C, T, H, E>: Send,

§

impl<CS, A, X, C, T, H, E> Sync for Workspace<CS, A, X, C, T, H, E>
where WorkspaceRuntime<CS, A, X, C, T, H, E>: Sync,

§

impl<CS, A, X, C, T, H, E> Unpin for Workspace<CS, A, X, C, T, H, E>
where WorkspaceRuntime<CS, A, X, C, T, H, E>: Unpin,

§

impl<CS, A, X, C, T, H, E> UnsafeUnpin for Workspace<CS, A, X, C, T, H, E>
where WorkspaceRuntime<CS, A, X, C, T, H, E>: UnsafeUnpin,

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> ArchivePointee for T

Source§

type ArchivedMetadata = ()

The archived version of the pointer metadata for this type.
Source§

fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata

Converts some archived metadata to the pointer metadata for itself.
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

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

Source§

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

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

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

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> LayoutRaw for T

Source§

fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>

Returns the layout of the type.
Source§

impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
where T: SharedNiching<N1, N2>, N1: Niching<T>, N2: Niching<T>,

Source§

unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool

Returns whether the given value has been niched. Read more
Source§

fn resolve_niched(out: Place<NichedOption<T, N1>>)

Writes data to out indicating that a T is niched.
Source§

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

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Pointee for T

Source§

type Metadata = ()

The metadata type for pointers and references to this type.
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

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

Source§

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

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

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

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more