Skip to content

Commit 1382deb

Browse files
authored
Special case bool literals (#784)
1 parent fe9a462 commit 1382deb

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

src/validators/literal.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,19 @@ use crate::tools::SchemaDict;
1515

1616
use super::{BuildValidator, CombinedValidator, Definitions, DefinitionsBuilder, Extra, Validator};
1717

18+
#[derive(Debug, Clone)]
19+
struct BoolLiteral {
20+
pub true_id: Option<usize>,
21+
pub false_id: Option<usize>,
22+
}
23+
1824
#[derive(Debug, Clone)]
1925
pub struct LiteralLookup<T: Clone + Debug> {
20-
// Specialized lookups for ints and strings because they
26+
// Specialized lookups for ints, bools and strings because they
2127
// (1) are easy to convert between Rust and Python
2228
// (2) hashing them in Rust is very fast
2329
// (3) are the most commonly used things in Literal[...]
30+
expected_bool: Option<BoolLiteral>,
2431
expected_int: Option<AHashMap<i64, usize>>,
2532
expected_str: Option<AHashMap<String, usize>>,
2633
// Catch all for Enum and bytes (the latter only because it is seldom used)
@@ -31,12 +38,23 @@ pub struct LiteralLookup<T: Clone + Debug> {
3138
impl<T: Clone + Debug> LiteralLookup<T> {
3239
pub fn new<'py>(py: Python<'py>, expected: impl Iterator<Item = (&'py PyAny, T)>) -> PyResult<Self> {
3340
let mut expected_int = AHashMap::new();
34-
let mut expected_str = AHashMap::new();
41+
let mut expected_str: AHashMap<String, usize> = AHashMap::new();
42+
let mut expected_bool = BoolLiteral {
43+
true_id: None,
44+
false_id: None,
45+
};
3546
let expected_py = PyDict::new(py);
3647
let mut values = Vec::new();
3748
for (k, v) in expected {
3849
let id = values.len();
3950
values.push(v);
51+
if let Ok(bool) = k.strict_bool() {
52+
if bool {
53+
expected_bool.true_id = Some(id);
54+
} else {
55+
expected_bool.false_id = Some(id);
56+
}
57+
}
4058
if let Ok(either_int) = k.exact_int() {
4159
let int = either_int
4260
.into_i64(py)
@@ -53,6 +71,10 @@ impl<T: Clone + Debug> LiteralLookup<T> {
5371
}
5472

5573
Ok(Self {
74+
expected_bool: match expected_bool.true_id.is_some() || expected_bool.false_id.is_some() {
75+
true => Some(expected_bool),
76+
false => None,
77+
},
5678
expected_int: match expected_int.is_empty() {
5779
true => None,
5880
false => Some(expected_int),
@@ -74,7 +96,17 @@ impl<T: Clone + Debug> LiteralLookup<T> {
7496
py: Python<'data>,
7597
input: &'data I,
7698
) -> ValResult<'data, Option<(&'data I, &T)>> {
77-
// dbg!(input.to_object(py).as_ref(py).repr().unwrap());
99+
if let Some(expected_bool) = &self.expected_bool {
100+
if let Ok(bool_value) = input.strict_bool() {
101+
if bool_value {
102+
if let Some(true_value) = &expected_bool.true_id {
103+
return Ok(Some((input, &self.values[*true_value])));
104+
}
105+
} else if let Some(false_value) = &expected_bool.false_id {
106+
return Ok(Some((input, &self.values[*false_value])));
107+
}
108+
}
109+
}
78110
if let Some(expected_ints) = &self.expected_int {
79111
if let Ok(either_int) = input.exact_int() {
80112
let int = either_int.into_i64(py)?;

0 commit comments

Comments
 (0)