Skip to main content

AppConfig

Struct AppConfig 

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

Complete application configuration.

App does not offer a separate built-in storage construction path:

ⓘ
let _ = app_kit::AppState::<storage_kit::StateStore>::Ephemeral;

Owns caller-built storage, a homogeneous agent inventory, and workflow definitions.

The consuming with_* methods change their concrete App behavior parameter. They do not erase backends or alter already admitted runs. Heterogeneous agent inventories use a caller-owned exhaustive hierarchy. Dropping configuration before open does not perform asynchronous Agent shutdown.

§Configure behavior

Start with ready storage, ready Agents, and parsed definitions. Apply the consuming configuration methods before App::open; they retain exact implementation types, including associated lower children and transaction ownership. None registers a runtime callback or erases a backend.

BehaviorComplete implementation exampleAttach before open
Produce lazy action events and writesworkflow::ActionBackendSelf::with_actions
Evaluate declared routing predicatesworkflow::ConditionBackendSelf::with_conditions
Construct and validate application stateworkflow::StateTypingSelf::with_state_typing
Observe authoritative lifecycle eventsworkflow::LifecycleHooksSelf::with_hooks
Drive concrete local child futuresworkflow::ChildExecutorSelf::with_child_executor

The with_* examples exercise the complete path from a concrete implementation to opening App. Action and condition declarations must match the workflow’s exact logical keys and revisions. A custom child executor must return every admitted completion exactly once; it never creates child identities. App’s built-in NoActions, NoConditions, JsonState, NoHooks and InlineExecutor are suitable defaults only where their actual behavior satisfies the workflow.

Lower composition is independent: A::Workspace fixes its Conversation, while CS::Transaction fixes consuming commit/rollback. For heterogeneous Agent inventories implement matching caller-owned exhaustive hierarchies; do not substitute public trait objects or independent child parameters.

§Example

let mut app = App::open(config).await?;
app.shutdown(Shutdown::RejectActive).await?;

Implementations§

Source§

impl<CS: StateStoreBackend, A: AgentBackend> AppConfig<CS, A>

Source

pub fn new( state: CS, agents: Vec<AgentSpec<A>>, workflows: Vec<WorkflowDefinition>, ) -> Self

Constructs configuration from a caller-owned control-plane store and agents.

The store is required even for process-local operation. App preserves its concrete transaction type and never constructs lower products. Ownership transfers to App when App::open is called.

