1
- use ahash :: AHashSet ;
1
+ use std :: collections :: HashSet ;
2
2
use std:: fmt:: Debug ;
3
+ use std:: hash:: BuildHasherDefault ;
3
4
4
5
use enum_dispatch:: enum_dispatch;
6
+ use nohash_hasher:: NoHashHasher ;
5
7
6
8
use pyo3:: exceptions:: PyRecursionError ;
7
9
use pyo3:: prelude:: * ;
@@ -75,19 +77,24 @@ impl SchemaValidator {
75
77
}
76
78
77
79
pub fn validate_python ( & self , py : Python , input : & PyAny ) -> PyResult < PyObject > {
78
- let mut recursion_guard = RecursionGuard :: new ( ) ;
79
- let r = self
80
- . validator
81
- . validate ( py, input, & Extra :: default ( ) , & self . slots , & mut recursion_guard) ;
80
+ let r = self . validator . validate (
81
+ py,
82
+ input,
83
+ & Extra :: default ( ) ,
84
+ & self . slots ,
85
+ & mut RecursionGuard :: default ( ) ,
86
+ ) ;
82
87
r. map_err ( |e| self . prepare_validation_err ( py, e) )
83
88
}
84
89
85
90
pub fn isinstance_python ( & self , py : Python , input : & PyAny ) -> PyResult < bool > {
86
- let mut recursion_guard = RecursionGuard :: new ( ) ;
87
- match self
88
- . validator
89
- . validate ( py, input, & Extra :: default ( ) , & self . slots , & mut recursion_guard)
90
- {
91
+ match self . validator . validate (
92
+ py,
93
+ input,
94
+ & Extra :: default ( ) ,
95
+ & self . slots ,
96
+ & mut RecursionGuard :: default ( ) ,
97
+ ) {
91
98
Ok ( _) => Ok ( true ) ,
92
99
Err ( ValError :: InternalErr ( err) ) => Err ( err) ,
93
100
_ => Ok ( false ) ,
@@ -97,10 +104,13 @@ impl SchemaValidator {
97
104
pub fn validate_json ( & self , py : Python , input : String ) -> PyResult < PyObject > {
98
105
match parse_json :: < JsonInput > ( & input) {
99
106
Ok ( input) => {
100
- let mut recursion_guard = RecursionGuard :: new ( ) ;
101
- let r = self
102
- . validator
103
- . validate ( py, & input, & Extra :: default ( ) , & self . slots , & mut recursion_guard) ;
107
+ let r = self . validator . validate (
108
+ py,
109
+ & input,
110
+ & Extra :: default ( ) ,
111
+ & self . slots ,
112
+ & mut RecursionGuard :: default ( ) ,
113
+ ) ;
104
114
r. map_err ( |e| self . prepare_validation_err ( py, e) )
105
115
}
106
116
Err ( e) => {
@@ -118,11 +128,13 @@ impl SchemaValidator {
118
128
pub fn isinstance_json ( & self , py : Python , input : String ) -> PyResult < bool > {
119
129
match parse_json :: < JsonInput > ( & input) {
120
130
Ok ( input) => {
121
- let mut recursion_guard = RecursionGuard :: new ( ) ;
122
- match self
123
- . validator
124
- . validate ( py, & input, & Extra :: default ( ) , & self . slots , & mut recursion_guard)
125
- {
131
+ match self . validator . validate (
132
+ py,
133
+ & input,
134
+ & Extra :: default ( ) ,
135
+ & self . slots ,
136
+ & mut RecursionGuard :: default ( ) ,
137
+ ) {
126
138
Ok ( _) => Ok ( true ) ,
127
139
Err ( ValError :: InternalErr ( err) ) => Err ( err) ,
128
140
_ => Ok ( false ) ,
@@ -137,10 +149,9 @@ impl SchemaValidator {
137
149
data : Some ( data) ,
138
150
field : Some ( field. as_str ( ) ) ,
139
151
} ;
140
- let mut recursion_guard = RecursionGuard :: new ( ) ;
141
152
let r = self
142
153
. validator
143
- . validate ( py, input, & extra, & self . slots , & mut recursion_guard ) ;
154
+ . validate ( py, input, & extra, & self . slots , & mut RecursionGuard :: default ( ) ) ;
144
155
r. map_err ( |e| self . prepare_validation_err ( py, e) )
145
156
}
146
157
@@ -353,7 +364,40 @@ pub enum CombinedValidator {
353
364
FrozenSet ( frozenset:: FrozenSetValidator ) ,
354
365
}
355
366
356
- pub type RecursionGuard = AHashSet < usize > ;
367
+ #[ derive( Debug , Clone , Default ) ]
368
+ pub struct RecursionGuard ( Option < HashSet < usize , BuildHasherDefault < NoHashHasher < usize > > > > ) ;
369
+
370
+ impl RecursionGuard {
371
+ pub fn insert ( & mut self , id : usize ) {
372
+ match self . 0 {
373
+ Some ( ref mut set) => {
374
+ set. insert ( id) ;
375
+ }
376
+ None => {
377
+ let mut set: HashSet < usize , BuildHasherDefault < NoHashHasher < usize > > > =
378
+ HashSet :: with_capacity_and_hasher ( 10 , BuildHasherDefault :: default ( ) ) ;
379
+ set. insert ( id) ;
380
+ self . 0 = Some ( set) ;
381
+ }
382
+ } ;
383
+ }
384
+
385
+ pub fn remove ( & mut self , id : & usize ) {
386
+ match self . 0 {
387
+ Some ( ref mut set) => {
388
+ set. remove ( id) ;
389
+ }
390
+ None => unreachable ! ( ) ,
391
+ } ;
392
+ }
393
+
394
+ pub fn contains ( & self , id : & usize ) -> bool {
395
+ match self . 0 {
396
+ Some ( ref set) => set. contains ( id) ,
397
+ None => false ,
398
+ }
399
+ }
400
+ }
357
401
358
402
/// This trait must be implemented by all validators, it allows various validators to be accessed consistently,
359
403
/// validators defined in `build_validator` also need `EXPECTED_TYPE` as a const, but that can't be part of the trait
0 commit comments