Skip to main content

BoundValidationContext

Struct BoundValidationContext 

Source
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>

Source

pub fn new(values: &'a [ValidationValue<'a>]) -> Self

Creates a context with root paths for each dependency slot.

Examples found in repository?
examples/local_registry.rs (line 160)
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
Hide additional examples
examples/validate_named_bench.rs (line 181)
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}
Source

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?
examples/validate_named_bench.rs (line 188)
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}
Source

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?
examples/local_registry.rs (line 101)
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    }
Source

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.

Source

pub fn typed<T: 'static>(&self, index: usize) -> Result<&'a T, ExecutionError>

Downcasts a required dependency to its exact type.

§Type Parameters
  • T: Concrete dependency type to borrow; it must be 'static for Any downcasting.
§Errors

Returns a shape, missing-value, or slot error.

§Returns

Returns a borrow of the value when it has concrete type T.

Source

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 'static for Any downcasting.
§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.

Source

pub fn text(&self, index: usize) -> Result<&'a str, ExecutionError>

Borrows a required text dependency.

§Errors

Returns a shape, missing-value, or slot error.

§Returns

Returns the borrowed text dependency.

Trait Implementations§

Source§

impl Debug for BoundValidationContext<'_>

Source§

fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult

Formats only the slot count so dependency values remain private.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.