pub struct VirtualizerOptions<K = ItemKey> {Show 18 fields
pub count: usize,
pub estimate_size: Arc<dyn Fn(usize) -> u32 + Send + Sync>,
pub get_item_key: Arc<dyn Fn(usize) -> K + Send + Sync>,
pub range_extractor: Option<RangeExtractor>,
pub enabled: bool,
pub overscan: usize,
pub initial_rect: Option<Rect>,
pub padding_start: u32,
pub padding_end: u32,
pub scroll_padding_start: u32,
pub scroll_padding_end: u32,
pub scroll_margin: u32,
pub initial_offset: InitialOffset,
pub on_change: Option<OnChangeCallback<K>>,
pub use_scrollend_event: bool,
pub is_scrolling_reset_delay_ms: u64,
pub should_adjust_scroll_position_on_item_size_change: Option<ShouldAdjustScrollPositionOnItemSizeChangeCallback<K>>,
pub gap: u32,
}Expand description
Configuration for crate::Virtualizer.
This type is designed to be cheap to clone: heavy fields are stored in Arcs so adapters can
update a few fields and call Virtualizer::set_options without reallocating closures.
Fields§
§count: usize§estimate_size: Arc<dyn Fn(usize) -> u32 + Send + Sync>§get_item_key: Arc<dyn Fn(usize) -> K + Send + Sync>§range_extractor: Option<RangeExtractor>Optional index selection hook.
When set, the virtualizer will call this extractor to emit the final set of indexes to render. This is useful for pinned/sticky rows, section headers, etc.
The extractor receives the visible range (no overscan) plus overscan and count, and
must emit a sorted (ascending) sequence of indexes. Duplicates are allowed but ignored.
enabled: boolEnables/disables the virtualizer. When disabled, query methods return empty results.
overscan: usize§initial_rect: Option<Rect>The initial size of the scrollable area (aka TanStack Virtual initialRect).
This is a platform-agnostic rect where:
mainis the virtualized axis size (e.g. height for vertical lists)crossis the cross axis size (e.g. width for vertical lists)
padding_start: u32Padding before the first item.
padding_end: u32Padding after the last item.
scroll_padding_start: u32Additional padding applied when computing scroll-to offsets.
scroll_padding_end: u32Additional padding applied when computing scroll-to offsets.
scroll_margin: u32Where the list starts inside the scroll element (aka TanStack Virtual scrollMargin).
This is useful when the scroll offset is measured from a larger scroll container (e.g. window scrolling) while the list begins after some header/content.
initial_offset: InitialOffsetInitial scroll offset (aka TanStack Virtual initialOffset).
on_change: Option<OnChangeCallback<K>>Optional callback fired when the virtualizer’s internal state changes.
The sync argument indicates whether a scroll is in progress.
use_scrollend_event: boolDetermines whether to use a native scrollend event to detect when scrolling has stopped.
This is included for TanStack Virtual parity. In this crate, scrolling state is driven
by your adapter via set_is_scrolling/notify_scroll_event/update_scrolling.
is_scrolling_reset_delay_ms: u64Debounced fallback duration for resetting is_scrolling when use_scrollend_event is false.
should_adjust_scroll_position_on_item_size_change: Option<ShouldAdjustScrollPositionOnItemSizeChangeCallback<K>>Whether to adjust the scroll position when an item’s measured size differs from its estimate and the item is before the current scroll offset.
gap: u32Space between items.
Implementations§
Source§impl VirtualizerOptions<ItemKey>
impl VirtualizerOptions<ItemKey>
Sourcepub fn new(
count: usize,
estimate_size: impl Fn(usize) -> u32 + Send + Sync + 'static,
) -> Self
pub fn new( count: usize, estimate_size: impl Fn(usize) -> u32 + Send + Sync + 'static, ) -> Self
Creates options for a list keyed by index (ItemKey = u64).
estimate_size(i) should return the estimated item size in the scroll axis (e.g. row
height for vertical lists). The estimate is used until an item is measured.
Examples found in repository?
4fn main() {
5 let mut v = Virtualizer::new(VirtualizerOptions::new(1_000_000, |_| 1));
6 v.set_viewport_and_scroll(10, 123_456);
7
8 let mut items = Vec::new();
9 v.for_each_virtual_item(|it| items.push(it));
10 println!("total_size={}", v.total_size());
11 println!("visible_range={:?}", v.virtual_range());
12 println!("first_visible={:?}", items.first());
13
14 let off = v.scroll_to_index_offset(999_999, Align::End);
15 v.set_scroll_offset_clamped(off);
16 println!("after scroll_to_index: offset={}", v.scroll_offset());
17}More examples
4fn main() {
5 // Example: measurements follow keys after reorder.
6 let mut v = Virtualizer::new(VirtualizerOptions::new(2, |_| 1));
7 v.measure(0, 10);
8 println!(
9 "before reorder: size0={:?} size1={:?}",
10 v.item_size(0),
11 v.item_size(1)
12 );
13
14 // Simulate data reorder by changing the key mapping.
15 v.set_get_item_key(|i| if i == 0 { 1 } else { 0 });
16 // Note: in real apps you usually keep `get_item_key` stable and call `sync_item_keys()` when
17 // your underlying dataset is reordered while `count` stays the same.
18
19 println!(
20 "after reorder: size0={:?} size1={:?}",
21 v.item_size(0),
22 v.item_size(1)
23 );
24}4fn main() {
5 // Example: export and import measurement cache (key -> measured size).
6 //
7 // This is useful if you want to persist measurements across screens/sessions so that the
8 // virtualizer can start with better estimates and avoid re-measuring everything.
9 let mut v1 = Virtualizer::new(VirtualizerOptions::new(10, |_| 1));
10 v1.measure(2, 10);
11 v1.measure(5, 42);
12
13 let snapshot = v1.export_measurement_cache();
14 println!("exported_cache_len={}", snapshot.len());
15
16 let mut v2 = Virtualizer::new(VirtualizerOptions::new(10, |_| 1));
17 println!(
18 "before import: size2={:?} size5={:?}",
19 v2.item_size(2),
20 v2.item_size(5)
21 );
22
23 v2.import_measurement_cache(snapshot);
24 println!(
25 "after import: cache_len={} size2={:?} size5={:?}",
26 v2.measurement_cache_len(),
27 v2.item_size(2),
28 v2.item_size(5)
29 );
30}4fn main() {
5 // Example: dynamic measurement + scroll jump prevention.
6 let mut v = Virtualizer::new(VirtualizerOptions::new(100, |_| 10));
7 v.set_viewport_and_scroll_clamped(30, 200);
8
9 println!(
10 "before: off={} total={} range={:?}",
11 v.scroll_offset(),
12 v.total_size(),
13 v.virtual_range()
14 );
15
16 // If an item before the viewport changes size, `resize_item` can adjust scroll_offset to
17 // prevent visual jumps.
18 let applied = v.resize_item(0, 30);
19 println!(
20 "resize_item(0): applied_delta={applied} off={} total={}",
21 v.scroll_offset(),
22 v.total_size()
23 );
24
25 // Measuring an item updates sizes and may adjust scroll (TanStack-aligned behavior).
26 v.measure(1, 50);
27 println!(
28 "measure(1): off={} total={}",
29 v.scroll_offset(),
30 v.total_size()
31 );
32
33 // If you want to update measurements without changing scroll, use `measure_unadjusted`.
34 v.measure_unadjusted(2, 30);
35
36 // Scroll-to helpers still work with updated measurements.
37 let to = v.scroll_to_index_offset(10, Align::Start);
38 v.set_scroll_offset_clamped(to);
39 println!(
40 "set_scroll_offset_clamped(scroll_to_index_offset(10)): off={} range={:?}",
41 v.scroll_offset(),
42 v.virtual_range()
43 );
44}47fn main() {
48 // Simulate an adapter that drives scroll_offset with a tween.
49 let mut v = Virtualizer::new(VirtualizerOptions::new(10_000, |_| 1));
50 v.set_viewport_and_scroll_clamped(20, 0);
51
52 let to = v.scroll_to_index_offset(2_000, Align::Center);
53 let mut tween = Tween::new(v.scroll_offset(), to, 0, 240);
54
55 let mut now_ms = 0u64;
56 let mut frame = 0u64;
57
58 loop {
59 // Simulate a 60fps "tick".
60 now_ms = now_ms.saturating_add(16);
61 frame += 1;
62
63 // Adapter samples tween and writes it into the virtualizer.
64 let off = tween.sample(now_ms);
65 v.apply_scroll_offset_event_clamped(off, now_ms);
66
67 // Render: a UI would iterate items and draw them.
68 let mut first: Option<usize> = None;
69 let mut last: Option<usize> = None;
70 v.for_each_virtual_item(|it| {
71 first.get_or_insert(it.index);
72 last = Some(it.index);
73 });
74
75 if frame.is_multiple_of(5) {
76 println!(
77 "t={now_ms}ms off={} visible={:?} first={:?} last={:?}",
78 v.scroll_offset(),
79 v.visible_range(),
80 first,
81 last
82 );
83 }
84
85 // Simulate user input interrupting the animation:
86 // at ~120ms, retarget to a new index.
87 if (120..120 + 16).contains(&now_ms) {
88 let new_to = v.scroll_to_index_offset(7_500, Align::Start);
89 tween.retarget(now_ms, new_to, 300);
90 }
91
92 if tween.is_done(now_ms) {
93 break;
94 }
95 }
96
97 // Mark scroll as finished for adapters that use this state.
98 v.set_is_scrolling(false);
99
100 println!(
101 "done: off={} range={:?}",
102 v.scroll_offset(),
103 v.virtual_range()
104 );
105}6fn main() {
7 // Example: pinned/sticky "headers" at fixed indexes.
8 let mut opts = VirtualizerOptions::new(1_000, |_| 1);
9 opts.overscan = 2;
10
11 let pinned: Arc<[usize]> = Arc::from([0usize, 10, 20, 30, 40, 999]);
12 opts.range_extractor = Some(Arc::new({
13 let pinned = Arc::clone(&pinned);
14 move |r: Range, emit: &mut dyn FnMut(usize)| {
15 let mut e = IndexEmitter::new(r, emit);
16 // IMPORTANT: indexes must be emitted in ascending order.
17 //
18 // We want pinned rows both before and after the overscanned range. To keep the output
19 // sorted, emit:
20 // 1) pinned indexes before the overscanned range
21 // 2) the overscanned contiguous range
22 // 3) pinned indexes after the overscanned range
23 let overscanned_start = r.start_index.saturating_sub(r.overscan);
24 let overscanned_end = r.end_index.saturating_add(r.overscan).min(r.count);
25
26 for &idx in pinned.iter() {
27 if idx < overscanned_start {
28 e.emit_pinned(idx);
29 }
30 }
31
32 e.emit_overscanned();
33
34 for &idx in pinned.iter() {
35 if idx >= overscanned_end {
36 e.emit_pinned(idx);
37 }
38 }
39 }
40 }));
41
42 let mut v = Virtualizer::new(opts);
43 v.set_viewport_and_scroll_clamped(10, 500);
44
45 let mut collected = Vec::new();
46 v.for_each_virtual_index(|i| collected.push(i));
47
48 println!("visible_range={:?}", v.visible_range());
49 println!("virtual_range={:?}", v.virtual_range());
50 println!(
51 "indexes_len={} first_20={:?}",
52 collected.len(),
53 &collected[..20.min(collected.len())]
54 );
55
56 // A real UI would typically iterate items:
57 let mut headers = 0usize;
58 v.for_each_virtual_item(|it| {
59 if pinned.binary_search(&it.index).is_ok() {
60 headers += 1;
61 }
62 });
63 println!("pinned_headers_in_output={headers}");
64}Source§impl<K> VirtualizerOptions<K>
impl<K> VirtualizerOptions<K>
Sourcepub fn new_with_key(
count: usize,
estimate_size: impl Fn(usize) -> u32 + Send + Sync + 'static,
get_item_key: impl Fn(usize) -> K + Send + Sync + 'static,
) -> Self
pub fn new_with_key( count: usize, estimate_size: impl Fn(usize) -> u32 + Send + Sync + 'static, get_item_key: impl Fn(usize) -> K + Send + Sync + 'static, ) -> Self
Creates options with a custom key mapping.
Use this when you want measurements to follow items across reordering/replacement:
get_item_key(i) should return a stable identity for the item at index i.
pub fn with_get_item_key( self, get_item_key: impl Fn(usize) -> K + Send + Sync + 'static, ) -> Self
Sourcepub fn with_range_extractor(
self,
range_extractor: Option<impl Fn(Range, &mut dyn FnMut(usize)) + Send + Sync + 'static>,
) -> Self
pub fn with_range_extractor( self, range_extractor: Option<impl Fn(Range, &mut dyn FnMut(usize)) + Send + Sync + 'static>, ) -> Self
Examples found in repository?
7fn main() {
8 // Simulate a framework adapter that owns the scroll state.
9 let saved_scroll = Arc::new(AtomicU64::new(120));
10
11 let opts = VirtualizerOptions::new(1000, |_| 1)
12 .with_initial_rect(Some(Rect {
13 main: 10,
14 cross: 80,
15 }))
16 .with_initial_offset_provider({
17 let saved_scroll = Arc::clone(&saved_scroll);
18 move || saved_scroll.load(Ordering::Relaxed)
19 })
20 .with_scroll_margin(5)
21 .with_range_extractor(Some(|r: Range, emit: &mut dyn FnMut(usize)| {
22 // Pin a "sticky header" at index 0, regardless of scroll position.
23 let mut e = virtualizer::IndexEmitter::new(r, emit);
24 e.emit_pinned(0);
25 e.emit_visible();
26 }));
27
28 let mut v = Virtualizer::new(opts);
29
30 // First render: scroll offset comes from the provider.
31 println!("initial scroll_offset={}", v.scroll_offset());
32 println!("initial scroll_rect={:?}", v.scroll_rect());
33
34 // Adapter updates rect + scroll offset on events.
35 v.apply_scroll_frame(
36 Rect {
37 main: 12,
38 cross: 80,
39 },
40 200,
41 0,
42 );
43
44 let mut items = Vec::new();
45 v.for_each_virtual_item_keyed(|it| items.push(it));
46 println!(
47 "is_scrolling={}, visible_range={:?}, items_len={}",
48 v.is_scrolling(),
49 v.visible_range(),
50 items.len()
51 );
52 println!("first_item={:?}", items.first());
53
54 // Demonstrate scroll-to helpers.
55 let target = v.scroll_to_index_offset(500, Align::Start);
56 v.set_scroll_offset_clamped(target);
57 println!("after scroll_to_index: scroll_offset={}", v.scroll_offset());
58
59 // Demonstrate dynamic measurement + scroll adjustment.
60 let applied = v.resize_item(0, 20);
61 println!("resize_item applied_scroll_adjustment={applied}");
62
63 // Simulate reorder: change key mapping. This automatically rebuilds per-index sizes from the
64 // key-based measurement cache. In real apps, you usually keep `get_item_key` stable and call
65 // `sync_item_keys()` when your dataset is reordered while `count` stays the same.
66 v.set_get_item_key(|i| if i == 0 { 1 } else { i as u64 });
67
68 // Debounced scrolling reset without relying on a native scrollend event.
69 v.update_scrolling(200);
70 println!("after update_scrolling: is_scrolling={}", v.is_scrolling());
71
72 // Toggle enabled to disable all queries.
73 v.set_enabled(false);
74 let mut disabled_len = 0usize;
75 v.for_each_virtual_item(|_| disabled_len += 1);
76 println!(
77 "disabled total_size={}, items_len={}",
78 v.total_size(),
79 disabled_len
80 );
81}pub fn with_enabled(self, enabled: bool) -> Self
Sourcepub fn with_initial_rect(self, initial_rect: Option<Rect>) -> Self
pub fn with_initial_rect(self, initial_rect: Option<Rect>) -> Self
Sets the initial viewport rectangle.
Examples found in repository?
7fn main() {
8 // Simulate a framework adapter that owns the scroll state.
9 let saved_scroll = Arc::new(AtomicU64::new(120));
10
11 let opts = VirtualizerOptions::new(1000, |_| 1)
12 .with_initial_rect(Some(Rect {
13 main: 10,
14 cross: 80,
15 }))
16 .with_initial_offset_provider({
17 let saved_scroll = Arc::clone(&saved_scroll);
18 move || saved_scroll.load(Ordering::Relaxed)
19 })
20 .with_scroll_margin(5)
21 .with_range_extractor(Some(|r: Range, emit: &mut dyn FnMut(usize)| {
22 // Pin a "sticky header" at index 0, regardless of scroll position.
23 let mut e = virtualizer::IndexEmitter::new(r, emit);
24 e.emit_pinned(0);
25 e.emit_visible();
26 }));
27
28 let mut v = Virtualizer::new(opts);
29
30 // First render: scroll offset comes from the provider.
31 println!("initial scroll_offset={}", v.scroll_offset());
32 println!("initial scroll_rect={:?}", v.scroll_rect());
33
34 // Adapter updates rect + scroll offset on events.
35 v.apply_scroll_frame(
36 Rect {
37 main: 12,
38 cross: 80,
39 },
40 200,
41 0,
42 );
43
44 let mut items = Vec::new();
45 v.for_each_virtual_item_keyed(|it| items.push(it));
46 println!(
47 "is_scrolling={}, visible_range={:?}, items_len={}",
48 v.is_scrolling(),
49 v.visible_range(),
50 items.len()
51 );
52 println!("first_item={:?}", items.first());
53
54 // Demonstrate scroll-to helpers.
55 let target = v.scroll_to_index_offset(500, Align::Start);
56 v.set_scroll_offset_clamped(target);
57 println!("after scroll_to_index: scroll_offset={}", v.scroll_offset());
58
59 // Demonstrate dynamic measurement + scroll adjustment.
60 let applied = v.resize_item(0, 20);
61 println!("resize_item applied_scroll_adjustment={applied}");
62
63 // Simulate reorder: change key mapping. This automatically rebuilds per-index sizes from the
64 // key-based measurement cache. In real apps, you usually keep `get_item_key` stable and call
65 // `sync_item_keys()` when your dataset is reordered while `count` stays the same.
66 v.set_get_item_key(|i| if i == 0 { 1 } else { i as u64 });
67
68 // Debounced scrolling reset without relying on a native scrollend event.
69 v.update_scrolling(200);
70 println!("after update_scrolling: is_scrolling={}", v.is_scrolling());
71
72 // Toggle enabled to disable all queries.
73 v.set_enabled(false);
74 let mut disabled_len = 0usize;
75 v.for_each_virtual_item(|_| disabled_len += 1);
76 println!(
77 "disabled total_size={}, items_len={}",
78 v.total_size(),
79 disabled_len
80 );
81}pub fn with_overscan(self, overscan: usize) -> Self
pub fn with_padding(self, padding_start: u32, padding_end: u32) -> Self
pub fn with_scroll_padding( self, scroll_padding_start: u32, scroll_padding_end: u32, ) -> Self
Sourcepub fn with_scroll_margin(self, scroll_margin: u32) -> Self
pub fn with_scroll_margin(self, scroll_margin: u32) -> Self
Examples found in repository?
7fn main() {
8 // Simulate a framework adapter that owns the scroll state.
9 let saved_scroll = Arc::new(AtomicU64::new(120));
10
11 let opts = VirtualizerOptions::new(1000, |_| 1)
12 .with_initial_rect(Some(Rect {
13 main: 10,
14 cross: 80,
15 }))
16 .with_initial_offset_provider({
17 let saved_scroll = Arc::clone(&saved_scroll);
18 move || saved_scroll.load(Ordering::Relaxed)
19 })
20 .with_scroll_margin(5)
21 .with_range_extractor(Some(|r: Range, emit: &mut dyn FnMut(usize)| {
22 // Pin a "sticky header" at index 0, regardless of scroll position.
23 let mut e = virtualizer::IndexEmitter::new(r, emit);
24 e.emit_pinned(0);
25 e.emit_visible();
26 }));
27
28 let mut v = Virtualizer::new(opts);
29
30 // First render: scroll offset comes from the provider.
31 println!("initial scroll_offset={}", v.scroll_offset());
32 println!("initial scroll_rect={:?}", v.scroll_rect());
33
34 // Adapter updates rect + scroll offset on events.
35 v.apply_scroll_frame(
36 Rect {
37 main: 12,
38 cross: 80,
39 },
40 200,
41 0,
42 );
43
44 let mut items = Vec::new();
45 v.for_each_virtual_item_keyed(|it| items.push(it));
46 println!(
47 "is_scrolling={}, visible_range={:?}, items_len={}",
48 v.is_scrolling(),
49 v.visible_range(),
50 items.len()
51 );
52 println!("first_item={:?}", items.first());
53
54 // Demonstrate scroll-to helpers.
55 let target = v.scroll_to_index_offset(500, Align::Start);
56 v.set_scroll_offset_clamped(target);
57 println!("after scroll_to_index: scroll_offset={}", v.scroll_offset());
58
59 // Demonstrate dynamic measurement + scroll adjustment.
60 let applied = v.resize_item(0, 20);
61 println!("resize_item applied_scroll_adjustment={applied}");
62
63 // Simulate reorder: change key mapping. This automatically rebuilds per-index sizes from the
64 // key-based measurement cache. In real apps, you usually keep `get_item_key` stable and call
65 // `sync_item_keys()` when your dataset is reordered while `count` stays the same.
66 v.set_get_item_key(|i| if i == 0 { 1 } else { i as u64 });
67
68 // Debounced scrolling reset without relying on a native scrollend event.
69 v.update_scrolling(200);
70 println!("after update_scrolling: is_scrolling={}", v.is_scrolling());
71
72 // Toggle enabled to disable all queries.
73 v.set_enabled(false);
74 let mut disabled_len = 0usize;
75 v.for_each_virtual_item(|_| disabled_len += 1);
76 println!(
77 "disabled total_size={}, items_len={}",
78 v.total_size(),
79 disabled_len
80 );
81}pub fn with_initial_offset(self, initial_offset: InitialOffset) -> Self
pub fn with_initial_offset_value(self, initial_offset: u64) -> Self
Sourcepub fn with_initial_offset_provider(
self,
initial_offset: impl Fn() -> u64 + Send + Sync + 'static,
) -> Self
pub fn with_initial_offset_provider( self, initial_offset: impl Fn() -> u64 + Send + Sync + 'static, ) -> Self
Examples found in repository?
7fn main() {
8 // Simulate a framework adapter that owns the scroll state.
9 let saved_scroll = Arc::new(AtomicU64::new(120));
10
11 let opts = VirtualizerOptions::new(1000, |_| 1)
12 .with_initial_rect(Some(Rect {
13 main: 10,
14 cross: 80,
15 }))
16 .with_initial_offset_provider({
17 let saved_scroll = Arc::clone(&saved_scroll);
18 move || saved_scroll.load(Ordering::Relaxed)
19 })
20 .with_scroll_margin(5)
21 .with_range_extractor(Some(|r: Range, emit: &mut dyn FnMut(usize)| {
22 // Pin a "sticky header" at index 0, regardless of scroll position.
23 let mut e = virtualizer::IndexEmitter::new(r, emit);
24 e.emit_pinned(0);
25 e.emit_visible();
26 }));
27
28 let mut v = Virtualizer::new(opts);
29
30 // First render: scroll offset comes from the provider.
31 println!("initial scroll_offset={}", v.scroll_offset());
32 println!("initial scroll_rect={:?}", v.scroll_rect());
33
34 // Adapter updates rect + scroll offset on events.
35 v.apply_scroll_frame(
36 Rect {
37 main: 12,
38 cross: 80,
39 },
40 200,
41 0,
42 );
43
44 let mut items = Vec::new();
45 v.for_each_virtual_item_keyed(|it| items.push(it));
46 println!(
47 "is_scrolling={}, visible_range={:?}, items_len={}",
48 v.is_scrolling(),
49 v.visible_range(),
50 items.len()
51 );
52 println!("first_item={:?}", items.first());
53
54 // Demonstrate scroll-to helpers.
55 let target = v.scroll_to_index_offset(500, Align::Start);
56 v.set_scroll_offset_clamped(target);
57 println!("after scroll_to_index: scroll_offset={}", v.scroll_offset());
58
59 // Demonstrate dynamic measurement + scroll adjustment.
60 let applied = v.resize_item(0, 20);
61 println!("resize_item applied_scroll_adjustment={applied}");
62
63 // Simulate reorder: change key mapping. This automatically rebuilds per-index sizes from the
64 // key-based measurement cache. In real apps, you usually keep `get_item_key` stable and call
65 // `sync_item_keys()` when your dataset is reordered while `count` stays the same.
66 v.set_get_item_key(|i| if i == 0 { 1 } else { i as u64 });
67
68 // Debounced scrolling reset without relying on a native scrollend event.
69 v.update_scrolling(200);
70 println!("after update_scrolling: is_scrolling={}", v.is_scrolling());
71
72 // Toggle enabled to disable all queries.
73 v.set_enabled(false);
74 let mut disabled_len = 0usize;
75 v.for_each_virtual_item(|_| disabled_len += 1);
76 println!(
77 "disabled total_size={}, items_len={}",
78 v.total_size(),
79 disabled_len
80 );
81}