Skip to main content

panopticon_core/operation/
metadata.rs

1use crate::imports::*;
2
3/// A static description of an [`Operation`]'s inputs, outputs, and
4/// extension requirements.
5///
6/// Returned by [`Operation::metadata`] and consumed by the
7/// [`Registry`] during draft-time validation. Because every field is a
8/// `&'static` reference, the metadata is allocation-free — an
9/// implementation typically returns a struct literal built from `const`
10/// arrays.
11#[derive(Debug, Clone)]
12pub struct OperationMetadata {
13    /// The operation's canonical name, surfaced in error messages and
14    /// in logs from the [`Logger`](crate::prelude::Logger) hook.
15    pub name: &'static str,
16    /// A human-readable description of what the operation does.
17    pub description: &'static str,
18    /// The operation's declared inputs, in declaration order.
19    pub inputs: &'static [InputSpec],
20    /// The operation's declared outputs, in declaration order.
21    pub outputs: &'static [OutputSpec],
22    /// The extensions the operation requires at runtime.
23    pub requires_extensions: &'static [ExtensionSpec],
24}
25
26/// A single declared input on an [`OperationMetadata`].
27#[derive(Debug, Clone, PartialEq)]
28pub struct InputSpec {
29    /// The input's name — used as the lookup key for
30    /// [`Context::input`](crate::extend::Context).
31    pub name: &'static str,
32    /// The expected type. Use [`Type::Any`] to opt out of type
33    /// checking.
34    pub ty: Type,
35    /// Whether the input must be supplied by the caller. If `false`
36    /// and absent, the operation is expected to supply its own fallback
37    /// via `default` or custom logic.
38    pub required: bool,
39    /// An optional fallback value used when the input is absent.
40    pub default: Option<Value>,
41    /// A human-readable description of the input's role.
42    pub description: &'static str,
43}
44
45/// A single declared output on an [`OperationMetadata`].
46#[derive(Debug, Clone, PartialEq)]
47pub struct OutputSpec {
48    /// How the output's runtime name is determined. See [`NameSpec`].
49    pub name: NameSpec,
50    /// The output's type tag. Use [`Type::Any`] when the type varies
51    /// with the input.
52    pub ty: Type,
53    /// A human-readable description of the output's role.
54    pub description: &'static str,
55    /// Where the output is visible: globally or only within the
56    /// operation's outputs for the current step.
57    pub scope: OutputScope,
58}
59
60/// How the runtime name of an [`OutputSpec`] or [`ExtensionSpec`] is
61/// determined.
62///
63/// Static names are fixed at declaration time; derived names are
64/// looked up from a `Type::Text` input when the step runs, optionally
65/// falling back to a static default.
66#[derive(Debug, Clone, PartialEq)]
67pub enum NameSpec {
68    /// A fixed name known at declaration time.
69    Static(&'static str),
70    /// The name is read from the named input at runtime. The input
71    /// must be declared on the operation with `ty: Type::Text`.
72    DerivedFrom(&'static str),
73    /// As for [`DerivedFrom`](Self::DerivedFrom), but falls back to
74    /// `default` when the input is absent at runtime. The referenced
75    /// input must be optional (`required: false`).
76    DerivedWithDefault {
77        /// The name of the input to read the output name from.
78        input_name: &'static str,
79        /// The fallback name used when the input is absent.
80        default: &'static str,
81    },
82}
83
84/// Where an [`OutputSpec`]'s runtime value is written.
85///
86/// Global outputs are merged into the runtime [`Store`](crate::prelude::Store)
87/// and become visible to every subsequent step and return block.
88/// Operation-scoped outputs are visible only within the current step
89/// — callers read them from
90/// [`HookEvent::AfterStep`](crate::extend::HookEvent) but they do not
91/// persist.
92#[derive(Debug, Clone, PartialEq)]
93pub enum OutputScope {
94    /// Visible to every subsequent step and return block.
95    Global,
96    /// Visible only for the duration of the current step.
97    Operation,
98}
99
100/// A declared extension requirement on an [`OperationMetadata`].
101#[derive(Debug, Clone)]
102pub struct ExtensionSpec {
103    /// How the runtime name of the required extension is determined.
104    pub name: NameSpec,
105    /// A human-readable description of what the operation needs from
106    /// the extension.
107    pub description: &'static str,
108    /// A factory that produces the [`TypeId`] of the extension type.
109    /// Stored as a function rather than a value because `TypeId::of`
110    /// is only `const` on recent compilers.
111    pub type_id: fn() -> TypeId,
112}