Skip to content

Commit 2d533da

Browse files
committed
refactor: Rework unevaluatedItems
Signed-off-by: Dmitry Dygalo <[email protected]>
1 parent 2e17feb commit 2d533da

File tree

4 files changed

+520
-456
lines changed

4 files changed

+520
-456
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- Large schema compilation is significantly faster. [#755](https://github.com/Stranger6667/jsonschema/issues/755)
2424
- `unevaluatedProperties` validation is 25-35% faster through optimized property marking and early-exit paths.
2525
- `unevaluatedProperties` memory usage drastically reduced by eliminating redundant registry clones during compilation.
26+
- `unevaluatedItems` validation is ~10% faster through early-exit optimizations and eliminating redundant validations in combinators.
2627

2728
### Removed
2829

crates/jsonschema-py/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- Large schema compilation is significantly faster. [#755](https://github.com/Stranger6667/jsonschema/issues/755)
1818
- `unevaluatedProperties` validation is 25-35% faster through optimized property marking and early-exit paths.
1919
- `unevaluatedProperties` memory usage drastically reduced by eliminating redundant registry clones during compilation.
20+
- `unevaluatedItems` validation is ~10% faster through early-exit optimizations and eliminating redundant validations in combinators.
2021

2122
## [0.32.1] - 2025-08-24
2223

crates/jsonschema/src/compiler.rs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
self,
77
custom::{CustomKeyword, KeywordFactory},
88
format::Format,
9+
unevaluated_items::PendingItemsValidators,
910
unevaluated_properties::PendingPropertyValidators,
1011
BoxedValidator, BuiltinKeyword, Keyword,
1112
},
@@ -27,6 +28,11 @@ use std::{borrow::Cow, cell::RefCell, iter::once, rc::Rc, sync::Arc};
2728
const DEFAULT_SCHEME: &str = "json-schema";
2829
pub(crate) const DEFAULT_BASE_URI: &str = "json-schema:///";
2930

31+
/// Type alias for shared cache maps in compiler state.
32+
type SharedCache<K, V> = Rc<RefCell<AHashMap<K, V>>>;
33+
/// Type alias for shared sets in compiler state.
34+
type SharedSet<T> = Rc<RefCell<AHashSet<T>>>;
35+
3036
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
3137
pub(crate) struct LocationCacheKey {
3238
pub(crate) base_uri: Arc<Uri<String>>,
@@ -47,6 +53,19 @@ impl PropertyValidatorsPendingKey {
4753
}
4854
}
4955

56+
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
57+
struct ItemsValidatorsPendingKey {
58+
schema_ptr: usize,
59+
}
60+
61+
impl ItemsValidatorsPendingKey {
62+
fn new(schema: &Map<String, Value>) -> Self {
63+
Self {
64+
schema_ptr: schema as *const _ as usize,
65+
}
66+
}
67+
}
68+
5069
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
5170
pub(crate) struct AliasCacheKey {
5271
uri: Arc<Uri<String>>,
@@ -56,15 +75,18 @@ pub(crate) struct AliasCacheKey {
5675
/// Shared caches reused across every `Context` derived from a schema root.
5776
#[derive(Debug, Clone)]
5877
struct SharedContextState {
59-
seen: Rc<RefCell<AHashSet<Arc<Uri<String>>>>>,
60-
location_nodes: Rc<RefCell<AHashMap<LocationCacheKey, SchemaNode>>>,
61-
alias_nodes: Rc<RefCell<AHashMap<AliasCacheKey, SchemaNode>>>,
62-
pending_nodes: Rc<RefCell<AHashMap<LocationCacheKey, PendingSchemaNode>>>,
63-
alias_placeholders: Rc<RefCell<AHashMap<Arc<Uri<String>>, PendingSchemaNode>>>,
64-
pending_property_validators: Rc<RefCell<AHashMap<LocationCacheKey, PendingPropertyValidators>>>,
78+
seen: SharedSet<Arc<Uri<String>>>,
79+
location_nodes: SharedCache<LocationCacheKey, SchemaNode>,
80+
alias_nodes: SharedCache<AliasCacheKey, SchemaNode>,
81+
pending_nodes: SharedCache<LocationCacheKey, PendingSchemaNode>,
82+
alias_placeholders: SharedCache<Arc<Uri<String>>, PendingSchemaNode>,
83+
pending_property_validators: SharedCache<LocationCacheKey, PendingPropertyValidators>,
6584
pending_property_validators_by_schema:
66-
Rc<RefCell<AHashMap<PropertyValidatorsPendingKey, PendingPropertyValidators>>>,
67-
pattern_cache: Rc<RefCell<AHashMap<Arc<str>, PatternCacheEntry>>>,
85+
SharedCache<PropertyValidatorsPendingKey, PendingPropertyValidators>,
86+
pending_items_validators: SharedCache<LocationCacheKey, PendingItemsValidators>,
87+
pending_items_validators_by_schema:
88+
SharedCache<ItemsValidatorsPendingKey, PendingItemsValidators>,
89+
pattern_cache: SharedCache<Arc<str>, PatternCacheEntry>,
6890
uri_buffer: Rc<RefCell<String>>,
6991
}
7092

@@ -85,6 +107,8 @@ impl SharedContextState {
85107
alias_placeholders: Rc::new(RefCell::new(AHashMap::new())),
86108
pending_property_validators: Rc::new(RefCell::new(AHashMap::new())),
87109
pending_property_validators_by_schema: Rc::new(RefCell::new(AHashMap::new())),
110+
pending_items_validators: Rc::new(RefCell::new(AHashMap::new())),
111+
pending_items_validators_by_schema: Rc::new(RefCell::new(AHashMap::new())),
88112
pattern_cache: Rc::new(RefCell::new(AHashMap::new())),
89113
uri_buffer: Rc::new(RefCell::new(String::new())),
90114
}
@@ -419,6 +443,33 @@ impl<'a> Context<'a> {
419443
.remove(&key);
420444
}
421445

446+
fn items_schema_key(schema: &Map<String, Value>) -> ItemsValidatorsPendingKey {
447+
ItemsValidatorsPendingKey::new(schema)
448+
}
449+
450+
pub(crate) fn get_pending_items_validators_for_schema(
451+
&self,
452+
schema: &Map<String, Value>,
453+
) -> Option<PendingItemsValidators> {
454+
let key = Self::items_schema_key(schema);
455+
self.shared
456+
.pending_items_validators_by_schema
457+
.borrow()
458+
.get(&key)
459+
.cloned()
460+
}
461+
462+
pub(crate) fn get_pending_items_validators(
463+
&self,
464+
key: &LocationCacheKey,
465+
) -> Option<PendingItemsValidators> {
466+
self.shared
467+
.pending_items_validators
468+
.borrow()
469+
.get(key)
470+
.cloned()
471+
}
472+
422473
pub(crate) fn cached_alias_placeholder(
423474
&self,
424475
alias: &Arc<Uri<String>>,

0 commit comments

Comments
 (0)