§Example
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition]);
let mut app = App::open(config).await?;
app.shutdown(Shutdown::RejectActive).await?;
Examples found in repository?
examples/history_and_recovery.rs (lines 55-59)
31    async fn open_app(&self) -> Result<App<StateStore, Agent>, AppError> {
32        let definition = WorkflowDefinition::parse(
33            &json!({
34                "schema":"app-kit.workflow/v2", "id":"history-counter", "revision":"r1",
35                "state":{"count":0}, "required":["count"],
36                "reducers":{"count":"reject_concurrent"}, "entry":"first",
37                "nodes":[
38                    {"id":"first", "step":{"kind":"state", "mutations":[{
39                        "kind":"increment", "target":"count",
40                        "value":{"kind":"literal", "value":1}
41                    }]}},
42                    {"id":"second", "step":{"kind":"state", "mutations":[{
43                        "kind":"increment", "target":"count",
44                        "value":{"kind":"literal", "value":1}
45                    }]}}
46                ],
47                "routes":{"first":{"mode":"first", "branches":[{
48                    "target":{"kind":"node", "id":"second"}
49                }]}}
50            })
51            .to_string(),
52        )?;
53        // Agent supplies the static type for an empty inventory. No Agent value
54        // is constructed, and these native State nodes need no lower service.
55        App::open(AppConfig::<_, Agent>::new(
56            self.store.clone(),
57            Vec::new(),
58            vec![definition],
59        ))
60        .await
61    }
More examples
Hide additional examples
examples/actions_and_inputs.rs (line 40)
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    }
examples/performance.rs (line 1107)
1054    async fn run(mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
1055        let manifest = if matches!(self.command, Command::ReopenHistory { .. }) {
1056            self.root = self.root.canonicalize()?;
1057            Some(self.read_manifest()?)
1058        } else {
1059            fs::create_dir(&self.root)?;
1060            self.root = self.root.canonicalize()?;
1061            fs::create_dir(self.root.join("workspace"))?;
1062            let mut marker = OpenOptions::new()
1063                .write(true)
1064                .create_new(true)
1065                .open(self.root.join(".performance-root"))?;
1066            marker.write_all(MANIFEST_SCHEMA.as_bytes())?;
1067            marker.sync_all()?;
1068            None
1069        };
1070        let actions = match self.command {
1071            Command::Linear => 1_000,
1072            Command::SeedHistory { rows } => (rows - 4) / 3,
1073            Command::Ready => 32 * 32,
1074            Command::Map => 4_096,
1075            Command::Repeated => 100,
1076            Command::NestedCancel => 16,
1077            Command::DelayedObserver => 1,
1078            Command::ReopenHistory { .. } => {
1079                manifest.as_ref().unwrap()["actions"].as_u64().unwrap()
1080            }
1081        };
1082        let linear = matches!(self.command, Command::Linear);
1083        let (definitions, definition_bytes) = self.definitions(actions)?;
1084        let probe = match self.command {
1085            Command::Ready => Some(WorkloadProbe::new(SourceMode::Permuted, 1_024)),
1086            Command::Map | Command::Repeated => {
1087                Some(WorkloadProbe::new(SourceMode::Parallel, actions as usize))
1088            }
1089            Command::NestedCancel => Some(WorkloadProbe::new(SourceMode::Held, 16)),
1090            Command::DelayedObserver => Some(WorkloadProbe::new(SourceMode::Partials, 1)),
1091            Command::Linear | Command::SeedHistory { .. } | Command::ReopenHistory { .. } => None,
1092        };
1093        if let Some(manifest) = &manifest {
1094            assert_eq!(manifest["definition_bytes"], json!(definition_bytes));
1095        }
1096        let mut app = None;
1097        let started = Instant::now();
1098        let observed = AssertUnwindSafe(tokio::time::timeout(WORKLOAD_BUDGET, async {
1099            let connecting = Instant::now();
1100            let config = LanceStateStoreConfig::directory(self.root.join("state"))
1101                .with_operation_timeout(Duration::from_secs(30))?;
1102            let store = StateStore::connect(StateStoreConfig::Lance(config)).await?;
1103            let connect = connecting.elapsed();
1104            let opening = Instant::now();
1105            app = Some(
1106                App::open(
1107                    AppConfig::<_, Agent>::new(store, Vec::new(), definitions).with_actions(
1108                        probe
1109                            .as_ref()
1110                            .map(WorkloadAction::new)
1111                            .into_iter()
1112                            .collect(),
1113                    ),
1114                )
1115                .await?,
1116            );
1117            let open = opening.elapsed();
1118            let mut result = match self.command {
1119                Command::Linear | Command::SeedHistory { .. } => {
1120                    self.seed(app.as_ref().unwrap(), actions, linear).await?
1121                }
1122                Command::Ready => {
1123                    self.ready(app.as_ref().unwrap(), probe.as_ref().unwrap())
1124                        .await?
1125                }
1126                Command::Map => {
1127                    self.mapped(app.as_ref().unwrap(), probe.as_ref().unwrap())
1128                        .await?
1129                }
1130                Command::Repeated => {
1131                    self.repeated(app.as_ref().unwrap(), probe.as_ref().unwrap())
1132                        .await?
1133                }
1134                Command::NestedCancel => {
1135                    self.nested_cancel(app.as_ref().unwrap(), probe.as_ref().unwrap())
1136                        .await?
1137                }
1138                Command::DelayedObserver => {
1139                    self.delayed_observer(app.as_ref().unwrap(), probe.as_ref().unwrap())
1140                        .await?
1141                }
1142                Command::ReopenHistory { open_only } => {
1143                    self.reopen(
1144                        app.as_ref().unwrap(),
1145                        manifest.as_ref().unwrap(),
1146                        actions,
1147                        open_only,
1148                    )
1149                    .await?
1150                }
1151            };
1152            result["store_connect_ns"] = json!(connect.as_nanos());
1153            result["app_open_ns"] = json!(open.as_nanos());
1154            result["workload_elapsed_ns"] = json!(started.elapsed().as_nanos());
1155            Ok::<_, Box<dyn Error + Send + Sync>>(result)
1156        }))
1157        .catch_unwind()
1158        .await;
1159        let success = matches!(&observed, Ok(Ok(Ok(_))));
1160        let closing = Instant::now();
1161        let cleanup = if let Some(mut app) = app.take() {
1162            let closed = AssertUnwindSafe(Self::close(&mut app, success))
1163                .catch_unwind()
1164                .await;
1165            drop(app);
1166            Some(closed)
1167        } else {
1168            None
1169        };
1170        if !success {
1171            eprintln!(
1172                "performance workload failed; cleanup completed={}",
1173                matches!(&cleanup, Some(Ok(Ok(()))))
1174            );
1175        }
1176        let mut result = match observed {
1177            Ok(Ok(result)) => result?,
1178            Ok(Err(_)) => {
1179                return Err(
1180                    AppError::Timeout("performance workload budget exhausted".into()).into(),
1181                );
1182            }
1183            Err(panic) => resume_unwind(panic),
1184        };
1185        match cleanup {
1186            Some(Ok(result)) => result?,
1187            Some(Err(panic)) => resume_unwind(panic),
1188            None => return Err("successful workload did not retain its App cleanup owner".into()),
1189        }
1190        // All run/workflow/App owners and the caller-created store have dropped.
1191        // A cleanup timeout remains a failure even if reattachment later joined.
1192        result["schema"] = json!(MANIFEST_SCHEMA);
1193        result["settings"] = Self::settings(actions);
1194        if let Some(probe) = &probe {
1195            probe.assert_idle();
1196            result["caller_sources"] = probe.report();
1197            result["settings"]
1198                .as_object_mut()
1199                .unwrap()
1200                .remove("history_row_ceiling");
1201            result["settings"]["private_task_counts"] =
1202                json!("not exposed; App shutdown proves joined ownership");
1203            result["settings"]["lower_agents_and_tool_handlers"] = json!("none constructed");
1204        }
1205        result["definition_bytes"] = json!(definition_bytes);
1206        result["process_id"] = json!(std::process::id());
1207        result["os"] = json!(std::env::consts::OS);
1208        result["architecture"] = json!(std::env::consts::ARCH);
1209        result["package_version"] = json!(env!("CARGO_PKG_VERSION"));
1210        result["cleanup_joined"] = json!(true);
1211        result["cleanup_ns"] = json!(closing.elapsed().as_nanos());
1212        let encoded = serde_json::to_vec(&result)?;
1213        assert!(
1214            encoded.len() <= 16_384,
1215            "result stays within the manifest bound"
1216        );
1217        if matches!(self.command, Command::SeedHistory { .. }) {
1218            let mut file = OpenOptions::new()
1219                .write(true)
1220                .create_new(true)
1221                .open(self.root.join("manifest.json"))?;
1222            file.write_all(&encoded)?;
1223            file.sync_all()?;
1224        }
1225        println!("{}", std::str::from_utf8(&encoded)?);
1226        Ok(())
1227    }
Source§

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

