qubit_validator/registry/validator_signature.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9//! Input and dependency signatures for validator definitions.
10
11use std::fmt::Debug;
12use std::fmt::Formatter;
13use std::fmt::Result as FmtResult;
14
15use crate::binding::DependencySpec;
16use crate::binding::InputType;
17use crate::binding::PrepareFn;
18
19/// One statically declared way to bind a validator.
20///
21/// # Examples
22///
23/// ```
24/// use std::sync::Arc;
25///
26/// use qubit_validator::ArgumentReader;
27/// use qubit_validator::BindError;
28/// use qubit_validator::BoundValidationContext;
29/// use qubit_validator::DependencySpec;
30/// use qubit_validator::ExecutionError;
31/// use qubit_validator::InputType;
32/// use qubit_validator::PreparedOutcome;
33/// use qubit_validator::PreparedValidator;
34/// use qubit_validator::ValidationValue;
35/// use qubit_validator::ValidatorSignature;
36///
37/// struct Accept;
38/// impl PreparedValidator for Accept {
39/// fn input_type(&self) -> InputType { InputType::Text }
40/// fn dependency_specs(&self) -> &'static [DependencySpec] { &[] }
41/// fn validate(
42/// &self,
43/// _: ValidationValue<'_>,
44/// _: &BoundValidationContext<'_>,
45/// ) -> Result<PreparedOutcome, ExecutionError> {
46/// Ok(PreparedOutcome::valid())
47/// }
48/// }
49/// fn prepare(_reader: &mut ArgumentReader<'_>) -> Result<Arc<dyn PreparedValidator>, BindError> {
50/// Ok(Arc::new(Accept))
51/// }
52///
53/// let signature = ValidatorSignature::new(InputType::Text, &[], prepare);
54/// assert_eq!(signature.input(), InputType::Text);
55/// assert!(signature.dependencies().is_empty());
56/// ```
57#[derive(Clone, Copy)]
58pub struct ValidatorSignature {
59 /// Erased input shape accepted by this signature.
60 input: InputType,
61 /// Ordered dependency slots required by the prepared validator.
62 dependencies: &'static [DependencySpec],
63 /// Factory which decodes parameters and creates the prepared validator.
64 prepare: PrepareFn,
65}
66
67impl ValidatorSignature {
68 /// Creates a signature with ordered dependency slots.
69 ///
70 /// # Parameters
71 ///
72 /// - `input`: Erased input shape accepted by the validator.
73 /// - `dependencies`: Dependency slots passed to the prepared validator, in
74 /// order.
75 /// - `prepare`: Function that binds arguments and creates the prepared
76 /// validator.
77 ///
78 /// # Returns
79 ///
80 /// A signature containing the supplied input shape, dependencies, and
81 /// factory.
82 #[must_use]
83 #[inline]
84 pub const fn new(input: InputType, dependencies: &'static [DependencySpec], prepare: PrepareFn) -> Self {
85 Self {
86 input,
87 dependencies,
88 prepare,
89 }
90 }
91
92 /// Returns the accepted value shape.
93 ///
94 /// # Returns
95 ///
96 /// The erased input shape this signature accepts.
97 #[must_use]
98 #[inline]
99 pub const fn input(self) -> InputType {
100 self.input
101 }
102
103 /// Returns dependency declarations in slot order.
104 ///
105 /// # Returns
106 ///
107 /// The static dependency slice in the order passed to the prepared
108 /// validator.
109 #[must_use]
110 #[inline]
111 pub const fn dependencies(self) -> &'static [DependencySpec] {
112 self.dependencies
113 }
114
115 /// Returns the parameter binding function.
116 ///
117 /// # Returns
118 ///
119 /// The factory function that binds parameters and creates the prepared
120 /// validator.
121 #[must_use]
122 #[inline]
123 pub const fn prepare(self) -> PrepareFn {
124 self.prepare
125 }
126}
127
128impl Debug for ValidatorSignature {
129 /// Formats the input shape and dependency count without invoking the
130 /// factory.
131 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
132 formatter
133 .debug_struct("ValidatorSignature")
134 .field("input", &self.input)
135 .field("dependency_count", &self.dependencies.len())
136 .finish()
137 }
138}