Skip to content

Commit 18f5fce

Browse files
committed
compress smart union implementation
1 parent 159a7ce commit 18f5fce

File tree

2 files changed

+39
-60
lines changed

2 files changed

+39
-60
lines changed

‎src/validators/union.rs‎

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -111,76 +111,55 @@ impl UnionValidator {
111111
let strict = state.strict_or(self.strict);
112112
let mut errors = MaybeErrors::new(self.custom_error.as_ref());
113113

114-
let mut strict_success = None;
115-
let mut lax_success = None;
116-
117-
if strict {
118-
// one-pass strict validation
119-
let state = &mut state.rebind_extra(|extra| extra.strict = Some(true));
120-
for (choice, label) in &self.choices {
121-
state.exactness = Some(Exactness::Exact);
122-
match choice.validate(py, input, state) {
123-
Ok(success) => {
124-
if state.exactness == Some(Exactness::Exact) {
114+
let mut success = None;
115+
116+
for (choice, label) in &self.choices {
117+
let state = &mut state.rebind_extra(|extra| {
118+
if strict {
119+
extra.strict = Some(strict);
120+
}
121+
});
122+
state.exactness = Some(Exactness::Exact);
123+
let result = choice.validate(py, input, state);
124+
match result {
125+
Ok(new_success) => match state.exactness {
126+
// exact match, return
127+
Some(Exactness::Exact) => {
128+
return {
125129
// exact match, return, restore any previous exactness
126130
state.exactness = old_exactness;
127-
return Ok(success);
128-
} else if strict_success.is_none() {
129-
// remember first success for later as a fallback
130-
// we know this must have been strict, because we ran strict validation
131-
strict_success = Some(success);
132-
}
131+
Ok(new_success)
132+
};
133133
}
134-
Err(ValError::LineErrors(lines)) => {
135-
// if we don't yet know this validation will succeed, record the error
136-
if strict_success.is_none() {
137-
errors.push(choice, label.as_deref(), lines);
134+
_ => {
135+
// success should always have an exactness
136+
debug_assert_ne!(state.exactness, None);
137+
let new_exactness = state.exactness.unwrap_or(Exactness::Lax);
138+
// if the new result has higher exactness than the current success, replace it
139+
if success
140+
.as_ref()
141+
.map_or(true, |(_, current_exactness)| *current_exactness < new_exactness)
142+
{
143+
// TODO: is there a possible optimization here, where once there has
144+
// been one success, we turn on strict mode, to avoid unnecessary
145+
// coercions for further validation?
146+
success = Some((new_success, new_exactness));
138147
}
139148
}
140-
otherwise => return otherwise,
141-
}
142-
}
143-
} else {
144-
// one-pass lax validation
145-
for (choice, label) in &self.choices {
146-
state.exactness = Some(Exactness::Exact);
147-
let result = choice.validate(py, input, state);
148-
match result {
149-
Ok(success) => match state.exactness {
150-
// exact match, return
151-
Some(Exactness::Exact) => return Ok(success),
152-
Some(Exactness::Strict) => {
153-
if strict_success.is_none() {
154-
strict_success = Some(success);
155-
}
156-
}
157-
_ => {
158-
// success should always have an exactness
159-
debug_assert_eq!(state.exactness, Some(Exactness::Lax));
160-
if lax_success.is_none() {
161-
lax_success = Some(success);
162-
}
163-
}
164-
},
165-
Err(ValError::LineErrors(lines)) => {
166-
// if we don't yet know this validation will succeed, record the error
167-
if strict_success.is_none() && lax_success.is_none() {
168-
errors.push(choice, label.as_deref(), lines);
169-
}
149+
},
150+
Err(ValError::LineErrors(lines)) => {
151+
// if we don't yet know this validation will succeed, record the error
152+
if success.is_none() {
153+
errors.push(choice, label.as_deref(), lines);
170154
}
171-
otherwise => return otherwise,
172155
}
156+
otherwise => return otherwise,
173157
}
174158
}
175159
state.exactness = old_exactness;
176160

177-
if let Some(success) = strict_success {
178-
state.floor_exactness(Exactness::Strict);
179-
return Ok(success);
180-
}
181-
182-
if let Some(success) = lax_success {
183-
state.floor_exactness(Exactness::Lax);
161+
if let Some((success, exactness)) = success {
162+
state.floor_exactness(exactness);
184163
return Ok(success);
185164
}
186165

‎src/validators/validation_state.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::recursion_guard::RecursionGuard;
22

33
use super::Extra;
44

5-
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
66
pub enum Exactness {
77
Lax,
88
Strict,

0 commit comments

Comments
 (0)