Source

pub fn with_actions<N: ActionBackend>( self, actions: Vec<N>, ) -> AppConfig<CS, A, N, C, T, H, E>

Replaces the complete caller-owned action inventory before opening App.

Values retain their concrete type and need not implement Clone. App validates their stable declarations before accepting any workflow work. Replacing an inventory drops its previous values without invoking them.

§Example
use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use app_kit::workflow::{CheckpointSelector, ExecutionEvent, ExecutionOptions, RunSelector,
    RunStatus, WorkflowDefinition, WorkflowState};
use storage_kit::StateStore;
use storage_kit::state::config::{LanceStateStoreConfig, StateStoreConfig};
use app_kit::{AppError, workflow::{ActionBackend, ActionDeclaration, ActionEvent,
    ActionMode, ActionRequest, StateChange}};
use serde_json::{Map, Value};
struct Increment { declaration: ActionDeclaration }
impl ActionBackend for Increment {
    type Stream = futures_util::stream::Iter<std::vec::IntoIter<Result<ActionEvent, AppError>>>;
    fn declaration(&self) -> &ActionDeclaration { &self.declaration }
    fn start(&self, request: ActionRequest) -> Self::Stream {
        let count = request.state.values()["count"].as_i64().unwrap() + 1;
        futures_util::stream::iter(vec![Ok(ActionEvent::Completed {
            result: Map::from_iter([("new_count".into(), Value::from(count))]),
            writes: vec![StateChange::Increment { values: vec![("count".into(), Value::from(1))] }],
        })])
    }
}
let action = Increment { declaration: ActionDeclaration {
    key: "increment".into(), revision: "r1".into(), reads: vec!["count".into()],
    writes: vec!["count".into()], required_inputs: Vec::new(), optional_inputs: Vec::new(),
    bound_inputs: Map::new(), default_inputs: Map::new(), tags: vec!["counter".into()],
    source: Some("increment count by one".into()), mode: ActionMode::Both,
} };
let store = StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
let definition = WorkflowDefinition::parse(r#"{
 "schema":"app-kit.workflow/v2","id":"counter","revision":"r1",
 "state":{"count":0},"required":["count"],"reducers":{"count":"reject_concurrent"},
 "entry":"increment","nodes":[{"id":"increment","step":{"kind":"action",
 "action":"increment","revision":"r1"}}],"routes":{}
}"#)?;
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition]);
let config = config.with_actions(vec![action]);
let mut app = App::open(config).await?;
let workspace = app.create_workspace(WorkspaceConfig { name: None, root: std::env::current_dir()? }).await?;
let workflow = workspace.workflow("counter".parse()?).await?;
let run = workflow.start(ExecutionOptions::default()).await?;
assert_eq!(run.wait().await?.state.values()["count"], 1);
app.shutdown(Shutdown::Drain { timeout: std::time::Duration::from_secs(5) }).await?;
Examples found in repository?
examples/actions_and_inputs.rs (line 41)
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    }
More examples
Hide additional examples
examples/performance.rs (lines 1107-1113)
1054    async fn run(mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
1055        let manifest = if matches!(self.command, Command::ReopenHistory { .. }) {
1056            self.root = self.root.canonicalize()?;
1057            Some(self.read_manifest()?)
1058        } else {
1059            fs::create_dir(&self.root)?;
1060            self.root = self.root.canonicalize()?;
1061            fs::create_dir(self.root.join("workspace"))?;
1062            let mut marker = OpenOptions::new()
1063                .write(true)
1064                .create_new(true)
1065                .open(self.root.join(".performance-root"))?;
1066            marker.write_all(MANIFEST_SCHEMA.as_bytes())?;
1067            marker.sync_all()?;
1068            None
1069        };
1070        let actions = match self.command {
1071            Command::Linear => 1_000,
1072            Command::SeedHistory { rows } => (rows - 4) / 3,
1073            Command::Ready => 32 * 32,
1074            Command::Map => 4_096,
1075            Command::Repeated => 100,
1076            Command::NestedCancel => 16,
1077            Command::DelayedObserver => 1,
1078            Command::ReopenHistory { .. } => {
1079                manifest.as_ref().unwrap()["actions"].as_u64().unwrap()
1080            }
1081        };
1082        let linear = matches!(self.command, Command::Linear);
1083        let (definitions, definition_bytes) = self.definitions(actions)?;
1084        let probe = match self.command {
1085            Command::Ready => Some(WorkloadProbe::new(SourceMode::Permuted, 1_024)),
1086            Command::Map | Command::Repeated => {
1087                Some(WorkloadProbe::new(SourceMode::Parallel, actions as usize))
1088            }
1089            Command::NestedCancel => Some(WorkloadProbe::new(SourceMode::Held, 16)),
1090            Command::DelayedObserver => Some(WorkloadProbe::new(SourceMode::Partials, 1)),
1091            Command::Linear | Command::SeedHistory { .. } | Command::ReopenHistory { .. } => None,
1092        };
1093        if let Some(manifest) = &manifest {
1094            assert_eq!(manifest["definition_bytes"], json!(definition_bytes));
1095        }
1096        let mut app = None;
1097        let started = Instant::now();
1098        let observed = AssertUnwindSafe(tokio::time::timeout(WORKLOAD_BUDGET, async {
1099            let connecting = Instant::now();
1100            let config = LanceStateStoreConfig::directory(self.root.join("state"))
1101                .with_operation_timeout(Duration::from_secs(30))?;
1102            let store = StateStore::connect(StateStoreConfig::Lance(config)).await?;
1103            let connect = connecting.elapsed();
1104            let opening = Instant::now();
1105            app = Some(
1106                App::open(
1107                    AppConfig::<_, Agent>::new(store, Vec::new(), definitions).with_actions(
1108                        probe
1109                            .as_ref()
1110                            .map(WorkloadAction::new)
1111                            .into_iter()
1112                            .collect(),
1113                    ),
1114                )
1115                .await?,
1116            );
1117            let open = opening.elapsed();
1118            let mut result = match self.command {
1119                Command::Linear | Command::SeedHistory { .. } => {
1120                    self.seed(app.as_ref().unwrap(), actions, linear).await?
1121                }
1122                Command::Ready => {
1123                    self.ready(app.as_ref().unwrap(), probe.as_ref().unwrap())
1124                        .await?
1125                }
1126                Command::Map => {
1127                    self.mapped(app.as_ref().unwrap(), probe.as_ref().unwrap())
1128                        .await?
1129                }
1130                Command::Repeated => {
1131                    self.repeated(app.as_ref().unwrap(), probe.as_ref().unwrap())
1132                        .await?
1133                }
1134                Command::NestedCancel => {
1135                    self.nested_cancel(app.as_ref().unwrap(), probe.as_ref().unwrap())
1136                        .await?
1137                }
1138                Command::DelayedObserver => {
1139                    self.delayed_observer(app.as_ref().unwrap(), probe.as_ref().unwrap())
1140                        .await?
1141                }
1142                Command::ReopenHistory { open_only } => {
1143                    self.reopen(
1144                        app.as_ref().unwrap(),
1145                        manifest.as_ref().unwrap(),
1146                        actions,
1147                        open_only,
1148                    )
1149                    .await?
1150                }
1151            };
1152            result["store_connect_ns"] = json!(connect.as_nanos());
1153            result["app_open_ns"] = json!(open.as_nanos());
1154            result["workload_elapsed_ns"] = json!(started.elapsed().as_nanos());
1155            Ok::<_, Box<dyn Error + Send + Sync>>(result)
1156        }))
1157        .catch_unwind()
1158        .await;
1159        let success = matches!(&observed, Ok(Ok(Ok(_))));
1160        let closing = Instant::now();
1161        let cleanup = if let Some(mut app) = app.take() {
1162            let closed = AssertUnwindSafe(Self::close(&mut app, success))
1163                .catch_unwind()
1164                .await;
1165            drop(app);
1166            Some(closed)
1167        } else {
1168            None
1169        };
1170        if !success {
1171            eprintln!(
1172                "performance workload failed; cleanup completed={}",
1173                matches!(&cleanup, Some(Ok(Ok(()))))
1174            );
1175        }
1176        let mut result = match observed {
1177            Ok(Ok(result)) => result?,
1178            Ok(Err(_)) => {
1179                return Err(
1180                    AppError::Timeout("performance workload budget exhausted".into()).into(),
1181                );
1182            }
1183            Err(panic) => resume_unwind(panic),
1184        };
1185        match cleanup {
1186            Some(Ok(result)) => result?,
1187            Some(Err(panic)) => resume_unwind(panic),
1188            None => return Err("successful workload did not retain its App cleanup owner".into()),
1189        }
1190        // All run/workflow/App owners and the caller-created store have dropped.
1191        // A cleanup timeout remains a failure even if reattachment later joined.
1192        result["schema"] = json!(MANIFEST_SCHEMA);
1193        result["settings"] = Self::settings(actions);
1194        if let Some(probe) = &probe {
1195            probe.assert_idle();
1196            result["caller_sources"] = probe.report();
1197            result["settings"]
1198                .as_object_mut()
1199                .unwrap()
1200                .remove("history_row_ceiling");
1201            result["settings"]["private_task_counts"] =
1202                json!("not exposed; App shutdown proves joined ownership");
1203            result["settings"]["lower_agents_and_tool_handlers"] = json!("none constructed");
1204        }
1205        result["definition_bytes"] = json!(definition_bytes);
1206        result["process_id"] = json!(std::process::id());
1207        result["os"] = json!(std::env::consts::OS);
1208        result["architecture"] = json!(std::env::consts::ARCH);
1209        result["package_version"] = json!(env!("CARGO_PKG_VERSION"));
1210        result["cleanup_joined"] = json!(true);
1211        result["cleanup_ns"] = json!(closing.elapsed().as_nanos());
1212        let encoded = serde_json::to_vec(&result)?;
1213        assert!(
1214            encoded.len() <= 16_384,
1215            "result stays within the manifest bound"
1216        );
1217        if matches!(self.command, Command::SeedHistory { .. }) {
1218            let mut file = OpenOptions::new()
1219                .write(true)
1220                .create_new(true)
1221                .open(self.root.join("manifest.json"))?;
1222            file.write_all(&encoded)?;
1223            file.sync_all()?;
1224        }
1225        println!("{}", std::str::from_utf8(&encoded)?);
1226        Ok(())
1227    }
Source

