cloacina_workflow_plugin/inventory_entries.rs
1/*
2 * Copyright 2025-2026 Colliery Software
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! Inventory entry types reachable from packaged cdylibs.
18//!
19//! These types live in `cloacina-workflow-plugin` (a leaf crate that
20//! packaged cdylibs depend on) so the unified `cloacina::package!()` shell
21//! macro can walk `inventory::iter::<T>` at FFI call time without dragging
22//! in the full `cloacina` engine.
23//!
24//! `cloacina` (the host engine) re-exports these types from
25//! `cloacina_workflow_plugin::inventory` so existing engine code paths
26//! continue to compile unchanged.
27//!
28//! T-C (CLOACI-T-0549) relocated `TaskEntry` and `ComputationGraphEntry`
29//! here so the shell's `get_task_metadata` / `execute_task` /
30//! `get_graph_metadata` / `execute_graph` bodies can walk these inventories
31//! from packaged cdylibs. `TriggerEntry` / `TriggerlessGraphEntry` /
32//! `WorkflowEntry` / `StreamBackendEntry` remain in
33//! `cloacina/src/inventory_entries.rs` until their constructor return
34//! types likewise relocate.
35
36use cloacina_computation_graph::{ComputationGraphRegistration, GraphResult, ReactorRegistration};
37use cloacina_workflow::{Context, Task, TaskNamespace, Trigger};
38use std::future::Future;
39use std::pin::Pin;
40use std::sync::Arc;
41
42// ----------------------------------------------------------------------------
43// Trigger-less computation graph types (T-0552 — relocated from
44// cloacina/src/computation_graph/triggerless.rs so packaged cdylibs can
45// reach them).
46// ----------------------------------------------------------------------------
47
48/// The compiled function emitted for a trigger-less computation graph.
49///
50/// Takes the workflow context the graph was invoked with; returns a
51/// `GraphResult` whose terminal outputs are pre-serialized to
52/// `serde_json::Value`.
53pub type TriggerlessGraphFn = Arc<
54 dyn Fn(Context<::serde_json::Value>) -> Pin<Box<dyn Future<Output = GraphResult> + Send>>
55 + Send
56 + Sync,
57>;
58
59/// Runtime-side description of a trigger-less computation graph.
60pub struct TriggerlessGraphRegistration {
61 /// Graph name (the macro's `mod` name).
62 pub name: String,
63 /// Compiled graph function.
64 pub graph_fn: TriggerlessGraphFn,
65 /// Names of every terminal node in declaration order. Workflow-task
66 /// invocation writes each terminal output into the post-invocation
67 /// context under the matching name.
68 pub terminal_node_names: Vec<String>,
69}
70
71/// Compile-time link from a `Graph` handle to its trigger-less invocation
72/// surface.
73///
74/// The `#[computation_graph]` macro emits an `impl TriggerlessGraph for
75/// __CGHandle_<mod>` only when the graph is trigger-less.
76pub trait TriggerlessGraph: cloacina_computation_graph::Graph {
77 /// Construct a fresh `TriggerlessGraphFn` wrapping the compiled fn.
78 fn compiled_fn() -> TriggerlessGraphFn;
79 /// Names of every terminal node in declaration order.
80 fn terminal_node_names() -> &'static [&'static str];
81}
82
83/// Reactor entry emitted by the `#[reactor]` attribute macro. The `package!()`
84/// shell walks `inventory::iter::<ReactorEntry>` at FFI call time to produce
85/// `Vec<ReactorPackageMetadata>` for `get_reactor_metadata`.
86pub struct ReactorEntry {
87 pub name: &'static str,
88 pub constructor: fn() -> ReactorRegistration,
89}
90inventory::collect!(ReactorEntry);
91
92/// Task entry emitted by `#[task]`. The `package!()` shell walks
93/// `inventory::iter::<TaskEntry>` to build the per-task metadata in
94/// `get_task_metadata` and to dispatch task execution by name in
95/// `execute_task`.
96pub struct TaskEntry {
97 /// Deferred construction of the task namespace (cannot be const because
98 /// `TaskNamespace` contains `String`).
99 pub namespace: fn() -> TaskNamespace,
100 /// Task constructor — instantiates a fresh task object on each call.
101 pub constructor: fn() -> Arc<dyn Task>,
102}
103inventory::collect!(TaskEntry);
104
105/// Workflow descriptor entry emitted by `#[workflow]`. Provides the
106/// metadata fields the unified `cloacina::package!()` shell can't infer
107/// from `TaskEntry` alone (description, author, fingerprint, graph_data,
108/// triggers). Walked by the shell's `get_task_metadata` body to populate
109/// `PackageTasksMetadata`. (T-C / I-0102)
110pub struct WorkflowDescriptorEntry {
111 pub name: &'static str,
112 pub description: &'static str,
113 pub author: &'static str,
114 pub fingerprint: &'static str,
115 pub graph_data_json: &'static str,
116 /// Trigger names this workflow subscribes to (from
117 /// `#[workflow(triggers = ["..."])]`).
118 pub triggers: fn() -> ::std::vec::Vec<::std::string::String>,
119}
120inventory::collect!(WorkflowDescriptorEntry);
121
122/// Computation graph entry emitted by `#[computation_graph]` for the
123/// reactor-triggered (split) form. The `package!()` shell walks
124/// `inventory::iter::<ComputationGraphEntry>` to build the metadata
125/// returned by `get_graph_metadata` and to dispatch
126/// execution in `execute_graph`. At most one entry is expected per cdylib;
127/// the shell's body errors if it finds more than one.
128pub struct ComputationGraphEntry {
129 pub name: &'static str,
130 pub constructor: fn() -> ComputationGraphRegistration,
131}
132inventory::collect!(ComputationGraphEntry);
133
134/// Trigger entry emitted by `#[trigger]`. The `package!()` shell walks
135/// `inventory::iter::<TriggerEntry>` to populate `get_trigger_metadata`,
136/// calling each entry's constructor and querying the resulting trigger's
137/// `name` / `poll_interval` / `cron_expression` / `allow_concurrent`.
138/// (T-0552 — relocated from `cloacina` so packaged cdylibs can reach it.)
139pub struct TriggerEntry {
140 pub name: &'static str,
141 pub constructor: fn() -> Arc<dyn Trigger>,
142}
143inventory::collect!(TriggerEntry);
144
145/// Trigger-less computation graph entry emitted by `#[computation_graph]`
146/// for graphs declared without a `trigger = reactor(...)` clause. These
147/// graphs operate on `Context<Value>` rather than `InputCache` and are
148/// invoked directly by workflow tasks. (T-0552 — relocated from `cloacina`.)
149pub struct TriggerlessGraphEntry {
150 pub name: &'static str,
151 pub constructor: fn() -> TriggerlessGraphRegistration,
152}
153inventory::collect!(TriggerlessGraphEntry);