-
Notifications
You must be signed in to change notification settings - Fork 233
/
recursive.rs
121 lines (103 loc) · 3.79 KB
/
recursive.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::sync::{Arc, RwLock, Weak};
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use pyo3::types::PyDict;
use crate::build_tools::{py_error, SchemaDict};
use crate::errors::{as_internal, ValResult};
use crate::input::Input;
use super::{build_validator, Extra, Validator};
pub type ValidatorArc = Arc<RwLock<Box<dyn Validator>>>;
#[derive(Debug, Clone)]
pub struct RecursiveValidator {
validator_arc: ValidatorArc,
name: String,
}
impl RecursiveValidator {
pub const EXPECTED_TYPE: &'static str = "recursive-container";
}
impl Validator for RecursiveValidator {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
let sub_schema: &PyAny = schema.get_as_req("schema")?;
let validator = build_validator(sub_schema, config)?.0;
let name: String = schema.get_as_req("name")?;
let validator_arc = Arc::new(RwLock::new(validator));
match validator_arc.write() {
Ok(mut validator_guard) => validator_guard.set_ref(name.as_str(), &validator_arc),
Err(err) => py_error!("Recursive container build error: {}", err),
}?;
Ok(Box::new(Self { validator_arc, name }))
}
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
input: &'data dyn Input,
extra: &Extra,
) -> ValResult<'data, PyObject> {
match self.validator_arc.read() {
Ok(validator) => validator.validate(py, input, extra),
Err(err) => {
py_error!(PyRuntimeError; "Recursive container error: {}", err.to_string()).map_err(as_internal)
}
}
}
fn set_ref(&mut self, name: &str, validator_arc: &ValidatorArc) -> PyResult<()> {
match self.validator_arc.write() {
Ok(mut validator_guard) => validator_guard.set_ref(name, validator_arc),
Err(err) => py_error!("Recursive container set_ref error: {}", err),
}
}
fn get_name(&self, _py: Python) -> String {
self.name.clone()
}
#[no_coverage]
fn clone_dyn(&self) -> Box<dyn Validator> {
Box::new(self.clone())
}
}
#[derive(Debug, Clone)]
pub struct RecursiveRefValidator {
validator_ref: Option<Weak<RwLock<Box<dyn Validator>>>>,
name: String,
}
impl RecursiveRefValidator {
pub const EXPECTED_TYPE: &'static str = "recursive-ref";
}
impl Validator for RecursiveRefValidator {
fn build(schema: &PyDict, _config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self {
validator_ref: None,
name: schema.get_as_req("name")?,
}))
}
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
input: &'data dyn Input,
extra: &Extra,
) -> ValResult<'data, PyObject> {
let error_msg: String = match self.validator_ref {
Some(ref validator_ref) => match validator_ref.upgrade() {
Some(validator_arc) => match validator_arc.read() {
Ok(validator) => return validator.validate(py, input, extra),
Err(err) => format!("PoisonError: {}", err),
},
None => "unable to upgrade weak reference".to_string(),
},
None => "ref not yet set".to_string(),
};
py_error!(PyRuntimeError; "Recursive reference error: {}", error_msg).map_err(as_internal)
}
fn set_ref(&mut self, name: &str, validator_arc: &ValidatorArc) -> PyResult<()> {
if self.validator_ref.is_none() && name == self.name.as_str() {
self.validator_ref = Some(Arc::downgrade(validator_arc));
}
Ok(())
}
fn get_name(&self, _py: Python) -> String {
self.name.clone()
}
#[no_coverage]
fn clone_dyn(&self) -> Box<dyn Validator> {
Box::new(self.clone())
}
}