pub fn with_conditions<N: ConditionBackend>( self, conditions: Vec<N>, ) -> AppConfig<CS, A, X, N, T, H, E>

Replaces the complete caller-owned condition inventory before opening App.

App validates stable logical keys and revisions without evaluating the predicates. Replacing an inventory drops its previous values.

§Example
use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use app_kit::workflow::{CheckpointSelector, ExecutionEvent, ExecutionOptions, RunSelector,
    RunStatus, WorkflowDefinition, WorkflowState};
use storage_kit::StateStore;
use storage_kit::state::config::{LanceStateStoreConfig, StateStoreConfig};
use app_kit::{AppError, workflow::{ConditionBackend, ConditionDeclaration}};
struct Ready { declaration: ConditionDeclaration }
impl ConditionBackend for Ready {
    fn declaration(&self) -> &ConditionDeclaration { &self.declaration }
    fn evaluate(&self, state: &WorkflowState) -> Result<bool, AppError> {
        let count = state.values().get("count").and_then(serde_json::Value::as_i64)
            .ok_or_else(|| AppError::InvalidInput("count must be an integer".into()))?;
        Ok(count >= 3)
    }
}
let condition = Ready { declaration: ConditionDeclaration {
    key: "ready".into(), revision: "r1".into(), reads: vec!["count".into()],
} };
let store = StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
let definition = WorkflowDefinition::parse(r#"{
    "schema":"app-kit.workflow/v2", "id":"counter", "revision":"r1",
    "state":{"count":0}, "required":["count"],
    "reducers":{"count":"reject_concurrent"}, "entry":"increment",
    "nodes":[{"id":"increment","step":{"kind":"state","mutations":[
        {"kind":"increment","target":"count","value":{"kind":"literal","value":1}}
    ]}}], "routes":{"increment":{"mode":"first","branches":[
        {"when":{"kind":"custom","condition":"ready","revision":"r1"},"target":{"kind":"end"}},
        {"target":{"kind":"node","id":"increment"}}
    ]}}
}"#)?;
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition]);
let config = config.with_conditions(vec![condition]);
let mut app = App::open(config).await?;
let workspace = app.create_workspace(WorkspaceConfig { name: None, root: std::env::current_dir()? }).await?;
let workflow = workspace.workflow("counter".parse()?).await?;
let terminal = workflow.start(ExecutionOptions::default()).await?.wait().await?;
assert!(matches!(terminal.status, RunStatus::Succeeded));
assert_eq!(terminal.state.values()["count"], 3);
app.shutdown(Shutdown::Drain { timeout: std::time::Duration::from_secs(5) }).await?;
Source

