Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
// Copyright 2023 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
use accesskit::Role;
use crate::node::Node;
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum FilterResult {
Include,
ExcludeNode,
ExcludeSubtree,
}
pub fn common_filter(node: &Node) -> FilterResult {
if node.is_focused() {
return FilterResult::Include;
}
if node.is_hidden() {
return FilterResult::ExcludeSubtree;
}
if let Some(parent) = node.parent() {
if common_filter(&parent) == FilterResult::ExcludeSubtree {
return FilterResult::ExcludeSubtree;
}
}
let role = node.role();
if role == Role::GenericContainer || role == Role::TextRun {
return FilterResult::ExcludeNode;
}
FilterResult::Include
}
pub fn common_filter_with_root_exception(node: &Node) -> FilterResult {
if node.is_root() {
return FilterResult::Include;
}
common_filter(node)
}

View File

@@ -0,0 +1,832 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
// Derived from Chromium's accessibility abstraction.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.chromium file.
use core::iter::FusedIterator;
use accesskit::NodeId;
use crate::{filters::FilterResult, node::Node, tree::State as TreeState};
/// An iterator that yields following siblings of a node.
///
/// This struct is created by the [`following_siblings`](Node::following_siblings) method on [`Node`].
pub struct FollowingSiblings<'a> {
back_position: usize,
done: bool,
front_position: usize,
parent: Option<Node<'a>>,
}
impl<'a> FollowingSiblings<'a> {
pub(crate) fn new(node: Node<'a>) -> Self {
let parent_and_index = node.parent_and_index();
let (back_position, front_position, done) =
if let Some((ref parent, index)) = parent_and_index {
let back_position = parent.data().children().len() - 1;
let front_position = index + 1;
(
back_position,
front_position,
front_position > back_position,
)
} else {
(0, 0, true)
};
Self {
back_position,
done,
front_position,
parent: parent_and_index.map(|(parent, _)| parent),
}
}
}
impl Iterator for FollowingSiblings<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front_position == self.back_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.front_position)?;
self.front_position += 1;
Some(*child)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = match self.done {
true => 0,
_ => self.back_position + 1 - self.front_position,
};
(len, Some(len))
}
}
impl DoubleEndedIterator for FollowingSiblings<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back_position == self.front_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.back_position)?;
self.back_position -= 1;
Some(*child)
}
}
}
impl ExactSizeIterator for FollowingSiblings<'_> {}
impl FusedIterator for FollowingSiblings<'_> {}
/// An iterator that yields preceding siblings of a node.
///
/// This struct is created by the [`preceding_siblings`](Node::preceding_siblings) method on [`Node`].
pub struct PrecedingSiblings<'a> {
back_position: usize,
done: bool,
front_position: usize,
parent: Option<Node<'a>>,
}
impl<'a> PrecedingSiblings<'a> {
pub(crate) fn new(node: Node<'a>) -> Self {
let parent_and_index = node.parent_and_index();
let (back_position, front_position, done) = if let Some((_, index)) = parent_and_index {
let front_position = index.saturating_sub(1);
(0, front_position, index == 0)
} else {
(0, 0, true)
};
Self {
back_position,
done,
front_position,
parent: parent_and_index.map(|(parent, _)| parent),
}
}
}
impl Iterator for PrecedingSiblings<'_> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front_position == self.back_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.front_position)?;
if !self.done {
self.front_position -= 1;
}
Some(*child)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = match self.done {
true => 0,
_ => self.front_position + 1 - self.back_position,
};
(len, Some(len))
}
}
impl DoubleEndedIterator for PrecedingSiblings<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back_position == self.front_position;
let child = self
.parent
.as_ref()?
.data()
.children()
.get(self.back_position)?;
self.back_position += 1;
Some(*child)
}
}
}
impl ExactSizeIterator for PrecedingSiblings<'_> {}
impl FusedIterator for PrecedingSiblings<'_> {}
fn next_filtered_sibling<'a>(
node: Option<Node<'a>>,
filter: &impl Fn(&Node) -> FilterResult,
) -> Option<Node<'a>> {
let mut next = node;
let mut consider_children = false;
while let Some(current) = next {
if let Some(Some(child)) = consider_children.then(|| current.children().next()) {
let result = filter(&child);
next = Some(child);
if result == FilterResult::Include {
return next;
}
consider_children = result == FilterResult::ExcludeNode;
} else if let Some(sibling) = current.following_siblings().next() {
let result = filter(&sibling);
next = Some(sibling);
if result == FilterResult::Include {
return next;
}
if result == FilterResult::ExcludeNode {
consider_children = true;
}
} else {
let parent = current.parent();
next = parent;
if let Some(parent) = parent {
if filter(&parent) != FilterResult::ExcludeNode {
return None;
}
consider_children = false;
} else {
return None;
}
}
}
None
}
fn previous_filtered_sibling<'a>(
node: Option<Node<'a>>,
filter: &impl Fn(&Node) -> FilterResult,
) -> Option<Node<'a>> {
let mut previous = node;
let mut consider_children = false;
while let Some(current) = previous {
if let Some(Some(child)) = consider_children.then(|| current.children().next_back()) {
let result = filter(&child);
previous = Some(child);
if result == FilterResult::Include {
return previous;
}
consider_children = result == FilterResult::ExcludeNode;
} else if let Some(sibling) = current.preceding_siblings().next() {
let result = filter(&sibling);
previous = Some(sibling);
if result == FilterResult::Include {
return previous;
}
if result == FilterResult::ExcludeNode {
consider_children = true;
}
} else {
let parent = current.parent();
previous = parent;
if let Some(parent) = parent {
if filter(&parent) != FilterResult::ExcludeNode {
return None;
}
consider_children = false;
} else {
return None;
}
}
}
None
}
/// An iterator that yields following siblings of a node according to the
/// specified filter.
///
/// This struct is created by the [`following_filtered_siblings`](Node::following_filtered_siblings) method on [`Node`].
pub struct FollowingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> FollowingFilteredSiblings<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = next_filtered_sibling(Some(node), &filter);
let back = node
.filtered_parent(&filter)
.and_then(|parent| parent.last_filtered_child(&filter));
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FollowingFilteredSiblings<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = next_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
for FollowingFilteredSiblings<'_, Filter>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = previous_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for FollowingFilteredSiblings<'_, Filter> {}
/// An iterator that yields preceding siblings of a node according to the
/// specified filter.
///
/// This struct is created by the [`preceding_filtered_siblings`](Node::preceding_filtered_siblings) method on [`Node`].
pub struct PrecedingFilteredSiblings<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> PrecedingFilteredSiblings<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = previous_filtered_sibling(Some(node), &filter);
let back = node
.filtered_parent(&filter)
.and_then(|parent| parent.first_filtered_child(&filter));
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for PrecedingFilteredSiblings<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = previous_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator
for PrecedingFilteredSiblings<'_, Filter>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = next_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for PrecedingFilteredSiblings<'_, Filter> {}
/// An iterator that yields children of a node according to the specified
/// filter.
///
/// This struct is created by the [`filtered_children`](Node::filtered_children) method on [`Node`].
pub struct FilteredChildren<'a, Filter: Fn(&Node) -> FilterResult> {
filter: Filter,
back: Option<Node<'a>>,
done: bool,
front: Option<Node<'a>>,
}
impl<'a, Filter: Fn(&Node) -> FilterResult> FilteredChildren<'a, Filter> {
pub(crate) fn new(node: Node<'a>, filter: Filter) -> Self {
let front = node.first_filtered_child(&filter);
let back = node.last_filtered_child(&filter);
Self {
filter,
back,
done: back.is_none() || front.is_none(),
front,
}
}
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for FilteredChildren<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.front.as_ref().unwrap().id() == self.back.as_ref().unwrap().id();
let current = self.front;
self.front = next_filtered_sibling(self.front, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for FilteredChildren<'_, Filter> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.done {
None
} else {
self.done = self.back.as_ref().unwrap().id() == self.front.as_ref().unwrap().id();
let current = self.back;
self.back = previous_filtered_sibling(self.back, &self.filter);
current
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for FilteredChildren<'_, Filter> {}
pub(crate) enum LabelledBy<'a, Filter: Fn(&Node) -> FilterResult> {
FromDescendants(FilteredChildren<'a, Filter>),
Explicit {
ids: core::slice::Iter<'a, NodeId>,
tree_state: &'a TreeState,
},
}
impl<'a, Filter: Fn(&Node) -> FilterResult> Iterator for LabelledBy<'a, Filter> {
type Item = Node<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::FromDescendants(iter) => iter.next(),
Self::Explicit { ids, tree_state } => {
ids.next().map(|id| tree_state.node_by_id(*id).unwrap())
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::FromDescendants(iter) => iter.size_hint(),
Self::Explicit { ids, .. } => ids.size_hint(),
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> DoubleEndedIterator for LabelledBy<'_, Filter> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
Self::FromDescendants(iter) => iter.next_back(),
Self::Explicit { ids, tree_state } => ids
.next_back()
.map(|id| tree_state.node_by_id(*id).unwrap()),
}
}
}
impl<Filter: Fn(&Node) -> FilterResult> FusedIterator for LabelledBy<'_, Filter> {}
#[cfg(test)]
mod tests {
use crate::tests::*;
use accesskit::NodeId;
use alloc::vec::Vec;
#[test]
fn following_siblings() {
let tree = test_tree();
assert!(tree.state().root().following_siblings().next().is_none());
assert_eq!(0, tree.state().root().following_siblings().len());
assert_eq!(
[
PARAGRAPH_1_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_3_IGNORED_ID
],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
3,
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.len()
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.next()
.is_none());
assert_eq!(
0,
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.len()
);
}
#[test]
fn following_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_siblings()
.next_back()
.is_none());
assert_eq!(
[
PARAGRAPH_3_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_1_IGNORED_ID
],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_siblings()
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_siblings()
.next_back()
.is_none());
}
#[test]
fn preceding_siblings() {
let tree = test_tree();
assert!(tree.state().root().preceding_siblings().next().is_none());
assert_eq!(0, tree.state().root().preceding_siblings().len());
assert_eq!(
[PARAGRAPH_2_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
3,
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.len()
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.next()
.is_none());
assert_eq!(
0,
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.len()
);
}
#[test]
fn preceding_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_siblings()
.next_back()
.is_none());
assert_eq!(
[PARAGRAPH_0_ID, PARAGRAPH_1_IGNORED_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_siblings()
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_siblings()
.next_back()
.is_none());
}
#[test]
fn following_filtered_siblings() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_filtered_siblings(test_tree_filter)
.next()
.is_none());
assert_eq!(
[LABEL_1_1_ID, PARAGRAPH_2_ID, LABEL_3_1_0_ID, BUTTON_3_2_ID],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[BUTTON_3_2_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.next()
.is_none());
}
#[test]
fn following_filtered_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.following_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
assert_eq!(
[BUTTON_3_2_ID, LABEL_3_1_0_ID, PARAGRAPH_2_ID, LABEL_1_1_ID],
tree.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[BUTTON_3_2_ID,],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.following_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
}
#[test]
fn preceding_filtered_siblings() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_filtered_siblings(test_tree_filter)
.next()
.is_none());
assert_eq!(
[PARAGRAPH_2_ID, LABEL_1_1_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[PARAGRAPH_2_ID, LABEL_1_1_ID, PARAGRAPH_0_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.next()
.is_none());
}
#[test]
fn preceding_filtered_siblings_reversed() {
let tree = test_tree();
assert!(tree
.state()
.root()
.preceding_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
assert_eq!(
[PARAGRAPH_0_ID, LABEL_1_1_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(PARAGRAPH_3_IGNORED_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert_eq!(
[PARAGRAPH_0_ID, LABEL_1_1_ID, PARAGRAPH_2_ID],
tree.state()
.node_by_id(LABEL_3_1_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.preceding_filtered_siblings(test_tree_filter)
.next_back()
.is_none());
}
#[test]
fn filtered_children() {
let tree = test_tree();
assert_eq!(
[
PARAGRAPH_0_ID,
LABEL_1_1_ID,
PARAGRAPH_2_ID,
LABEL_3_1_0_ID,
BUTTON_3_2_ID
],
tree.state()
.root()
.filtered_children(test_tree_filter)
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next()
.is_none());
assert!(tree
.state()
.node_by_id(LABEL_0_0_IGNORED_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next()
.is_none());
}
#[test]
fn filtered_children_reversed() {
let tree = test_tree();
assert_eq!(
[
BUTTON_3_2_ID,
LABEL_3_1_0_ID,
PARAGRAPH_2_ID,
LABEL_1_1_ID,
PARAGRAPH_0_ID
],
tree.state()
.root()
.filtered_children(test_tree_filter)
.rev()
.map(|node| node.id())
.collect::<Vec<NodeId>>()[..]
);
assert!(tree
.state()
.node_by_id(PARAGRAPH_0_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next_back()
.is_none());
assert!(tree
.state()
.node_by_id(LABEL_0_0_IGNORED_ID)
.unwrap()
.filtered_children(test_tree_filter)
.next_back()
.is_none());
}
}

204
vendor/accesskit_consumer/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,204 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
#![no_std]
extern crate alloc;
pub(crate) mod tree;
pub use tree::{ChangeHandler as TreeChangeHandler, State as TreeState, Tree};
pub(crate) mod node;
pub use node::Node;
pub(crate) mod filters;
pub use filters::{common_filter, common_filter_with_root_exception, FilterResult};
pub(crate) mod iterators;
pub(crate) mod text;
pub use text::{
AttributeValue as TextAttributeValue, Position as TextPosition, Range as TextRange,
WeakRange as WeakTextRange,
};
#[cfg(test)]
mod tests {
use accesskit::{Affine, Node, NodeId, Rect, Role, Tree, TreeUpdate, Vec2};
use alloc::vec;
use crate::FilterResult;
pub const ROOT_ID: NodeId = NodeId(0);
pub const PARAGRAPH_0_ID: NodeId = NodeId(1);
pub const LABEL_0_0_IGNORED_ID: NodeId = NodeId(2);
pub const PARAGRAPH_1_IGNORED_ID: NodeId = NodeId(3);
pub const BUTTON_1_0_HIDDEN_ID: NodeId = NodeId(4);
pub const CONTAINER_1_0_0_HIDDEN_ID: NodeId = NodeId(5);
pub const LABEL_1_1_ID: NodeId = NodeId(6);
pub const BUTTON_1_2_HIDDEN_ID: NodeId = NodeId(7);
pub const CONTAINER_1_2_0_HIDDEN_ID: NodeId = NodeId(8);
pub const PARAGRAPH_2_ID: NodeId = NodeId(9);
pub const LABEL_2_0_ID: NodeId = NodeId(10);
pub const PARAGRAPH_3_IGNORED_ID: NodeId = NodeId(11);
pub const EMPTY_CONTAINER_3_0_IGNORED_ID: NodeId = NodeId(12);
pub const LINK_3_1_IGNORED_ID: NodeId = NodeId(13);
pub const LABEL_3_1_0_ID: NodeId = NodeId(14);
pub const BUTTON_3_2_ID: NodeId = NodeId(15);
pub const EMPTY_CONTAINER_3_3_IGNORED_ID: NodeId = NodeId(16);
pub fn test_tree() -> crate::tree::Tree {
let root = {
let mut node = Node::new(Role::RootWebArea);
node.set_children(vec![
PARAGRAPH_0_ID,
PARAGRAPH_1_IGNORED_ID,
PARAGRAPH_2_ID,
PARAGRAPH_3_IGNORED_ID,
]);
node
};
let paragraph_0 = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![LABEL_0_0_IGNORED_ID]);
node
};
let label_0_0_ignored = {
let mut node = Node::new(Role::Label);
node.set_value("label_0_0_ignored");
node
};
let paragraph_1_ignored = {
let mut node = Node::new(Role::Paragraph);
node.set_transform(Affine::translate(Vec2::new(10.0, 40.0)));
node.set_bounds(Rect {
x0: 0.0,
y0: 0.0,
x1: 800.0,
y1: 40.0,
});
node.set_children(vec![
BUTTON_1_0_HIDDEN_ID,
LABEL_1_1_ID,
BUTTON_1_2_HIDDEN_ID,
]);
node
};
let button_1_0_hidden = {
let mut node = Node::new(Role::Button);
node.set_label("button_1_0_hidden");
node.set_hidden();
node.set_children(vec![CONTAINER_1_0_0_HIDDEN_ID]);
node
};
let container_1_0_0_hidden = {
let mut node = Node::new(Role::GenericContainer);
node.set_hidden();
node
};
let label_1_1 = {
let mut node = Node::new(Role::Label);
node.set_bounds(Rect {
x0: 10.0,
y0: 10.0,
x1: 90.0,
y1: 30.0,
});
node.set_value("label_1_1");
node
};
let button_1_2_hidden = {
let mut node = Node::new(Role::Button);
node.set_label("button_1_2_hidden");
node.set_hidden();
node.set_children(vec![CONTAINER_1_2_0_HIDDEN_ID]);
node
};
let container_1_2_0_hidden = {
let mut node = Node::new(Role::GenericContainer);
node.set_hidden();
node
};
let paragraph_2 = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![LABEL_2_0_ID]);
node
};
let label_2_0 = {
let mut node = Node::new(Role::Label);
node.set_label("label_2_0");
node
};
let paragraph_3_ignored = {
let mut node = Node::new(Role::Paragraph);
node.set_children(vec![
EMPTY_CONTAINER_3_0_IGNORED_ID,
LINK_3_1_IGNORED_ID,
BUTTON_3_2_ID,
EMPTY_CONTAINER_3_3_IGNORED_ID,
]);
node
};
let empty_container_3_0_ignored = Node::new(Role::GenericContainer);
let link_3_1_ignored = {
let mut node = Node::new(Role::Link);
node.set_children(vec![LABEL_3_1_0_ID]);
node.set_linked();
node
};
let label_3_1_0 = {
let mut node = Node::new(Role::Label);
node.set_value("label_3_1_0");
node
};
let button_3_2 = {
let mut node = Node::new(Role::Button);
node.set_label("button_3_2");
node
};
let empty_container_3_3_ignored = Node::new(Role::GenericContainer);
let initial_update = TreeUpdate {
nodes: vec![
(ROOT_ID, root),
(PARAGRAPH_0_ID, paragraph_0),
(LABEL_0_0_IGNORED_ID, label_0_0_ignored),
(PARAGRAPH_1_IGNORED_ID, paragraph_1_ignored),
(BUTTON_1_0_HIDDEN_ID, button_1_0_hidden),
(CONTAINER_1_0_0_HIDDEN_ID, container_1_0_0_hidden),
(LABEL_1_1_ID, label_1_1),
(BUTTON_1_2_HIDDEN_ID, button_1_2_hidden),
(CONTAINER_1_2_0_HIDDEN_ID, container_1_2_0_hidden),
(PARAGRAPH_2_ID, paragraph_2),
(LABEL_2_0_ID, label_2_0),
(PARAGRAPH_3_IGNORED_ID, paragraph_3_ignored),
(EMPTY_CONTAINER_3_0_IGNORED_ID, empty_container_3_0_ignored),
(LINK_3_1_IGNORED_ID, link_3_1_ignored),
(LABEL_3_1_0_ID, label_3_1_0),
(BUTTON_3_2_ID, button_3_2),
(EMPTY_CONTAINER_3_3_IGNORED_ID, empty_container_3_3_ignored),
],
tree: Some(Tree::new(ROOT_ID)),
focus: ROOT_ID,
};
crate::tree::Tree::new(initial_update, false)
}
pub fn test_tree_filter(node: &crate::Node) -> FilterResult {
let id = node.id();
if node.is_hidden() {
FilterResult::ExcludeSubtree
} else if id == LABEL_0_0_IGNORED_ID
|| id == PARAGRAPH_1_IGNORED_ID
|| id == PARAGRAPH_3_IGNORED_ID
|| id == EMPTY_CONTAINER_3_0_IGNORED_ID
|| id == LINK_3_1_IGNORED_ID
|| id == EMPTY_CONTAINER_3_3_IGNORED_ID
{
FilterResult::ExcludeNode
} else {
FilterResult::Include
}
}
}

1319
vendor/accesskit_consumer/src/node.rs vendored Normal file

File diff suppressed because it is too large Load Diff

2065
vendor/accesskit_consumer/src/text.rs vendored Normal file

File diff suppressed because it is too large Load Diff

759
vendor/accesskit_consumer/src/tree.rs vendored Normal file
View File

@@ -0,0 +1,759 @@
// Copyright 2021 The AccessKit Authors. All rights reserved.
// Licensed under the Apache License, Version 2.0 (found in
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.
use accesskit::{FrozenNode as NodeData, NodeId, Tree as TreeData, TreeUpdate};
use alloc::{sync::Arc, vec};
use core::fmt;
use hashbrown::{HashMap, HashSet};
use immutable_chunkmap::map::MapM as ChunkMap;
use crate::node::{Node, NodeState, ParentAndIndex};
#[derive(Clone, Debug)]
pub struct State {
pub(crate) nodes: ChunkMap<NodeId, NodeState>,
pub(crate) data: TreeData,
pub(crate) focus: NodeId,
is_host_focused: bool,
}
#[derive(Default)]
struct InternalChanges {
added_node_ids: HashSet<NodeId>,
updated_node_ids: HashSet<NodeId>,
removed_node_ids: HashSet<NodeId>,
}
impl State {
fn validate_global(&self) {
if self.nodes.get_key(&self.data.root).is_none() {
panic!("Root id #{} is not in the node list", self.data.root.0);
}
if self.nodes.get_key(&self.focus).is_none() {
panic!("Focused id #{} is not in the node list", self.focus.0);
}
}
fn update(
&mut self,
update: TreeUpdate,
is_host_focused: bool,
mut changes: Option<&mut InternalChanges>,
) {
let mut unreachable = HashSet::new();
if let Some(tree) = update.tree {
if tree.root != self.data.root {
unreachable.insert(self.data.root);
}
self.data = tree;
}
let root = self.data.root;
let mut pending_nodes: HashMap<NodeId, _> = HashMap::new();
let mut pending_children = HashMap::new();
fn add_node(
nodes: &mut ChunkMap<NodeId, NodeState>,
changes: &mut Option<&mut InternalChanges>,
parent_and_index: Option<ParentAndIndex>,
id: NodeId,
data: NodeData,
) {
let state = NodeState {
parent_and_index,
data: Arc::new(data),
};
nodes.insert_cow(id, state);
if let Some(changes) = changes {
changes.added_node_ids.insert(id);
}
}
for (node_id, node_data) in update.nodes {
let node_data = NodeData::from(node_data);
unreachable.remove(&node_id);
let mut seen_child_ids = HashSet::with_capacity(node_data.children().len());
for (child_index, child_id) in node_data.children().iter().enumerate() {
if seen_child_ids.contains(child_id) {
panic!(
"Node #{} of TreeUpdate includes duplicate child #{};",
node_id.0, child_id.0
);
}
unreachable.remove(child_id);
let parent_and_index = ParentAndIndex(node_id, child_index);
if let Some(child_state) = self.nodes.get_mut_cow(child_id) {
if child_state.parent_and_index != Some(parent_and_index) {
child_state.parent_and_index = Some(parent_and_index);
}
} else if let Some(child_data) = pending_nodes.remove(child_id) {
add_node(
&mut self.nodes,
&mut changes,
Some(parent_and_index),
*child_id,
child_data,
);
} else {
pending_children.insert(*child_id, parent_and_index);
}
seen_child_ids.insert(*child_id);
}
if let Some(node_state) = self.nodes.get_mut_cow(&node_id) {
if node_id == root {
node_state.parent_and_index = None;
}
for child_id in node_state.data.children().iter() {
if !seen_child_ids.contains(child_id) {
unreachable.insert(*child_id);
}
}
if *node_state.data != node_data {
node_state.data = Arc::new(node_data);
if let Some(changes) = &mut changes {
changes.updated_node_ids.insert(node_id);
}
}
} else if let Some(parent_and_index) = pending_children.remove(&node_id) {
add_node(
&mut self.nodes,
&mut changes,
Some(parent_and_index),
node_id,
node_data,
);
} else if node_id == root {
add_node(&mut self.nodes, &mut changes, None, node_id, node_data);
} else {
pending_nodes.insert(node_id, node_data);
}
}
if !pending_nodes.is_empty() {
panic!("TreeUpdate includes {} nodes which are neither in the current tree nor a child of another node from the update: {}", pending_nodes.len(), ShortNodeList(&pending_nodes));
}
if !pending_children.is_empty() {
panic!("TreeUpdate's nodes include {} children ids which are neither in the current tree nor the id of another node from the update: {}", pending_children.len(), ShortNodeList(&pending_children));
}
self.focus = update.focus;
self.is_host_focused = is_host_focused;
if !unreachable.is_empty() {
fn traverse_unreachable(
nodes: &mut ChunkMap<NodeId, NodeState>,
changes: &mut Option<&mut InternalChanges>,
id: NodeId,
) {
if let Some(changes) = changes {
changes.removed_node_ids.insert(id);
}
let node = nodes.remove_cow(&id).unwrap();
for child_id in node.data.children().iter() {
traverse_unreachable(nodes, changes, *child_id);
}
}
for id in unreachable {
traverse_unreachable(&mut self.nodes, &mut changes, id);
}
}
self.validate_global();
}
fn update_host_focus_state(
&mut self,
is_host_focused: bool,
changes: Option<&mut InternalChanges>,
) {
let update = TreeUpdate {
nodes: vec![],
tree: None,
focus: self.focus,
};
self.update(update, is_host_focused, changes);
}
pub fn has_node(&self, id: NodeId) -> bool {
self.nodes.get(&id).is_some()
}
pub fn node_by_id(&self, id: NodeId) -> Option<Node<'_>> {
self.nodes.get(&id).map(|node_state| Node {
tree_state: self,
id,
state: node_state,
})
}
pub fn root_id(&self) -> NodeId {
self.data.root
}
pub fn root(&self) -> Node<'_> {
self.node_by_id(self.root_id()).unwrap()
}
pub fn is_host_focused(&self) -> bool {
self.is_host_focused
}
pub fn focus_id_in_tree(&self) -> NodeId {
self.focus
}
pub fn focus_in_tree(&self) -> Node<'_> {
self.node_by_id(self.focus_id_in_tree()).unwrap()
}
pub fn focus_id(&self) -> Option<NodeId> {
self.is_host_focused.then_some(self.focus)
}
pub fn focus(&self) -> Option<Node<'_>> {
self.focus_id().map(|id| self.node_by_id(id).unwrap())
}
pub fn toolkit_name(&self) -> Option<&str> {
self.data.toolkit_name.as_deref()
}
pub fn toolkit_version(&self) -> Option<&str> {
self.data.toolkit_version.as_deref()
}
}
pub trait ChangeHandler {
fn node_added(&mut self, node: &Node);
fn node_updated(&mut self, old_node: &Node, new_node: &Node);
fn focus_moved(&mut self, old_node: Option<&Node>, new_node: Option<&Node>);
fn node_removed(&mut self, node: &Node);
}
#[derive(Debug)]
pub struct Tree {
state: State,
}
impl Tree {
pub fn new(mut initial_state: TreeUpdate, is_host_focused: bool) -> Self {
let Some(tree) = initial_state.tree.take() else {
panic!("Tried to initialize the accessibility tree without a root tree. TreeUpdate::tree must be Some.");
};
let mut state = State {
nodes: ChunkMap::new(),
data: tree,
focus: initial_state.focus,
is_host_focused,
};
state.update(initial_state, is_host_focused, None);
Self { state }
}
pub fn update(&mut self, update: TreeUpdate) {
self.state.update(update, self.state.is_host_focused, None);
}
pub fn update_and_process_changes(
&mut self,
update: TreeUpdate,
handler: &mut impl ChangeHandler,
) {
let mut changes = InternalChanges::default();
let old_state = self.state.clone();
self.state
.update(update, self.state.is_host_focused, Some(&mut changes));
self.process_changes(old_state, changes, handler);
}
pub fn update_host_focus_state(&mut self, is_host_focused: bool) {
self.state.update_host_focus_state(is_host_focused, None);
}
pub fn update_host_focus_state_and_process_changes(
&mut self,
is_host_focused: bool,
handler: &mut impl ChangeHandler,
) {
let mut changes = InternalChanges::default();
let old_state = self.state.clone();
self.state
.update_host_focus_state(is_host_focused, Some(&mut changes));
self.process_changes(old_state, changes, handler);
}
fn process_changes(
&self,
old_state: State,
changes: InternalChanges,
handler: &mut impl ChangeHandler,
) {
for id in &changes.added_node_ids {
let node = self.state.node_by_id(*id).unwrap();
handler.node_added(&node);
}
for id in &changes.updated_node_ids {
let old_node = old_state.node_by_id(*id).unwrap();
let new_node = self.state.node_by_id(*id).unwrap();
handler.node_updated(&old_node, &new_node);
}
if old_state.focus_id() != self.state.focus_id() {
let old_node = old_state.focus();
if let Some(old_node) = &old_node {
let id = old_node.id();
if !changes.updated_node_ids.contains(&id)
&& !changes.removed_node_ids.contains(&id)
{
if let Some(old_node_new_version) = self.state.node_by_id(id) {
handler.node_updated(old_node, &old_node_new_version);
}
}
}
let new_node = self.state.focus();
if let Some(new_node) = &new_node {
let id = new_node.id();
if !changes.added_node_ids.contains(&id) && !changes.updated_node_ids.contains(&id)
{
if let Some(new_node_old_version) = old_state.node_by_id(id) {
handler.node_updated(&new_node_old_version, new_node);
}
}
}
handler.focus_moved(old_node.as_ref(), new_node.as_ref());
}
for id in &changes.removed_node_ids {
let node = old_state.node_by_id(*id).unwrap();
handler.node_removed(&node);
}
}
pub fn state(&self) -> &State {
&self.state
}
}
struct ShortNodeList<'a, T>(&'a HashMap<NodeId, T>);
impl<T> fmt::Display for ShortNodeList<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
let mut iter = self.0.iter();
for i in 0..10 {
let Some((id, _)) = iter.next() else {
break;
};
if i != 0 {
write!(f, ", ")?;
}
write!(f, "#{}", id.0)?;
}
if iter.next().is_some() {
write!(f, " ...")?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use accesskit::{Node, NodeId, Role, Tree, TreeUpdate};
use alloc::vec;
#[test]
fn init_tree_with_root_node() {
let update = TreeUpdate {
nodes: vec![(NodeId(0), Node::new(Role::Window))],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let tree = super::Tree::new(update, false);
assert_eq!(NodeId(0), tree.state().root().id());
assert_eq!(Role::Window, tree.state().root().role());
assert!(tree.state().root().parent().is_none());
}
#[test]
fn root_node_has_children() {
let update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1), NodeId(2)]);
node
}),
(NodeId(1), Node::new(Role::Button)),
(NodeId(2), Node::new(Role::Button)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let tree = super::Tree::new(update, false);
let state = tree.state();
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
);
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(2)).unwrap().parent().unwrap().id()
);
assert_eq!(2, state.root().children().count());
}
#[test]
fn add_child_to_root_node() {
let root_node = Node::new(Role::Window);
let first_update = TreeUpdate {
nodes: vec![(NodeId(0), root_node.clone())],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(0, tree.state().root().children().count());
let second_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = root_node;
node.push_child(NodeId(1));
node
}),
(NodeId(1), Node::new(Role::RootWebArea)),
],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_new_child_node: bool,
got_updated_root_node: bool,
}
fn unexpected_change() {
panic!("expected only new child node and updated root node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, node: &crate::Node) {
if node.id() == NodeId(1) {
self.got_new_child_node = true;
return;
}
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(0)
&& old_node.data().children().is_empty()
&& new_node.data().children() == [NodeId(1)]
{
self.got_updated_root_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_new_child_node: false,
got_updated_root_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_new_child_node);
assert!(handler.got_updated_root_node);
let state = tree.state();
assert_eq!(1, state.root().children().count());
assert_eq!(NodeId(1), state.root().children().next().unwrap().id());
assert_eq!(
NodeId(0),
state.node_by_id(NodeId(1)).unwrap().parent().unwrap().id()
);
}
#[test]
fn remove_child_from_root_node() {
let root_node = Node::new(Role::Window);
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = root_node.clone();
node.push_child(NodeId(1));
node
}),
(NodeId(1), Node::new(Role::RootWebArea)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(1, tree.state().root().children().count());
let second_update = TreeUpdate {
nodes: vec![(NodeId(0), root_node)],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_updated_root_node: bool,
got_removed_child_node: bool,
}
fn unexpected_change() {
panic!("expected only removed child node and updated root node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(0)
&& old_node.data().children() == [NodeId(1)]
&& new_node.data().children().is_empty()
{
self.got_updated_root_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, node: &crate::Node) {
if node.id() == NodeId(1) {
self.got_removed_child_node = true;
return;
}
unexpected_change();
}
}
let mut handler = Handler {
got_updated_root_node: false,
got_removed_child_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_updated_root_node);
assert!(handler.got_removed_child_node);
assert_eq!(0, tree.state().root().children().count());
assert!(tree.state().node_by_id(NodeId(1)).is_none());
}
#[test]
fn move_focus_between_siblings() {
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1), NodeId(2)]);
node
}),
(NodeId(1), Node::new(Role::Button)),
(NodeId(2), Node::new(Role::Button)),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(1),
};
let mut tree = super::Tree::new(first_update, true);
assert!(tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
let second_update = TreeUpdate {
nodes: vec![],
tree: None,
focus: NodeId(2),
};
struct Handler {
got_old_focus_node_update: bool,
got_new_focus_node_update: bool,
got_focus_change: bool,
}
fn unexpected_change() {
panic!("expected only focus change");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if old_node.id() == NodeId(1)
&& new_node.id() == NodeId(1)
&& old_node.is_focused()
&& !new_node.is_focused()
{
self.got_old_focus_node_update = true;
return;
}
if old_node.id() == NodeId(2)
&& new_node.id() == NodeId(2)
&& !old_node.is_focused()
&& new_node.is_focused()
{
self.got_new_focus_node_update = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
old_node: Option<&crate::Node>,
new_node: Option<&crate::Node>,
) {
if let (Some(old_node), Some(new_node)) = (old_node, new_node) {
if old_node.id() == NodeId(1) && new_node.id() == NodeId(2) {
self.got_focus_change = true;
return;
}
}
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_old_focus_node_update: false,
got_new_focus_node_update: false,
got_focus_change: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_old_focus_node_update);
assert!(handler.got_new_focus_node_update);
assert!(handler.got_focus_change);
assert!(tree.state().node_by_id(NodeId(2)).unwrap().is_focused());
assert!(!tree.state().node_by_id(NodeId(1)).unwrap().is_focused());
}
#[test]
fn update_node() {
let child_node = Node::new(Role::Button);
let first_update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1)]);
node
}),
(NodeId(1), {
let mut node = child_node.clone();
node.set_label("foo");
node
}),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(first_update, false);
assert_eq!(
Some("foo".into()),
tree.state().node_by_id(NodeId(1)).unwrap().label()
);
let second_update = TreeUpdate {
nodes: vec![(NodeId(1), {
let mut node = child_node;
node.set_label("bar");
node
})],
tree: None,
focus: NodeId(0),
};
struct Handler {
got_updated_child_node: bool,
}
fn unexpected_change() {
panic!("expected only updated child node");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, old_node: &crate::Node, new_node: &crate::Node) {
if new_node.id() == NodeId(1)
&& old_node.label() == Some("foo".into())
&& new_node.label() == Some("bar".into())
{
self.got_updated_child_node = true;
return;
}
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {
got_updated_child_node: false,
};
tree.update_and_process_changes(second_update, &mut handler);
assert!(handler.got_updated_child_node);
assert_eq!(
Some("bar".into()),
tree.state().node_by_id(NodeId(1)).unwrap().label()
);
}
// Verify that if an update consists entirely of node data and tree data
// that's the same as before, no changes are reported. This is useful
// for a provider that constructs a fresh tree every time, such as
// an immediate-mode GUI.
#[test]
fn no_change_update() {
let update = TreeUpdate {
nodes: vec![
(NodeId(0), {
let mut node = Node::new(Role::Window);
node.set_children(vec![NodeId(1)]);
node
}),
(NodeId(1), {
let mut node = Node::new(Role::Button);
node.set_label("foo");
node
}),
],
tree: Some(Tree::new(NodeId(0))),
focus: NodeId(0),
};
let mut tree = super::Tree::new(update.clone(), false);
struct Handler;
fn unexpected_change() {
panic!("expected no changes");
}
impl super::ChangeHandler for Handler {
fn node_added(&mut self, _node: &crate::Node) {
unexpected_change();
}
fn node_updated(&mut self, _old_node: &crate::Node, _new_node: &crate::Node) {
unexpected_change();
}
fn focus_moved(
&mut self,
_old_node: Option<&crate::Node>,
_new_node: Option<&crate::Node>,
) {
unexpected_change();
}
fn node_removed(&mut self, _node: &crate::Node) {
unexpected_change();
}
}
let mut handler = Handler {};
tree.update_and_process_changes(update, &mut handler);
}
}