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}