pub fn with_state_typing<N: StateTyping>( self, typing: N, ) -> AppConfig<CS, A, X, C, N, H, E>

Replaces the caller-owned workflow typing policy before opening App.

The policy remains concrete and need not implement Clone. Its data values are local to validation or execution and need not be Send.

§Example
use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use app_kit::workflow::{CheckpointSelector, ExecutionEvent, ExecutionOptions, RunSelector,
    RunStatus, WorkflowDefinition, WorkflowState};
use storage_kit::StateStore;
use storage_kit::state::config::{LanceStateStoreConfig, StateStoreConfig};
use app_kit::{AppError, workflow::{StateTyping, StateChange}};
use serde_json::{Map, Value};
struct Counter;
impl StateTyping for Counter {
    type Data = i64;
    fn construct_data(&self, state: &WorkflowState) -> Result<i64, AppError> {
        state.values().get("count").and_then(Value::as_i64)
            .ok_or_else(|| AppError::InvalidInput("count must be an integer".into()))
    }
    fn construct_state(&self, count: &i64) -> Result<WorkflowState, AppError> {
        WorkflowState::new(Map::from_iter([("count".into(), Value::from(*count))]))
    }
    fn validate_pre(&self, _state: &WorkflowState, change: &StateChange) -> Result<(), AppError> {
        if let StateChange::Increment { values } = change {
            if values.iter().any(|(_, delta)| delta.as_i64().is_some_and(|value| value < 0)) {
                return Err(AppError::InvalidInput("count cannot decrease".into()));
            }
        }
        Ok(())
    }
    fn validate_post(&self, before: &WorkflowState, after: &WorkflowState, _change: &StateChange) -> Result<(), AppError> {
        if self.construct_data(after)? < self.construct_data(before)? {
            return Err(AppError::InvalidInput("count cannot decrease".into()));
        }
        Ok(())
    }
    fn validate_state(&self, state: &WorkflowState) -> Result<(), AppError> {
        if self.construct_data(state)? < 0 {
            return Err(AppError::InvalidInput("count must be nonnegative".into()));
        }
        Ok(())
    }
}
let store = StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
let definition = WorkflowDefinition::parse(r#"{
    "schema":"app-kit.workflow/v2", "id":"counter", "revision":"r1",
    "state":{"count":0}, "required":["count"],
    "reducers":{"count":"reject_concurrent"}, "entry":"increment",
    "nodes":[{"id":"increment","step":{"kind":"state","mutations":[
        {"kind":"increment","target":"count","value":{"kind":"literal","value":1}}
    ]}}], "routes":{}
}"#)?;
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition]);
let config = config.with_state_typing(Counter);
let mut app = App::open(config).await?;
let workspace = app.create_workspace(WorkspaceConfig { name: None, root: std::env::current_dir()? }).await?;
let workflow = workspace.workflow("counter".parse()?).await?;
let invalid = WorkflowState::new(serde_json::from_str(r#"{"count":-1}"#)?)?;
assert!(workflow.prepare(invalid).await.is_err());
app.shutdown(Shutdown::RejectActive).await?;
Source

pub fn with_hooks<N: LifecycleHooks>( self, hooks: N, ) -> AppConfig<CS, A, X, C, T, N, E>

Replaces the caller-owned lifecycle observer before opening App.

Replacement drops the prior observer without invoking it. The new observer retains its concrete type and need not implement Clone.

§Example
use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use app_kit::workflow::{CheckpointSelector, ExecutionEvent, ExecutionOptions, RunSelector,
    RunStatus, WorkflowDefinition, WorkflowState};
use storage_kit::StateStore;
use storage_kit::state::config::{LanceStateStoreConfig, StateStoreConfig};
use app_kit::{AppError, workflow::{LifecycleEvent, LifecycleHooks}};
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
struct CountEvents(Arc<AtomicUsize>);
impl LifecycleHooks for CountEvents {
    fn observe(&self, event: &LifecycleEvent<'_>) -> Result<(), AppError> {
        if matches!(event, LifecycleEvent::ExecuteStarted { .. }) {
            self.0.fetch_add(1, Ordering::SeqCst);
        }
        Ok(())
    }
    fn observe_async<'a>(&'a self, event: &'a LifecycleEvent<'a>)
        -> impl std::future::Future<Output = Result<(), AppError>> + Send + 'a {
        async move {
            if matches!(event, LifecycleEvent::ExecuteStarted { .. }) {
                self.0.fetch_add(10, Ordering::SeqCst);
            }
            Ok(())
        }
    }
}
let store = StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
let definition = WorkflowDefinition::parse(r#"{
    "schema":"app-kit.workflow/v2", "id":"counter", "revision":"r1",
    "state":{"count":0}, "required":["count"],
    "reducers":{"count":"reject_concurrent"}, "entry":"increment",
    "nodes":[{"id":"increment","step":{"kind":"state","mutations":[
        {"kind":"increment","target":"count","value":{"kind":"literal","value":1}}
    ]}}], "routes":{}
}"#)?;
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition]);
let count = Arc::new(AtomicUsize::new(0));
let config = config.with_hooks(CountEvents(Arc::clone(&count)));
let mut app = App::open(config).await?;
let workspace = app.create_workspace(WorkspaceConfig { name: None, root: std::env::current_dir()? }).await?;
let workflow = workspace.workflow("counter".parse()?).await?;
let mut run = workflow.prepare(WorkflowState::default()).await?;
run.execution(ExecutionOptions::default()).await?.finish().await?;
assert_eq!(count.load(Ordering::SeqCst), 11);
app.shutdown(Shutdown::Drain { timeout: std::time::Duration::from_secs(5) }).await?;
Source

