pub struct BoundValidationContext<'a> { /* private fields */ }Expand description
Borrowed dependency slots used during a synchronous validation call.
Optional paths are stored in slot order exactly as supplied by the caller.
This type does not infer a coordinate system or add the current target’s
path. When paths are omitted, Self::dependency_path returns the root
path as a default location; that does not identify the target or report
root.
§Examples
use qubit_validator::{BoundValidationContext, ValidationValue};
let owner = String::from("member@example.test");
let values = [ValidationValue::Text(&owner)];
let context = BoundValidationContext::new(&values);
assert_eq!(context.text(0)?, "member@example.test");Implementations§
Source§impl<'a> BoundValidationContext<'a>
impl<'a> BoundValidationContext<'a>
Sourcepub fn new(values: &'a [ValidationValue<'a>]) -> Self
pub fn new(values: &'a [ValidationValue<'a>]) -> Self
Creates a context with root paths for each dependency slot.
Examples found in repository?
150fn main() -> Result<(), Box<dyn Error>> {
151 let registration = ValidatorRegistration::new(
152 ValidatorId::new("text.non_blank"),
153 &DESCRIPTOR,
154 RegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
155 );
156 let registry = ValidatorRegistry::from_registrations([registration])?;
157
158 assert!(registry.get("text.non_blank").is_some());
159 let validator = registry.bind("text.non_blank", InputType::Text, &[])?;
160 let context = BoundValidationContext::new(&[]);
161
162 let valid = validator.validate(ValidationValue::Text("Ada"), &context)?;
163 assert_eq!(valid, ValidationOutcome::Valid);
164
165 let invalid = validator.validate(ValidationValue::Text(" "), &context)?;
166 let ValidationOutcome::Invalid(violations) = invalid else {
167 panic!("blank text must be invalid");
168 };
169 assert_eq!(violations.len(), 1);
170 assert_eq!(violations[0].code(), ViolationCode::new("text.blank"));
171
172 assert_dependency_specs_come_from_signature()?;
173 assert_parameters_are_consumed_once()?;
174
175 #[cfg(feature = "inventory")]
176 {
177 let global = ValidatorRegistry::try_global()?;
178 assert!(global.get("text.non_blank.global").is_some());
179 }
180
181 Ok(())
182}More examples
168fn main() {
169 let b0 = V0.bind(ValidatorId::new("bench.zero"), 0, &[]).unwrap();
170 let b1 = V1.bind(ValidatorId::new("bench.one"), 0, &[]).unwrap();
171 let b4 = V4.bind(ValidatorId::new("bench.four"), 0, &[]).unwrap();
172 let b8 = V8.bind(ValidatorId::new("bench.eight"), 0, &[]).unwrap();
173 let b9 = V9.bind(ValidatorId::new("bench.nine"), 0, &[]).unwrap();
174 let number = 7_u64;
175 let value = ValidationValue::Typed(&number);
176 let path = ValidationPath::root().with_field("sample");
177 let tail_path = ValidationPath::root().with_field("tail");
178
179 let empty_named: [NamedValidationDependency<'_>; 0] = [];
180 let empty_values: [ValidationValue<'_>; 0] = [];
181 run_case("zero", &b0, &empty_named, &BoundValidationContext::new(&empty_values));
182
183 let one_named = [NamedValidationDependency::new("a", value)];
184 let one_values = [value];
185 run_case("one_plain", &b1, &one_named, &BoundValidationContext::new(&one_values));
186 let one_named_path = [NamedValidationDependency::new("a", value).with_path(&path)];
187 let one_paths = [path.clone()];
188 let one_context = BoundValidationContext::new_with_paths(&one_values, &one_paths).unwrap();
189 run_case("one_path", &b1, &one_named_path, &one_context);
190
191 let four_named = [
192 NamedValidationDependency::new("a", value),
193 NamedValidationDependency::new("b", value),
194 NamedValidationDependency::new("c", value),
195 NamedValidationDependency::new("d", value),
196 ];
197 let four_values = [value; 4];
198 run_case(
199 "four_plain",
200 &b4,
201 &four_named,
202 &BoundValidationContext::new(&four_values),
203 );
204 let four_named_path = [
205 NamedValidationDependency::new("a", value).with_path(&path),
206 NamedValidationDependency::new("b", value).with_path(&path),
207 NamedValidationDependency::new("c", value).with_path(&path),
208 NamedValidationDependency::new("d", value).with_path(&path),
209 ];
210 let four_paths = [path.clone(), path.clone(), path.clone(), path.clone()];
211 let four_context = BoundValidationContext::new_with_paths(&four_values, &four_paths).unwrap();
212 run_case("four_path", &b4, &four_named_path, &four_context);
213
214 let eight_named = [
215 NamedValidationDependency::new("h", value),
216 NamedValidationDependency::new("g", value),
217 NamedValidationDependency::new("f", value),
218 NamedValidationDependency::new("e", value),
219 NamedValidationDependency::new("d", value),
220 NamedValidationDependency::new("c", value),
221 NamedValidationDependency::new("b", value),
222 NamedValidationDependency::new("a", value),
223 ];
224 let eight_values = [value; 8];
225 let eight_context = BoundValidationContext::new(&eight_values);
226 run_case("eight_plain", &b8, &eight_named, &eight_context);
227 let eight_named_mixed = [
228 NamedValidationDependency::new("h", value).with_path(&path),
229 NamedValidationDependency::new("g", value),
230 NamedValidationDependency::new("f", value),
231 NamedValidationDependency::new("e", value),
232 NamedValidationDependency::new("d", value),
233 NamedValidationDependency::new("c", value),
234 NamedValidationDependency::new("b", value),
235 NamedValidationDependency::new("a", value).with_path(&tail_path),
236 ];
237 let eight_paths = [
238 tail_path.clone(),
239 ValidationPath::root(),
240 ValidationPath::root(),
241 ValidationPath::root(),
242 ValidationPath::root(),
243 ValidationPath::root(),
244 ValidationPath::root(),
245 path.clone(),
246 ];
247 let eight_context = BoundValidationContext::new_with_paths(&eight_values, &eight_paths).unwrap();
248 run_case("eight_mixed_path", &b8, &eight_named_mixed, &eight_context);
249
250 let nine_named = [
251 NamedValidationDependency::new("i", value),
252 NamedValidationDependency::new("h", value),
253 NamedValidationDependency::new("g", value),
254 NamedValidationDependency::new("f", value),
255 NamedValidationDependency::new("e", value),
256 NamedValidationDependency::new("d", value),
257 NamedValidationDependency::new("c", value),
258 NamedValidationDependency::new("b", value),
259 NamedValidationDependency::new("a", value),
260 ];
261 let nine_values = [value; 9];
262 let nine_context = BoundValidationContext::new(&nine_values);
263 run_case("nine_plain", &b9, &nine_named, &nine_context);
264 let nine_named_mixed = [
265 NamedValidationDependency::new("i", value).with_path(&path),
266 NamedValidationDependency::new("h", value),
267 NamedValidationDependency::new("g", value),
268 NamedValidationDependency::new("f", value),
269 NamedValidationDependency::new("e", value),
270 NamedValidationDependency::new("d", value),
271 NamedValidationDependency::new("c", value),
272 NamedValidationDependency::new("b", value),
273 NamedValidationDependency::new("a", value).with_path(&tail_path),
274 ];
275 let nine_paths = [
276 tail_path.clone(),
277 ValidationPath::root(),
278 ValidationPath::root(),
279 ValidationPath::root(),
280 ValidationPath::root(),
281 ValidationPath::root(),
282 ValidationPath::root(),
283 ValidationPath::root(),
284 path.clone(),
285 ];
286 let nine_context = BoundValidationContext::new_with_paths(&nine_values, &nine_paths).unwrap();
287 run_case("nine_mixed_path", &b9, &nine_named_mixed, &nine_context);
288}Sourcepub fn new_with_paths(
values: &'a [ValidationValue<'a>],
paths: &'a [ValidationPath],
) -> Result<Self, ExecutionError>
pub fn new_with_paths( values: &'a [ValidationValue<'a>], paths: &'a [ValidationPath], ) -> Result<Self, ExecutionError>
Creates a context with caller-supplied dependency paths.
Paths are associated with values by slot index and kept unchanged. The caller chooses their coordinate system; this method does not add a current-target prefix.
§Examples
use qubit_validator::{BoundValidationContext, ValidationPath, ValidationValue};
let values = [ValidationValue::Text("ada@example.test")];
let paths = [ValidationPath::root().with_field("profile").with_field("email")];
let context = BoundValidationContext::new_with_paths(&values, &paths)?;
assert_eq!(context.dependency_path(0)?.render(), "profile.email");§Errors
Returns an adapter contract error when the two slices differ in length.
§Returns
Returns a context whose values and paths occupy matching slots.
Examples found in repository?
168fn main() {
169 let b0 = V0.bind(ValidatorId::new("bench.zero"), 0, &[]).unwrap();
170 let b1 = V1.bind(ValidatorId::new("bench.one"), 0, &[]).unwrap();
171 let b4 = V4.bind(ValidatorId::new("bench.four"), 0, &[]).unwrap();
172 let b8 = V8.bind(ValidatorId::new("bench.eight"), 0, &[]).unwrap();
173 let b9 = V9.bind(ValidatorId::new("bench.nine"), 0, &[]).unwrap();
174 let number = 7_u64;
175 let value = ValidationValue::Typed(&number);
176 let path = ValidationPath::root().with_field("sample");
177 let tail_path = ValidationPath::root().with_field("tail");
178
179 let empty_named: [NamedValidationDependency<'_>; 0] = [];
180 let empty_values: [ValidationValue<'_>; 0] = [];
181 run_case("zero", &b0, &empty_named, &BoundValidationContext::new(&empty_values));
182
183 let one_named = [NamedValidationDependency::new("a", value)];
184 let one_values = [value];
185 run_case("one_plain", &b1, &one_named, &BoundValidationContext::new(&one_values));
186 let one_named_path = [NamedValidationDependency::new("a", value).with_path(&path)];
187 let one_paths = [path.clone()];
188 let one_context = BoundValidationContext::new_with_paths(&one_values, &one_paths).unwrap();
189 run_case("one_path", &b1, &one_named_path, &one_context);
190
191 let four_named = [
192 NamedValidationDependency::new("a", value),
193 NamedValidationDependency::new("b", value),
194 NamedValidationDependency::new("c", value),
195 NamedValidationDependency::new("d", value),
196 ];
197 let four_values = [value; 4];
198 run_case(
199 "four_plain",
200 &b4,
201 &four_named,
202 &BoundValidationContext::new(&four_values),
203 );
204 let four_named_path = [
205 NamedValidationDependency::new("a", value).with_path(&path),
206 NamedValidationDependency::new("b", value).with_path(&path),
207 NamedValidationDependency::new("c", value).with_path(&path),
208 NamedValidationDependency::new("d", value).with_path(&path),
209 ];
210 let four_paths = [path.clone(), path.clone(), path.clone(), path.clone()];
211 let four_context = BoundValidationContext::new_with_paths(&four_values, &four_paths).unwrap();
212 run_case("four_path", &b4, &four_named_path, &four_context);
213
214 let eight_named = [
215 NamedValidationDependency::new("h", value),
216 NamedValidationDependency::new("g", value),
217 NamedValidationDependency::new("f", value),
218 NamedValidationDependency::new("e", value),
219 NamedValidationDependency::new("d", value),
220 NamedValidationDependency::new("c", value),
221 NamedValidationDependency::new("b", value),
222 NamedValidationDependency::new("a", value),
223 ];
224 let eight_values = [value; 8];
225 let eight_context = BoundValidationContext::new(&eight_values);
226 run_case("eight_plain", &b8, &eight_named, &eight_context);
227 let eight_named_mixed = [
228 NamedValidationDependency::new("h", value).with_path(&path),
229 NamedValidationDependency::new("g", value),
230 NamedValidationDependency::new("f", value),
231 NamedValidationDependency::new("e", value),
232 NamedValidationDependency::new("d", value),
233 NamedValidationDependency::new("c", value),
234 NamedValidationDependency::new("b", value),
235 NamedValidationDependency::new("a", value).with_path(&tail_path),
236 ];
237 let eight_paths = [
238 tail_path.clone(),
239 ValidationPath::root(),
240 ValidationPath::root(),
241 ValidationPath::root(),
242 ValidationPath::root(),
243 ValidationPath::root(),
244 ValidationPath::root(),
245 path.clone(),
246 ];
247 let eight_context = BoundValidationContext::new_with_paths(&eight_values, &eight_paths).unwrap();
248 run_case("eight_mixed_path", &b8, &eight_named_mixed, &eight_context);
249
250 let nine_named = [
251 NamedValidationDependency::new("i", value),
252 NamedValidationDependency::new("h", value),
253 NamedValidationDependency::new("g", value),
254 NamedValidationDependency::new("f", value),
255 NamedValidationDependency::new("e", value),
256 NamedValidationDependency::new("d", value),
257 NamedValidationDependency::new("c", value),
258 NamedValidationDependency::new("b", value),
259 NamedValidationDependency::new("a", value),
260 ];
261 let nine_values = [value; 9];
262 let nine_context = BoundValidationContext::new(&nine_values);
263 run_case("nine_plain", &b9, &nine_named, &nine_context);
264 let nine_named_mixed = [
265 NamedValidationDependency::new("i", value).with_path(&path),
266 NamedValidationDependency::new("h", value),
267 NamedValidationDependency::new("g", value),
268 NamedValidationDependency::new("f", value),
269 NamedValidationDependency::new("e", value),
270 NamedValidationDependency::new("d", value),
271 NamedValidationDependency::new("c", value),
272 NamedValidationDependency::new("b", value),
273 NamedValidationDependency::new("a", value).with_path(&tail_path),
274 ];
275 let nine_paths = [
276 tail_path.clone(),
277 ValidationPath::root(),
278 ValidationPath::root(),
279 ValidationPath::root(),
280 ValidationPath::root(),
281 ValidationPath::root(),
282 ValidationPath::root(),
283 ValidationPath::root(),
284 path.clone(),
285 ];
286 let nine_context = BoundValidationContext::new_with_paths(&nine_values, &nine_paths).unwrap();
287 run_case("nine_mixed_path", &b9, &nine_named_mixed, &nine_context);
288}Sourcepub fn value(&self, index: usize) -> Result<ValidationValue<'a>, ExecutionError>
pub fn value(&self, index: usize) -> Result<ValidationValue<'a>, ExecutionError>
Returns the value at an ordered dependency slot.
§Errors
Returns an adapter contract error for an invalid slot index.
§Returns
Returns a copy of the value stored at index.
Examples found in repository?
96 fn validate(
97 &self,
98 _: ValidationValue<'_>,
99 context: &BoundValidationContext<'_>,
100 ) -> Result<PreparedOutcome, ExecutionError> {
101 let valid = context.value(0)?.as_text() == Some("minimum") && context.value(1)?.as_text() == Some("maximum");
102 Ok(if valid {
103 PreparedOutcome::Valid
104 } else {
105 PreparedOutcome::Invalid(vec![ViolationDraft::new(ViolationCode::new(
106 "text.dependencies_mismatch",
107 ))])
108 })
109 }Sourcepub fn dependency_path(
&self,
index: usize,
) -> Result<&ValidationPath, ExecutionError>
pub fn dependency_path( &self, index: usize, ) -> Result<&ValidationPath, ExecutionError>
Returns the path at an ordered dependency slot.
§Errors
Returns an adapter contract error for an invalid slot index.
§Returns
Returns the stored path unchanged, or the root path when no paths were supplied. The default root is only a fallback location and does not establish that the dependency is the current target.
Sourcepub fn optional_typed<T: 'static>(
&self,
index: usize,
) -> Result<Option<&'a T>, ExecutionError>
pub fn optional_typed<T: 'static>( &self, index: usize, ) -> Result<Option<&'a T>, ExecutionError>
Downcasts an optional dependency, treating only Missing as None.
§Type Parameters
T: Concrete dependency type to borrow; it must be'staticforAnydowncasting.
§Returns
Returns Some with a correctly typed present value, or None for the
explicit missing marker.
§Errors
Returns a shape or slot error. A wrong concrete type is never treated as an absent optional value.