When adding {field-name}: Option<&'a dyn Fn(T) -> Result<...> + Send + Sync>
to a struct type, lifetime requirements cause the program to fail (playground link at bottom of post):
(Problem field pub validators: Option<Vec<&'a Validator<T>>>,
(comment it on and off to see the issue))
use std::fmt::{Display};
use std::borrow::Cow;
/// Represent some scalar values for test.
///
trait InputValue: Copy + Default + Display + PartialEq + PartialOrd {}
impl InputValue for isize {}
impl InputValue for usize {}
impl InputValue for &str {}
// ...
// Set up some types
// ----
type ViolationMessage = String;
type ValidationResult = Result<(), Vec<ViolationMessage>>;
type Validator<T> = dyn Fn(T) -> ValidationResult + Send + Sync;
/// Used for input validation
trait InputConstraints<T>
where T: InputValue {
fn _validate_t_strategy_1(&self, t: T) -> ValidationResult {
println!("Incoming value: {}", t);
Ok(())
}
fn validate(&self, value: Option<T>) -> ValidationResult {
self._validate_t_strategy_1(value.unwrap())
}
}
/// Extends `InputConstraints` in order to be used for validation;
/// Instances expected to be long lived.
struct Input<'a, T>
where T: InputValue
{
pub validators: Option<Vec<&'a Validator<T>>>,
}
impl<'a, T> InputConstraints<T> for Input<'a, T>
where T: InputValue {}
/// Faux data model, for validation test
struct SomeModel {
name: String
}
impl SomeModel {
fn validate(&self, rules: &InputRules) -> ValidationResult {
// mimick some lifetime redirection
some_deep_ctx_validate_model_name(rules, self.name.as_str())
}
}
fn some_deep_ctx_validate_model_name(rules: &InputRules, name: &str) -> ValidationResult {
rules.name.validate(Some(name))
}
struct InputRules<'a, 'b> {
name: Input<'a, &'b str>
}
fn app_runtime_ctx(rules: &InputRules, data: String) {
let model = SomeModel {
name: data,
};
model.validate(&rules);
}
fn main() {
let rule: Input<&str> = Input {
validators: None
};
let rules = InputRules {
name: rule,
};
app_runtime_ctx(&rules, "Hello".to_string())
}
Errors:
Compiling playground v0.0.1 (/playground)
warning: unused import: `std::borrow::Cow`
--> src/main.rs:2:5
|
2 | use std::borrow::Cow;
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error: lifetime may not live long enough
--> src/main.rs:59:5
|
58 | fn some_deep_ctx_validate_model_name(rules: &InputRules, name: &str) -> ValidationResult {
| ----- - let's call the lifetime of this reference `'1`
| |
| has type `&InputRules<'_, '2>`
59 | rules.name.validate(Some(name))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
warning: `playground` (bin "playground") generated 1 warning
error: could not compile `playground` (bin "playground") due to 1 previous error; 1 warning emitted