pub fn with_child_executor<N: ChildExecutor>( self, executor: N, ) -> AppConfig<CS, A, X, C, T, H, N>

Replaces the caller-owned admitted child executor before opening App.

The executor remains concrete. Its associated execution futures are created only for admitted child work and need not implement Send.

§Example
use agents_kit::Agent;
use app_kit::{App, AppConfig, Shutdown, WorkspaceConfig};
use app_kit::workflow::{CheckpointSelector, ExecutionEvent, ExecutionOptions, RunSelector,
    RunStatus, WorkflowDefinition, WorkflowState};
use storage_kit::StateStore;
use storage_kit::state::config::{LanceStateStoreConfig, StateStoreConfig};
let store = StateStore::connect(StateStoreConfig::Lance(LanceStateStoreConfig::memory())).await?;
let definition = WorkflowDefinition::parse(r#"{
 "schema":"app-kit.workflow/v2","id":"counter","revision":"r1",
 "state":{"sum":0},"required":["sum"],"reducers":{"sum":"sum_integer"},
 "entry":"child","nodes":[{"id":"child","step":{"kind":"child","workflow":"child",
 "input":{"count":{"kind":"literal","value":4}},
 "reductions":[{"source":"count","target":"sum","reducer":"sum_integer"}]}}],"routes":{}
}"#)?;
let child = WorkflowDefinition::parse(r#"{
    "schema":"app-kit.workflow/v2", "id":"child", "revision":"r1",
    "state":{"count":0}, "required":["count"],
    "reducers":{"count":"reject_concurrent"}, "entry":"increment",
    "nodes":[{"id":"increment","step":{"kind":"state","mutations":[
        {"kind":"increment","target":"count","value":{"kind":"literal","value":1}}
    ]}}], "routes":{}
}"#)?;
let config = AppConfig::<_, Agent>::new(store, Vec::new(), vec![definition, child])
    .with_child_executor(app_kit::workflow::InlineExecutor);
let mut app = App::open(config).await?;
let mut workspace = app.create_workspace(WorkspaceConfig {
    name: Some("local counter".into()), root: std::env::current_dir()?,
}).await?;
let workflow = workspace.workflow("counter".parse()?).await?;
let mut run = workflow.prepare(WorkflowState::default()).await?;
let terminal = run.execution(ExecutionOptions::default()).await?.finish().await?;
assert_eq!(terminal.state.values()["sum"], 5);
app.shutdown(Shutdown::CancelAndDrain { timeout: std::time::Duration::from_secs(5) }).await?;

Auto Trait Implementations§

§

impl<CS, A, X, C, T, H, E> Freeze for AppConfig<CS, A, X, C, T, H, E>
where CS: Freeze, Vec<AgentSpec<A>>: Freeze, Vec<X>: Freeze, Vec<C>: Freeze, T: Freeze, H: Freeze, E: Freeze,

§

impl<CS, A, X, C, T, H, E> RefUnwindSafe for AppConfig<CS, A, X, C, T, H, E>

§

impl<CS, A, X, C, T, H, E> Send for AppConfig<CS, A, X, C, T, H, E>
where Vec<AgentSpec<A>>: Send, Vec<X>: Send, Vec<C>: Send,

§

impl<CS, A, X, C, T, H, E> Sync for AppConfig<CS, A, X, C, T, H, E>
where Vec<AgentSpec<A>>: Sync, Vec<X>: Sync, Vec<C>: Sync,

§

impl<CS, A, X, C, T, H, E> Unpin for AppConfig<CS, A, X, C, T, H, E>
where CS: Unpin, Vec<AgentSpec<A>>: Unpin, Vec<X>: Unpin, Vec<C>: Unpin, T: Unpin, H: Unpin, E: Unpin,

§

impl<CS, A, X, C, T, H, E> UnsafeUnpin for AppConfig<CS, A, X, C, T, H, E>

§

impl<CS, A, X, C, T, H, E> UnwindSafe for AppConfig<CS, A, X, C, T, H, E>

Blanket Implementations§

Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,

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