1#![cfg_attr(not(any(feature = "pyo3", feature = "schemars")), no_std)]
12
13extern crate alloc;
14
15use alloc::{boxed::Box, string::String, vec::Vec};
16use core::fmt;
17#[cfg(feature = "pyo3")]
18use pyo3::pyclass;
19#[cfg(feature = "schemars")]
20use schemars::{
21 gen::SchemaGenerator,
22 schema::{InstanceType, ObjectValidation, Schema, SchemaObject},
23 JsonSchema, Map as SchemaMap,
24};
25#[cfg(feature = "serde")]
26use serde::{
27 de::{Deserializer, IgnoredAny, MapAccess, Visitor},
28 ser::{SerializeMap, Serializer},
29 Deserialize, Serialize,
30};
31
32mod geometry;
33pub use geometry::{Affine, Point, Rect, Size, Vec2};
34
35#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[cfg_attr(feature = "enumn", derive(enumn::N))]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[cfg_attr(feature = "schemars", derive(JsonSchema))]
49#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
50#[cfg_attr(
51 feature = "pyo3",
52 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
53)]
54#[repr(u8)]
55pub enum Role {
56 #[default]
57 Unknown,
58 TextRun,
59 Cell,
60 Label,
61 Image,
62 Link,
63 Row,
64 ListItem,
65
66 ListMarker,
68
69 TreeItem,
70 ListBoxOption,
71 MenuItem,
72 MenuListOption,
73 Paragraph,
74
75 GenericContainer,
79
80 CheckBox,
81 RadioButton,
82 TextInput,
83 Button,
84 DefaultButton,
85 Pane,
86 RowHeader,
87 ColumnHeader,
88 RowGroup,
89 List,
90 Table,
91 LayoutTableCell,
92 LayoutTableRow,
93 LayoutTable,
94 Switch,
95 Menu,
96
97 MultilineTextInput,
98 SearchInput,
99 DateInput,
100 DateTimeInput,
101 WeekInput,
102 MonthInput,
103 TimeInput,
104 EmailInput,
105 NumberInput,
106 PasswordInput,
107 PhoneNumberInput,
108 UrlInput,
109
110 Abbr,
111 Alert,
112 AlertDialog,
113 Application,
114 Article,
115 Audio,
116 Banner,
117 Blockquote,
118 Canvas,
119 Caption,
120 Caret,
121 Code,
122 ColorWell,
123 ComboBox,
124 EditableComboBox,
125 Complementary,
126 Comment,
127 ContentDeletion,
128 ContentInsertion,
129 ContentInfo,
130 Definition,
131 DescriptionList,
132 DescriptionListDetail,
133 DescriptionListTerm,
134 Details,
135 Dialog,
136 Directory,
137 DisclosureTriangle,
138 Document,
139 EmbeddedObject,
140 Emphasis,
141 Feed,
142 FigureCaption,
143 Figure,
144 Footer,
145 FooterAsNonLandmark,
146 Form,
147 Grid,
148 Group,
149 Header,
150 HeaderAsNonLandmark,
151 Heading,
152 Iframe,
153 IframePresentational,
154 ImeCandidate,
155 Keyboard,
156 Legend,
157 LineBreak,
158 ListBox,
159 Log,
160 Main,
161 Mark,
162 Marquee,
163 Math,
164 MenuBar,
165 MenuItemCheckBox,
166 MenuItemRadio,
167 MenuListPopup,
168 Meter,
169 Navigation,
170 Note,
171 PluginObject,
172 Portal,
173 Pre,
174 ProgressIndicator,
175 RadioGroup,
176 Region,
177 RootWebArea,
178 Ruby,
179 RubyAnnotation,
180 ScrollBar,
181 ScrollView,
182 Search,
183 Section,
184 Slider,
185 SpinButton,
186 Splitter,
187 Status,
188 Strong,
189 Suggestion,
190 SvgRoot,
191 Tab,
192 TabList,
193 TabPanel,
194 Term,
195 Time,
196 Timer,
197 TitleBar,
198 Toolbar,
199 Tooltip,
200 Tree,
201 TreeGrid,
202 Video,
203 WebView,
204 Window,
205
206 PdfActionableHighlight,
207 PdfRoot,
208
209 GraphicsDocument,
212 GraphicsObject,
213 GraphicsSymbol,
214
215 DocAbstract,
218 DocAcknowledgements,
219 DocAfterword,
220 DocAppendix,
221 DocBackLink,
222 DocBiblioEntry,
223 DocBibliography,
224 DocBiblioRef,
225 DocChapter,
226 DocColophon,
227 DocConclusion,
228 DocCover,
229 DocCredit,
230 DocCredits,
231 DocDedication,
232 DocEndnote,
233 DocEndnotes,
234 DocEpigraph,
235 DocEpilogue,
236 DocErrata,
237 DocExample,
238 DocFootnote,
239 DocForeword,
240 DocGlossary,
241 DocGlossRef,
242 DocIndex,
243 DocIntroduction,
244 DocNoteRef,
245 DocNotice,
246 DocPageBreak,
247 DocPageFooter,
248 DocPageHeader,
249 DocPageList,
250 DocPart,
251 DocPreface,
252 DocPrologue,
253 DocPullquote,
254 DocQna,
255 DocSubtitle,
256 DocTip,
257 DocToc,
258
259 ListGrid,
263
264 Terminal,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
272#[cfg_attr(feature = "enumn", derive(enumn::N))]
273#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
274#[cfg_attr(feature = "schemars", derive(JsonSchema))]
275#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
276#[cfg_attr(
277 feature = "pyo3",
278 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
279)]
280#[repr(u8)]
281pub enum Action {
282 Click,
284
285 Focus,
286 Blur,
287
288 Collapse,
289 Expand,
290
291 CustomAction,
293
294 Decrement,
296 Increment,
298
299 HideTooltip,
300 ShowTooltip,
301
302 ReplaceSelectedText,
306
307 ScrollDown,
309 ScrollLeft,
311 ScrollRight,
313 ScrollUp,
315
316 ScrollIntoView,
319
320 ScrollToPoint,
324
325 SetScrollOffset,
327
328 SetTextSelection,
330
331 SetSequentialFocusNavigationStartingPoint,
335
336 SetValue,
340
341 ShowContextMenu,
342}
343
344impl Action {
345 fn mask(self) -> u32 {
346 1 << (self as u8)
347 }
348
349 #[cfg(not(feature = "enumn"))]
350 fn n(value: u8) -> Option<Self> {
351 match value {
355 0 => Some(Action::Click),
356 1 => Some(Action::Focus),
357 2 => Some(Action::Blur),
358 3 => Some(Action::Collapse),
359 4 => Some(Action::Expand),
360 5 => Some(Action::CustomAction),
361 6 => Some(Action::Decrement),
362 7 => Some(Action::Increment),
363 8 => Some(Action::HideTooltip),
364 9 => Some(Action::ShowTooltip),
365 10 => Some(Action::ReplaceSelectedText),
366 11 => Some(Action::ScrollDown),
367 12 => Some(Action::ScrollLeft),
368 13 => Some(Action::ScrollRight),
369 14 => Some(Action::ScrollUp),
370 15 => Some(Action::ScrollIntoView),
371 16 => Some(Action::ScrollToPoint),
372 17 => Some(Action::SetScrollOffset),
373 18 => Some(Action::SetTextSelection),
374 19 => Some(Action::SetSequentialFocusNavigationStartingPoint),
375 20 => Some(Action::SetValue),
376 21 => Some(Action::ShowContextMenu),
377 _ => None,
378 }
379 }
380}
381
382fn action_mask_to_action_vec(mask: u32) -> Vec<Action> {
383 let mut actions = Vec::new();
384 let mut i = 0;
385 while let Some(variant) = Action::n(i) {
386 if mask & variant.mask() != 0 {
387 actions.push(variant);
388 }
389 i += 1;
390 }
391 actions
392}
393
394#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
395#[cfg_attr(feature = "enumn", derive(enumn::N))]
396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
397#[cfg_attr(feature = "schemars", derive(JsonSchema))]
398#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
399#[cfg_attr(
400 feature = "pyo3",
401 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
402)]
403#[repr(u8)]
404pub enum Orientation {
405 Horizontal,
407 Vertical,
409}
410
411#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
412#[cfg_attr(feature = "enumn", derive(enumn::N))]
413#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
414#[cfg_attr(feature = "schemars", derive(JsonSchema))]
415#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
416#[cfg_attr(
417 feature = "pyo3",
418 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
419)]
420#[repr(u8)]
421pub enum TextDirection {
422 LeftToRight,
423 RightToLeft,
424 TopToBottom,
425 BottomToTop,
426}
427
428#[derive(Clone, Copy, Debug, PartialEq, Eq)]
433#[cfg_attr(feature = "enumn", derive(enumn::N))]
434#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
435#[cfg_attr(feature = "schemars", derive(JsonSchema))]
436#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
437#[cfg_attr(
438 feature = "pyo3",
439 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
440)]
441#[repr(u8)]
442pub enum Invalid {
443 True,
444 Grammar,
445 Spelling,
446}
447
448#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
449#[cfg_attr(feature = "enumn", derive(enumn::N))]
450#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
451#[cfg_attr(feature = "schemars", derive(JsonSchema))]
452#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
453#[cfg_attr(
454 feature = "pyo3",
455 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
456)]
457#[repr(u8)]
458pub enum Toggled {
459 False,
460 True,
461 Mixed,
462}
463
464impl From<bool> for Toggled {
465 #[inline]
466 fn from(b: bool) -> Self {
467 match b {
468 false => Self::False,
469 true => Self::True,
470 }
471 }
472}
473
474#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
475#[cfg_attr(feature = "enumn", derive(enumn::N))]
476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
477#[cfg_attr(feature = "schemars", derive(JsonSchema))]
478#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
479#[cfg_attr(
480 feature = "pyo3",
481 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
482)]
483#[repr(u8)]
484pub enum SortDirection {
485 Ascending,
486 Descending,
487 Other,
488}
489
490#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
491#[cfg_attr(feature = "enumn", derive(enumn::N))]
492#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
493#[cfg_attr(feature = "schemars", derive(JsonSchema))]
494#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
495#[cfg_attr(
496 feature = "pyo3",
497 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
498)]
499#[repr(u8)]
500pub enum AriaCurrent {
501 False,
502 True,
503 Page,
504 Step,
505 Location,
506 Date,
507 Time,
508}
509
510#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
511#[cfg_attr(feature = "enumn", derive(enumn::N))]
512#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
513#[cfg_attr(feature = "schemars", derive(JsonSchema))]
514#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
515#[cfg_attr(
516 feature = "pyo3",
517 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
518)]
519#[repr(u8)]
520pub enum AutoComplete {
521 Inline,
522 List,
523 Both,
524}
525
526#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
527#[cfg_attr(feature = "enumn", derive(enumn::N))]
528#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
529#[cfg_attr(feature = "schemars", derive(JsonSchema))]
530#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
531#[cfg_attr(
532 feature = "pyo3",
533 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
534)]
535#[repr(u8)]
536pub enum Live {
537 Off,
538 Polite,
539 Assertive,
540}
541
542#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
543#[cfg_attr(feature = "enumn", derive(enumn::N))]
544#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
545#[cfg_attr(feature = "schemars", derive(JsonSchema))]
546#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
547#[cfg_attr(
548 feature = "pyo3",
549 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
550)]
551#[repr(u8)]
552pub enum HasPopup {
553 Menu,
554 Listbox,
555 Tree,
556 Grid,
557 Dialog,
558}
559
560#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
561#[cfg_attr(feature = "enumn", derive(enumn::N))]
562#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
563#[cfg_attr(feature = "schemars", derive(JsonSchema))]
564#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
565#[cfg_attr(
566 feature = "pyo3",
567 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
568)]
569#[repr(u8)]
570pub enum ListStyle {
571 Circle,
572 Disc,
573 Image,
574 Numeric,
575 Square,
576 Other,
578}
579
580#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
581#[cfg_attr(feature = "enumn", derive(enumn::N))]
582#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
583#[cfg_attr(feature = "schemars", derive(JsonSchema))]
584#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
585#[cfg_attr(
586 feature = "pyo3",
587 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
588)]
589#[repr(u8)]
590pub enum TextAlign {
591 Left,
592 Right,
593 Center,
594 Justify,
595}
596
597#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
598#[cfg_attr(feature = "enumn", derive(enumn::N))]
599#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
600#[cfg_attr(feature = "schemars", derive(JsonSchema))]
601#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
602#[cfg_attr(
603 feature = "pyo3",
604 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
605)]
606#[repr(u8)]
607pub enum VerticalOffset {
608 Subscript,
609 Superscript,
610}
611
612#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
613#[cfg_attr(feature = "enumn", derive(enumn::N))]
614#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
615#[cfg_attr(feature = "schemars", derive(JsonSchema))]
616#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
617#[cfg_attr(
618 feature = "pyo3",
619 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
620)]
621#[repr(u8)]
622pub enum TextDecoration {
623 Solid,
624 Dotted,
625 Dashed,
626 Double,
627 Wavy,
628}
629
630pub type NodeIdContent = u64;
631
632#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
634#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
635#[cfg_attr(feature = "schemars", derive(JsonSchema))]
636#[repr(transparent)]
637pub struct NodeId(pub NodeIdContent);
638
639impl From<NodeIdContent> for NodeId {
640 #[inline]
641 fn from(inner: NodeIdContent) -> Self {
642 Self(inner)
643 }
644}
645
646impl From<NodeId> for NodeIdContent {
647 #[inline]
648 fn from(outer: NodeId) -> Self {
649 outer.0
650 }
651}
652
653impl fmt::Debug for NodeId {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 write!(f, "#{}", self.0)
656 }
657}
658
659#[derive(Clone, Debug, PartialEq, Eq)]
664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
665#[cfg_attr(feature = "schemars", derive(JsonSchema))]
666#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
667#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
668pub struct CustomAction {
669 pub id: i32,
670 pub description: Box<str>,
671}
672
673#[derive(Clone, Copy, Debug, PartialEq, Eq)]
674#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
675#[cfg_attr(feature = "schemars", derive(JsonSchema))]
676#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
677#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
678pub struct TextPosition {
679 pub node: NodeId,
681 pub character_index: usize,
684}
685
686#[derive(Clone, Copy, Debug, PartialEq, Eq)]
687#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
688#[cfg_attr(feature = "schemars", derive(JsonSchema))]
689#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
690#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
691pub struct TextSelection {
692 pub anchor: TextPosition,
697 pub focus: TextPosition,
701}
702
703#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
705#[cfg_attr(feature = "schemars", derive(JsonSchema))]
706#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
707#[repr(u8)]
708enum Flag {
709 Hidden,
710 Multiselectable,
711 Required,
712 Visited,
713 Busy,
714 LiveAtomic,
715 Modal,
716 TouchTransparent,
717 ReadOnly,
718 Disabled,
719 Bold,
720 Italic,
721 ClipsChildren,
722 IsLineBreakingObject,
723 IsPageBreakingObject,
724 IsSpellingError,
725 IsGrammarError,
726 IsSearchMatch,
727 IsSuggestion,
728}
729
730impl Flag {
731 fn mask(self) -> u32 {
732 1 << (self as u8)
733 }
734}
735
736#[derive(Clone, Debug, PartialEq)]
740enum PropertyValue {
741 None,
742 NodeIdVec(Vec<NodeId>),
743 NodeId(NodeId),
744 String(Box<str>),
745 F64(f64),
746 Usize(usize),
747 Color(u32),
748 TextDecoration(TextDecoration),
749 LengthSlice(Box<[u8]>),
750 CoordSlice(Box<[f32]>),
751 Bool(bool),
752 Invalid(Invalid),
753 Toggled(Toggled),
754 Live(Live),
755 TextDirection(TextDirection),
756 Orientation(Orientation),
757 SortDirection(SortDirection),
758 AriaCurrent(AriaCurrent),
759 AutoComplete(AutoComplete),
760 HasPopup(HasPopup),
761 ListStyle(ListStyle),
762 TextAlign(TextAlign),
763 VerticalOffset(VerticalOffset),
764 Affine(Box<Affine>),
765 Rect(Rect),
766 TextSelection(Box<TextSelection>),
767 CustomActionVec(Vec<CustomAction>),
768}
769
770#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
771#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
772#[cfg_attr(feature = "schemars", derive(JsonSchema))]
773#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
774#[repr(u8)]
775enum PropertyId {
776 Children,
778 Controls,
779 Details,
780 DescribedBy,
781 FlowTo,
782 LabelledBy,
783 Owns,
784 RadioGroup,
785
786 ActiveDescendant,
788 ErrorMessage,
789 InPageLinkTarget,
790 MemberOf,
791 NextOnLine,
792 PreviousOnLine,
793 PopupFor,
794
795 Label,
797 Description,
798 Value,
799 AccessKey,
800 AuthorId,
801 ClassName,
802 FontFamily,
803 HtmlTag,
804 InnerHtml,
805 KeyboardShortcut,
806 Language,
807 Placeholder,
808 RoleDescription,
809 StateDescription,
810 Tooltip,
811 Url,
812 RowIndexText,
813 ColumnIndexText,
814
815 ScrollX,
817 ScrollXMin,
818 ScrollXMax,
819 ScrollY,
820 ScrollYMin,
821 ScrollYMax,
822 NumericValue,
823 MinNumericValue,
824 MaxNumericValue,
825 NumericValueStep,
826 NumericValueJump,
827 FontSize,
828 FontWeight,
829
830 RowCount,
832 ColumnCount,
833 RowIndex,
834 ColumnIndex,
835 RowSpan,
836 ColumnSpan,
837 Level,
838 SizeOfSet,
839 PositionInSet,
840
841 ColorValue,
843 BackgroundColor,
844 ForegroundColor,
845
846 Overline,
848 Strikethrough,
849 Underline,
850
851 CharacterLengths,
853 WordLengths,
854
855 CharacterPositions,
857 CharacterWidths,
858
859 Expanded,
861 Selected,
862
863 Invalid,
865 Toggled,
866 Live,
867 TextDirection,
868 Orientation,
869 SortDirection,
870 AriaCurrent,
871 AutoComplete,
872 HasPopup,
873 ListStyle,
874 TextAlign,
875 VerticalOffset,
876
877 Transform,
879 Bounds,
880 TextSelection,
881 CustomActions,
882
883 Unset,
885}
886
887#[derive(Clone, Copy, Debug, PartialEq, Eq)]
888#[repr(transparent)]
889struct PropertyIndices([u8; PropertyId::Unset as usize]);
890
891impl Default for PropertyIndices {
892 fn default() -> Self {
893 Self([PropertyId::Unset as u8; PropertyId::Unset as usize])
894 }
895}
896
897#[derive(Clone, Debug, Default, PartialEq)]
898struct Properties {
899 indices: PropertyIndices,
900 values: Vec<PropertyValue>,
901}
902
903#[derive(Clone, Default, PartialEq)]
910#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
911#[cfg_attr(feature = "schemars", derive(JsonSchema))]
912#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
913#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
914pub struct Node {
915 role: Role,
916 actions: u32,
917 child_actions: u32,
918 flags: u32,
919 properties: Properties,
920}
921
922impl PropertyIndices {
923 fn get<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a PropertyValue {
924 let index = self.0[id as usize];
925 if index == PropertyId::Unset as u8 {
926 &PropertyValue::None
927 } else {
928 &values[index as usize]
929 }
930 }
931}
932
933impl Properties {
934 fn get_mut(&mut self, id: PropertyId, default: PropertyValue) -> &mut PropertyValue {
935 let index = self.indices.0[id as usize] as usize;
936 if index == PropertyId::Unset as usize {
937 self.values.push(default);
938 let index = self.values.len() - 1;
939 self.indices.0[id as usize] = index as u8;
940 &mut self.values[index]
941 } else {
942 &mut self.values[index]
943 }
944 }
945
946 fn set(&mut self, id: PropertyId, value: PropertyValue) {
947 let index = self.indices.0[id as usize];
948 if index == PropertyId::Unset as u8 {
949 self.values.push(value);
950 self.indices.0[id as usize] = (self.values.len() - 1) as u8;
951 } else {
952 self.values[index as usize] = value;
953 }
954 }
955
956 fn clear(&mut self, id: PropertyId) {
957 let index = self.indices.0[id as usize];
958 if index != PropertyId::Unset as u8 {
959 self.values[index as usize] = PropertyValue::None;
960 }
961 }
962}
963
964macro_rules! flag_methods {
965 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
966 impl Node {
967 $($(#[$doc])*
968 #[inline]
969 pub fn $getter(&self) -> bool {
970 (self.flags & (Flag::$id).mask()) != 0
971 }
972 #[inline]
973 pub fn $setter(&mut self) {
974 self.flags |= (Flag::$id).mask();
975 }
976 #[inline]
977 pub fn $clearer(&mut self) {
978 self.flags &= !((Flag::$id).mask());
979 })*
980 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
981 $(
982 if self.$getter() {
983 fmt.field(stringify!($getter), &true);
984 }
985 )*
986 }
987 }
988 $(#[cfg(test)]
989 mod $getter {
990 use super::{Node, Role};
991
992 #[test]
993 fn getter_should_return_default_value() {
994 let node = Node::new(Role::Unknown);
995 assert!(!node.$getter());
996 }
997
998 #[test]
999 fn setter_should_update_the_property() {
1000 let mut node = Node::new(Role::Unknown);
1001 node.$setter();
1002 assert!(node.$getter());
1003 }
1004
1005 #[test]
1006 fn clearer_should_reset_the_property() {
1007 let mut node = Node::new(Role::Unknown);
1008 node.$setter();
1009 node.$clearer();
1010 assert!(!node.$getter());
1011 }
1012 })*
1013 }
1014}
1015
1016macro_rules! option_ref_type_getters {
1017 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1018 impl PropertyIndices {
1019 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> Option<&'a $type> {
1020 match self.get(values, id) {
1021 PropertyValue::$variant(value) => Some(value),
1022 _ => None,
1023 }
1024 })*
1025 }
1026 }
1027}
1028
1029macro_rules! slice_type_getters {
1030 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1031 impl PropertyIndices {
1032 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a [$type] {
1033 match self.get(values, id) {
1034 PropertyValue::$variant(value) => value,
1035 _ => &[],
1036 }
1037 })*
1038 }
1039 }
1040}
1041
1042macro_rules! copy_type_getters {
1043 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1044 impl PropertyIndices {
1045 $(fn $method(&self, values: &[PropertyValue], id: PropertyId) -> Option<$type> {
1046 match self.get(values, id) {
1047 PropertyValue::$variant(value) => Some(*value),
1048 _ => None,
1049 }
1050 })*
1051 }
1052 }
1053}
1054
1055macro_rules! box_type_setters {
1056 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1057 impl Node {
1058 $(fn $method(&mut self, id: PropertyId, value: impl Into<Box<$type>>) {
1059 self.properties.set(id, PropertyValue::$variant(value.into()));
1060 })*
1061 }
1062 }
1063}
1064
1065macro_rules! copy_type_setters {
1066 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1067 impl Node {
1068 $(fn $method(&mut self, id: PropertyId, value: $type) {
1069 self.properties.set(id, PropertyValue::$variant(value));
1070 })*
1071 }
1072 }
1073}
1074
1075macro_rules! vec_type_methods {
1076 ($(($type:ty, $variant:ident, $getter:ident, $setter:ident, $pusher:ident)),+) => {
1077 $(slice_type_getters! {
1078 ($getter, $type, $variant)
1079 })*
1080 impl Node {
1081 $(fn $setter(&mut self, id: PropertyId, value: impl Into<Vec<$type>>) {
1082 self.properties.set(id, PropertyValue::$variant(value.into()));
1083 }
1084 fn $pusher(&mut self, id: PropertyId, item: $type) {
1085 if let PropertyValue::$variant(v) = self.properties.get_mut(id, PropertyValue::$variant(Vec::new())) {
1086 v.push(item);
1087 }
1088 })*
1089 }
1090 }
1091}
1092
1093macro_rules! property_methods {
1094 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $type_getter:ident, $getter_result:ty, $setter:ident, $type_setter:ident, $setter_param:ty, $clearer:ident)),+) => {
1095 impl Node {
1096 $($(#[$doc])*
1097 #[inline]
1098 pub fn $getter(&self) -> $getter_result {
1099 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1100 }
1101 #[inline]
1102 pub fn $setter(&mut self, value: $setter_param) {
1103 self.$type_setter(PropertyId::$id, value);
1104 }
1105 #[inline]
1106 pub fn $clearer(&mut self) {
1107 self.properties.clear(PropertyId::$id);
1108 })*
1109 }
1110 }
1111}
1112
1113macro_rules! vec_property_methods {
1114 ($($(#[$doc:meta])* ($id:ident, $item_type:ty, $getter:ident, $type_getter:ident, $setter:ident, $type_setter:ident, $pusher:ident, $type_pusher:ident, $clearer:ident)),+) => {
1115 $(property_methods! {
1116 $(#[$doc])*
1117 ($id, $getter, $type_getter, &[$item_type], $setter, $type_setter, impl Into<Vec<$item_type>>, $clearer)
1118 }
1119 impl Node {
1120 #[inline]
1121 pub fn $pusher(&mut self, item: $item_type) {
1122 self.$type_pusher(PropertyId::$id, item);
1123 }
1124 })*
1125 }
1126}
1127
1128macro_rules! slice_properties_debug_method {
1129 ($name:ident, [$($getter:ident,)*]) => {
1130 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1131 $(
1132 let value = self.$getter();
1133 if !value.is_empty() {
1134 fmt.field(stringify!($getter), &value);
1135 }
1136 )*
1137 }
1138 }
1139}
1140
1141macro_rules! node_id_vec_property_methods {
1142 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $pusher:ident, $clearer:ident)),+) => {
1143 $(vec_property_methods! {
1144 $(#[$doc])*
1145 ($id, NodeId, $getter, get_node_id_vec, $setter, set_node_id_vec, $pusher, push_to_node_id_vec, $clearer)
1146 })*
1147 impl Node {
1148 slice_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1149 }
1150 $(#[cfg(test)]
1151 mod $getter {
1152 use super::{Node, NodeId, Role};
1153
1154 #[test]
1155 fn getter_should_return_default_value() {
1156 let node = Node::new(Role::Unknown);
1157 assert!(node.$getter().is_empty());
1158 }
1159 #[test]
1160 fn setter_should_update_the_property() {
1161 let mut node = Node::new(Role::Unknown);
1162 node.$setter([]);
1163 assert!(node.$getter().is_empty());
1164 node.$setter([NodeId(0), NodeId(1)]);
1165 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1166 }
1167 #[test]
1168 fn pusher_should_update_the_property() {
1169 let mut node = Node::new(Role::Unknown);
1170 node.$pusher(NodeId(0));
1171 assert_eq!(node.$getter(), &[NodeId(0)]);
1172 node.$pusher(NodeId(1));
1173 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1174 }
1175 #[test]
1176 fn clearer_should_reset_the_property() {
1177 let mut node = Node::new(Role::Unknown);
1178 node.$setter([NodeId(0)]);
1179 node.$clearer();
1180 assert!(node.$getter().is_empty());
1181 }
1182 })*
1183 }
1184}
1185
1186macro_rules! option_properties_debug_method {
1187 ($name:ident, [$($getter:ident,)*]) => {
1188 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1189 $(
1190 if let Some(value) = self.$getter() {
1191 fmt.field(stringify!($getter), &value);
1192 }
1193 )*
1194 }
1195 }
1196}
1197
1198macro_rules! node_id_property_methods {
1199 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1200 $(property_methods! {
1201 $(#[$doc])*
1202 ($id, $getter, get_node_id_property, Option<NodeId>, $setter, set_node_id_property, NodeId, $clearer)
1203 })*
1204 impl Node {
1205 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1206 }
1207 $(#[cfg(test)]
1208 mod $getter {
1209 use super::{Node, NodeId, Role};
1210
1211 #[test]
1212 fn getter_should_return_default_value() {
1213 let node = Node::new(Role::Unknown);
1214 assert!(node.$getter().is_none());
1215 }
1216 #[test]
1217 fn setter_should_update_the_property() {
1218 let mut node = Node::new(Role::Unknown);
1219 node.$setter(NodeId(1));
1220 assert_eq!(node.$getter(), Some(NodeId(1)));
1221 }
1222 #[test]
1223 fn clearer_should_reset_the_property() {
1224 let mut node = Node::new(Role::Unknown);
1225 node.$setter(NodeId(1));
1226 node.$clearer();
1227 assert!(node.$getter().is_none());
1228 }
1229 })*
1230 }
1231}
1232
1233macro_rules! string_property_methods {
1234 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1235 $(property_methods! {
1236 $(#[$doc])*
1237 ($id, $getter, get_string_property, Option<&str>, $setter, set_string_property, impl Into<Box<str>>, $clearer)
1238 })*
1239 impl Node {
1240 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1241 }
1242 $(#[cfg(test)]
1243 mod $getter {
1244 use super::{Node, Role};
1245
1246 #[test]
1247 fn getter_should_return_default_value() {
1248 let node = Node::new(Role::Unknown);
1249 assert!(node.$getter().is_none());
1250 }
1251 #[test]
1252 fn setter_should_update_the_property() {
1253 let mut node = Node::new(Role::Unknown);
1254 node.$setter("test");
1255 assert_eq!(node.$getter(), Some("test"));
1256 }
1257 #[test]
1258 fn clearer_should_reset_the_property() {
1259 let mut node = Node::new(Role::Unknown);
1260 node.$setter("test");
1261 node.$clearer();
1262 assert!(node.$getter().is_none());
1263 }
1264 })*
1265 }
1266}
1267
1268macro_rules! f64_property_methods {
1269 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1270 $(property_methods! {
1271 $(#[$doc])*
1272 ($id, $getter, get_f64_property, Option<f64>, $setter, set_f64_property, f64, $clearer)
1273 })*
1274 impl Node {
1275 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1276 }
1277 $(#[cfg(test)]
1278 mod $getter {
1279 use super::{Node, Role};
1280
1281 #[test]
1282 fn getter_should_return_default_value() {
1283 let node = Node::new(Role::Unknown);
1284 assert!(node.$getter().is_none());
1285 }
1286 #[test]
1287 fn setter_should_update_the_property() {
1288 let mut node = Node::new(Role::Unknown);
1289 node.$setter(1.0);
1290 assert_eq!(node.$getter(), Some(1.0));
1291 }
1292 #[test]
1293 fn clearer_should_reset_the_property() {
1294 let mut node = Node::new(Role::Unknown);
1295 node.$setter(1.0);
1296 node.$clearer();
1297 assert!(node.$getter().is_none());
1298 }
1299 })*
1300 }
1301}
1302
1303macro_rules! usize_property_methods {
1304 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1305 $(property_methods! {
1306 $(#[$doc])*
1307 ($id, $getter, get_usize_property, Option<usize>, $setter, set_usize_property, usize, $clearer)
1308 })*
1309 impl Node {
1310 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1311 }
1312 $(#[cfg(test)]
1313 mod $getter {
1314 use super::{Node, Role};
1315
1316 #[test]
1317 fn getter_should_return_default_value() {
1318 let node = Node::new(Role::Unknown);
1319 assert!(node.$getter().is_none());
1320 }
1321 #[test]
1322 fn setter_should_update_the_property() {
1323 let mut node = Node::new(Role::Unknown);
1324 node.$setter(1);
1325 assert_eq!(node.$getter(), Some(1));
1326 }
1327 #[test]
1328 fn clearer_should_reset_the_property() {
1329 let mut node = Node::new(Role::Unknown);
1330 node.$setter(1);
1331 node.$clearer();
1332 assert!(node.$getter().is_none());
1333 }
1334 })*
1335 }
1336}
1337
1338macro_rules! color_property_methods {
1339 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1340 $(property_methods! {
1341 $(#[$doc])*
1342 ($id, $getter, get_color_property, Option<u32>, $setter, set_color_property, u32, $clearer)
1343 })*
1344 impl Node {
1345 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1346 }
1347 $(#[cfg(test)]
1348 mod $getter {
1349 use super::{Node, Role};
1350
1351 #[test]
1352 fn getter_should_return_default_value() {
1353 let node = Node::new(Role::Unknown);
1354 assert!(node.$getter().is_none());
1355 }
1356 #[test]
1357 fn setter_should_update_the_property() {
1358 let mut node = Node::new(Role::Unknown);
1359 node.$setter(1);
1360 assert_eq!(node.$getter(), Some(1));
1361 }
1362 #[test]
1363 fn clearer_should_reset_the_property() {
1364 let mut node = Node::new(Role::Unknown);
1365 node.$setter(1);
1366 node.$clearer();
1367 assert!(node.$getter().is_none());
1368 }
1369 })*
1370 }
1371}
1372
1373macro_rules! text_decoration_property_methods {
1374 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1375 $(property_methods! {
1376 $(#[$doc])*
1377 ($id, $getter, get_text_decoration_property, Option<TextDecoration>, $setter, set_text_decoration_property, TextDecoration, $clearer)
1378 })*
1379 impl Node {
1380 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1381 }
1382 $(#[cfg(test)]
1383 mod $getter {
1384 use super::{Node, Role, TextDecoration};
1385
1386 #[test]
1387 fn getter_should_return_default_value() {
1388 let node = Node::new(Role::Unknown);
1389 assert!(node.$getter().is_none());
1390 }
1391 #[test]
1392 fn setter_should_update_the_property() {
1393 let mut node = Node::new(Role::Unknown);
1394 node.$setter(TextDecoration::Dotted);
1395 assert_eq!(node.$getter(), Some(TextDecoration::Dotted));
1396 }
1397 #[test]
1398 fn clearer_should_reset_the_property() {
1399 let mut node = Node::new(Role::Unknown);
1400 node.$setter(TextDecoration::Dotted);
1401 node.$clearer();
1402 assert!(node.$getter().is_none());
1403 }
1404 })*
1405 }
1406}
1407
1408macro_rules! length_slice_property_methods {
1409 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1410 $(property_methods! {
1411 $(#[$doc])*
1412 ($id, $getter, get_length_slice_property, &[u8], $setter, set_length_slice_property, impl Into<Box<[u8]>>, $clearer)
1413 })*
1414 impl Node {
1415 slice_properties_debug_method! { debug_length_slice_properties, [$($getter,)*] }
1416 }
1417 $(#[cfg(test)]
1418 mod $getter {
1419 use super::{Node, Role};
1420
1421 #[test]
1422 fn getter_should_return_default_value() {
1423 let node = Node::new(Role::Unknown);
1424 assert!(node.$getter().is_empty());
1425 }
1426 #[test]
1427 fn setter_should_update_the_property() {
1428 let mut node = Node::new(Role::Unknown);
1429 node.$setter([]);
1430 assert!(node.$getter().is_empty());
1431 node.$setter([1, 2]);
1432 assert_eq!(node.$getter(), &[1, 2]);
1433 }
1434 #[test]
1435 fn clearer_should_reset_the_property() {
1436 let mut node = Node::new(Role::Unknown);
1437 node.$setter([1, 2]);
1438 node.$clearer();
1439 assert!(node.$getter().is_empty());
1440 }
1441 })*
1442 }
1443}
1444
1445macro_rules! coord_slice_property_methods {
1446 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1447 $(property_methods! {
1448 $(#[$doc])*
1449 ($id, $getter, get_coord_slice_property, Option<&[f32]>, $setter, set_coord_slice_property, impl Into<Box<[f32]>>, $clearer)
1450 })*
1451 impl Node {
1452 option_properties_debug_method! { debug_coord_slice_properties, [$($getter,)*] }
1453 }
1454 $(#[cfg(test)]
1455 mod $getter {
1456 use super::{Node, Role};
1457
1458 #[test]
1459 fn getter_should_return_default_value() {
1460 let node = Node::new(Role::Unknown);
1461 assert!(node.$getter().is_none());
1462 }
1463 #[test]
1464 fn setter_should_update_the_property() {
1465 let mut node = Node::new(Role::Unknown);
1466 node.$setter([]);
1467 let expected: Option<&[f32]> = Some(&[]);
1468 assert_eq!(node.$getter(), expected);
1469 node.$setter([1.0, 2.0]);
1470 let expected: Option<&[f32]> = Some(&[1.0, 2.0]);
1471 assert_eq!(node.$getter(), expected);
1472 }
1473 #[test]
1474 fn clearer_should_reset_the_property() {
1475 let mut node = Node::new(Role::Unknown);
1476 node.$setter([1.0, 2.0]);
1477 node.$clearer();
1478 assert!(node.$getter().is_none());
1479 }
1480 })*
1481 }
1482}
1483
1484macro_rules! bool_property_methods {
1485 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1486 $(property_methods! {
1487 $(#[$doc])*
1488 ($id, $getter, get_bool_property, Option<bool>, $setter, set_bool_property, bool, $clearer)
1489 })*
1490 impl Node {
1491 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1492 }
1493 $(#[cfg(test)]
1494 mod $getter {
1495 use super::{Node, Role};
1496
1497 #[test]
1498 fn getter_should_return_default_value() {
1499 let node = Node::new(Role::Unknown);
1500 assert!(node.$getter().is_none());
1501 }
1502 #[test]
1503 fn setter_should_update_the_property() {
1504 let mut node = Node::new(Role::Unknown);
1505 node.$setter(true);
1506 assert_eq!(node.$getter(), Some(true));
1507 }
1508 #[test]
1509 fn clearer_should_reset_the_property() {
1510 let mut node = Node::new(Role::Unknown);
1511 node.$setter(true);
1512 node.$clearer();
1513 assert!(node.$getter().is_none());
1514 }
1515 })*
1516 }
1517}
1518
1519macro_rules! unique_enum_property_methods {
1520 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident, $variant:ident)),+) => {
1521 impl Node {
1522 $($(#[$doc])*
1523 #[inline]
1524 pub fn $getter(&self) -> Option<$id> {
1525 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1526 PropertyValue::$id(value) => Some(*value),
1527 _ => None,
1528 }
1529 }
1530 #[inline]
1531 pub fn $setter(&mut self, value: $id) {
1532 self.properties.set(PropertyId::$id, PropertyValue::$id(value));
1533 }
1534 #[inline]
1535 pub fn $clearer(&mut self) {
1536 self.properties.clear(PropertyId::$id);
1537 })*
1538 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1539 }
1540 $(#[cfg(test)]
1541 mod $getter {
1542 use super::{Node, Role};
1543
1544 #[test]
1545 fn getter_should_return_default_value() {
1546 let node = Node::new(Role::Unknown);
1547 assert!(node.$getter().is_none());
1548 }
1549 #[test]
1550 fn setter_should_update_the_property() {
1551 let mut node = Node::new(Role::Unknown);
1552 let variant = super::$id::$variant;
1553 node.$setter(variant);
1554 assert_eq!(node.$getter(), Some(variant));
1555 }
1556 #[test]
1557 fn clearer_should_reset_the_property() {
1558 let mut node = Node::new(Role::Unknown);
1559 node.$setter(super::$id::$variant);
1560 node.$clearer();
1561 assert!(node.$getter().is_none());
1562 }
1563 })*
1564 }
1565}
1566
1567impl Node {
1568 #[inline]
1569 pub fn new(role: Role) -> Self {
1570 Self {
1571 role,
1572 ..Default::default()
1573 }
1574 }
1575}
1576
1577impl Node {
1578 #[inline]
1579 pub fn role(&self) -> Role {
1580 self.role
1581 }
1582 #[inline]
1583 pub fn set_role(&mut self, value: Role) {
1584 self.role = value;
1585 }
1586
1587 #[inline]
1588 pub fn supports_action(&self, action: Action) -> bool {
1589 (self.actions & action.mask()) != 0
1590 }
1591 #[inline]
1592 pub fn add_action(&mut self, action: Action) {
1593 self.actions |= action.mask();
1594 }
1595 #[inline]
1596 pub fn remove_action(&mut self, action: Action) {
1597 self.actions &= !(action.mask());
1598 }
1599 #[inline]
1600 pub fn clear_actions(&mut self) {
1601 self.actions = 0;
1602 }
1603
1604 #[inline]
1607 pub fn child_supports_action(&self, action: Action) -> bool {
1608 (self.child_actions & action.mask()) != 0
1609 }
1610 #[inline]
1613 pub fn add_child_action(&mut self, action: Action) {
1614 self.child_actions |= action.mask();
1615 }
1616 #[inline]
1619 pub fn remove_child_action(&mut self, action: Action) {
1620 self.child_actions &= !(action.mask());
1621 }
1622 #[inline]
1625 pub fn clear_child_actions(&mut self) {
1626 self.child_actions = 0;
1627 }
1628}
1629
1630flag_methods! {
1631 (Hidden, is_hidden, set_hidden, clear_hidden),
1634 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1635 (Required, is_required, set_required, clear_required),
1636 (Visited, is_visited, set_visited, clear_visited),
1637 (Busy, is_busy, set_busy, clear_busy),
1638 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1639 (Modal, is_modal, set_modal, clear_modal),
1641 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1645 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1647 (Disabled, is_disabled, set_disabled, clear_disabled),
1649 (Bold, is_bold, set_bold, clear_bold),
1650 (Italic, is_italic, set_italic, clear_italic),
1651 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1654 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1657 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1659 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1660 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1661 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1662 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1663}
1664
1665option_ref_type_getters! {
1666 (get_affine_property, Affine, Affine),
1667 (get_string_property, str, String),
1668 (get_coord_slice_property, [f32], CoordSlice),
1669 (get_text_selection_property, TextSelection, TextSelection)
1670}
1671
1672slice_type_getters! {
1673 (get_length_slice_property, u8, LengthSlice)
1674}
1675
1676copy_type_getters! {
1677 (get_rect_property, Rect, Rect),
1678 (get_node_id_property, NodeId, NodeId),
1679 (get_f64_property, f64, F64),
1680 (get_usize_property, usize, Usize),
1681 (get_color_property, u32, Color),
1682 (get_text_decoration_property, TextDecoration, TextDecoration),
1683 (get_bool_property, bool, Bool)
1684}
1685
1686box_type_setters! {
1687 (set_affine_property, Affine, Affine),
1688 (set_string_property, str, String),
1689 (set_length_slice_property, [u8], LengthSlice),
1690 (set_coord_slice_property, [f32], CoordSlice),
1691 (set_text_selection_property, TextSelection, TextSelection)
1692}
1693
1694copy_type_setters! {
1695 (set_rect_property, Rect, Rect),
1696 (set_node_id_property, NodeId, NodeId),
1697 (set_f64_property, f64, F64),
1698 (set_usize_property, usize, Usize),
1699 (set_color_property, u32, Color),
1700 (set_text_decoration_property, TextDecoration, TextDecoration),
1701 (set_bool_property, bool, Bool)
1702}
1703
1704vec_type_methods! {
1705 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
1706 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
1707}
1708
1709node_id_vec_property_methods! {
1710 (Children, children, set_children, push_child, clear_children),
1711 (Controls, controls, set_controls, push_controlled, clear_controls),
1712 (Details, details, set_details, push_detail, clear_details),
1713 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
1714 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
1715 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
1716 (Owns, owns, set_owns, push_owned, clear_owns),
1722 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
1725}
1726
1727node_id_property_methods! {
1728 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
1729 (ErrorMessage, error_message, set_error_message, clear_error_message),
1730 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
1731 (MemberOf, member_of, set_member_of, clear_member_of),
1732 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
1733 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
1734 (PopupFor, popup_for, set_popup_for, clear_popup_for)
1735}
1736
1737string_property_methods! {
1738 (Label, label, set_label, clear_label),
1743 (Description, description, set_description, clear_description),
1744 (Value, value, set_value, clear_value),
1745 (AccessKey, access_key, set_access_key, clear_access_key),
1753 (AuthorId, author_id, set_author_id, clear_author_id),
1756 (ClassName, class_name, set_class_name, clear_class_name),
1757 (FontFamily, font_family, set_font_family, clear_font_family),
1759 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
1760 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
1763 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
1767 (Language, language, set_language, clear_language),
1769 (Placeholder, placeholder, set_placeholder, clear_placeholder),
1774 (RoleDescription, role_description, set_role_description, clear_role_description),
1778 (StateDescription, state_description, set_state_description, clear_state_description),
1783 (Tooltip, tooltip, set_tooltip, clear_tooltip),
1788 (Url, url, set_url, clear_url),
1789 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
1790 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text)
1791}
1792
1793f64_property_methods! {
1794 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
1795 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
1796 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
1797 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
1798 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
1799 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
1800 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
1801 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
1802 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
1803 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
1804 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump),
1805 (FontSize, font_size, set_font_size, clear_font_size),
1807 (FontWeight, font_weight, set_font_weight, clear_font_weight)
1810}
1811
1812usize_property_methods! {
1813 (RowCount, row_count, set_row_count, clear_row_count),
1814 (ColumnCount, column_count, set_column_count, clear_column_count),
1815 (RowIndex, row_index, set_row_index, clear_row_index),
1816 (ColumnIndex, column_index, set_column_index, clear_column_index),
1817 (RowSpan, row_span, set_row_span, clear_row_span),
1818 (ColumnSpan, column_span, set_column_span, clear_column_span),
1819 (Level, level, set_level, clear_level),
1820 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
1822 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
1827}
1828
1829color_property_methods! {
1830 (ColorValue, color_value, set_color_value, clear_color_value),
1832 (BackgroundColor, background_color, set_background_color, clear_background_color),
1834 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
1836}
1837
1838text_decoration_property_methods! {
1839 (Overline, overline, set_overline, clear_overline),
1840 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
1841 (Underline, underline, set_underline, clear_underline)
1842}
1843
1844length_slice_property_methods! {
1845 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
1864
1865 (WordLengths, word_lengths, set_word_lengths, clear_word_lengths)
1888}
1889
1890coord_slice_property_methods! {
1891 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
1908
1909 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
1928}
1929
1930bool_property_methods! {
1931 (Expanded, is_expanded, set_expanded, clear_expanded),
1936
1937 (Selected, is_selected, set_selected, clear_selected)
1947}
1948
1949unique_enum_property_methods! {
1950 (Invalid, invalid, set_invalid, clear_invalid, Grammar),
1951 (Toggled, toggled, set_toggled, clear_toggled, True),
1952 (Live, live, set_live, clear_live, Polite),
1953 (TextDirection, text_direction, set_text_direction, clear_text_direction, RightToLeft),
1954 (Orientation, orientation, set_orientation, clear_orientation, Vertical),
1955 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction, Descending),
1956 (AriaCurrent, aria_current, set_aria_current, clear_aria_current, True),
1957 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete, List),
1958 (HasPopup, has_popup, set_has_popup, clear_has_popup, Menu),
1959 (ListStyle, list_style, set_list_style, clear_list_style, Disc),
1961 (TextAlign, text_align, set_text_align, clear_text_align, Right),
1962 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset, Superscript)
1963}
1964
1965property_methods! {
1966 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
1979
1980 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
1991
1992 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection)
1993}
1994
1995impl Node {
1996 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1997}
1998
1999#[cfg(test)]
2000mod transform {
2001 use super::{Affine, Node, Role};
2002
2003 #[test]
2004 fn getter_should_return_default_value() {
2005 let node = Node::new(Role::Unknown);
2006 assert!(node.transform().is_none());
2007 }
2008 #[test]
2009 fn setter_should_update_the_property() {
2010 let mut node = Node::new(Role::Unknown);
2011 node.set_transform(Affine::IDENTITY);
2012 assert_eq!(node.transform(), Some(&Affine::IDENTITY));
2013 }
2014 #[test]
2015 fn clearer_should_reset_the_property() {
2016 let mut node = Node::new(Role::Unknown);
2017 node.set_transform(Affine::IDENTITY);
2018 node.clear_transform();
2019 assert!(node.transform().is_none());
2020 }
2021}
2022
2023#[cfg(test)]
2024mod bounds {
2025 use super::{Node, Rect, Role};
2026
2027 #[test]
2028 fn getter_should_return_default_value() {
2029 let node = Node::new(Role::Unknown);
2030 assert!(node.bounds().is_none());
2031 }
2032 #[test]
2033 fn setter_should_update_the_property() {
2034 let mut node = Node::new(Role::Unknown);
2035 let value = Rect {
2036 x0: 0.0,
2037 y0: 1.0,
2038 x1: 2.0,
2039 y1: 3.0,
2040 };
2041 node.set_bounds(value);
2042 assert_eq!(node.bounds(), Some(value));
2043 }
2044 #[test]
2045 fn clearer_should_reset_the_property() {
2046 let mut node = Node::new(Role::Unknown);
2047 node.set_bounds(Rect {
2048 x0: 0.0,
2049 y0: 1.0,
2050 x1: 2.0,
2051 y1: 3.0,
2052 });
2053 node.clear_bounds();
2054 assert!(node.bounds().is_none());
2055 }
2056}
2057
2058#[cfg(test)]
2059mod text_selection {
2060 use super::{Node, NodeId, Role, TextPosition, TextSelection};
2061
2062 #[test]
2063 fn getter_should_return_default_value() {
2064 let node = Node::new(Role::Unknown);
2065 assert!(node.text_selection().is_none());
2066 }
2067 #[test]
2068 fn setter_should_update_the_property() {
2069 let mut node = Node::new(Role::Unknown);
2070 let value = TextSelection {
2071 anchor: TextPosition {
2072 node: NodeId(0),
2073 character_index: 0,
2074 },
2075 focus: TextPosition {
2076 node: NodeId(0),
2077 character_index: 2,
2078 },
2079 };
2080 node.set_text_selection(value);
2081 assert_eq!(node.text_selection(), Some(&value));
2082 }
2083 #[test]
2084 fn clearer_should_reset_the_property() {
2085 let mut node = Node::new(Role::Unknown);
2086 node.set_text_selection(TextSelection {
2087 anchor: TextPosition {
2088 node: NodeId(0),
2089 character_index: 0,
2090 },
2091 focus: TextPosition {
2092 node: NodeId(0),
2093 character_index: 2,
2094 },
2095 });
2096 node.clear_text_selection();
2097 assert!(node.text_selection().is_none());
2098 }
2099}
2100
2101vec_property_methods! {
2102 (CustomActions, CustomAction, custom_actions, get_custom_action_vec, set_custom_actions, set_custom_action_vec, push_custom_action, push_to_custom_action_vec, clear_custom_actions)
2103}
2104
2105#[cfg(test)]
2106mod custom_actions {
2107 use super::{CustomAction, Node, Role};
2108 use core::slice;
2109
2110 #[test]
2111 fn getter_should_return_default_value() {
2112 let node = Node::new(Role::Unknown);
2113 assert!(node.custom_actions().is_empty());
2114 }
2115 #[test]
2116 fn setter_should_update_the_property() {
2117 let mut node = Node::new(Role::Unknown);
2118 let value = alloc::vec![
2119 CustomAction {
2120 id: 0,
2121 description: "first test action".into(),
2122 },
2123 CustomAction {
2124 id: 1,
2125 description: "second test action".into(),
2126 },
2127 ];
2128 node.set_custom_actions(value.clone());
2129 assert_eq!(node.custom_actions(), value);
2130 }
2131 #[test]
2132 fn pusher_should_update_the_property() {
2133 let mut node = Node::new(Role::Unknown);
2134 let first_action = CustomAction {
2135 id: 0,
2136 description: "first test action".into(),
2137 };
2138 let second_action = CustomAction {
2139 id: 1,
2140 description: "second test action".into(),
2141 };
2142 node.push_custom_action(first_action.clone());
2143 assert_eq!(node.custom_actions(), slice::from_ref(&first_action));
2144 node.push_custom_action(second_action.clone());
2145 assert_eq!(node.custom_actions(), &[first_action, second_action]);
2146 }
2147 #[test]
2148 fn clearer_should_reset_the_property() {
2149 let mut node = Node::new(Role::Unknown);
2150 node.set_custom_actions([CustomAction {
2151 id: 0,
2152 description: "test action".into(),
2153 }]);
2154 node.clear_custom_actions();
2155 assert!(node.custom_actions().is_empty());
2156 }
2157}
2158
2159impl fmt::Debug for Node {
2160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2161 let mut fmt = f.debug_struct("Node");
2162
2163 fmt.field("role", &self.role());
2164
2165 let supported_actions = action_mask_to_action_vec(self.actions);
2166 if !supported_actions.is_empty() {
2167 fmt.field("actions", &supported_actions);
2168 }
2169
2170 let child_supported_actions = action_mask_to_action_vec(self.child_actions);
2171 if !child_supported_actions.is_empty() {
2172 fmt.field("child_actions", &child_supported_actions);
2173 }
2174
2175 self.debug_flag_properties(&mut fmt);
2176 self.debug_node_id_vec_properties(&mut fmt);
2177 self.debug_node_id_properties(&mut fmt);
2178 self.debug_string_properties(&mut fmt);
2179 self.debug_f64_properties(&mut fmt);
2180 self.debug_usize_properties(&mut fmt);
2181 self.debug_color_properties(&mut fmt);
2182 self.debug_text_decoration_properties(&mut fmt);
2183 self.debug_length_slice_properties(&mut fmt);
2184 self.debug_coord_slice_properties(&mut fmt);
2185 self.debug_bool_properties(&mut fmt);
2186 self.debug_unique_enum_properties(&mut fmt);
2187 self.debug_option_properties(&mut fmt);
2188
2189 let custom_actions = self.custom_actions();
2190 if !custom_actions.is_empty() {
2191 fmt.field("custom_actions", &custom_actions);
2192 }
2193
2194 fmt.finish()
2195 }
2196}
2197
2198#[cfg(feature = "serde")]
2199macro_rules! serialize_property {
2200 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
2201 match &$self.values[$index as usize] {
2202 PropertyValue::None => (),
2203 $(PropertyValue::$variant(value) => {
2204 $map.serialize_entry(&$id, &value)?;
2205 })*
2206 }
2207 }
2208}
2209
2210#[cfg(feature = "serde")]
2211macro_rules! deserialize_property {
2212 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
2213 match $key {
2214 $($(PropertyId::$id => {
2215 let value = $map.next_value()?;
2216 $props.set(PropertyId::$id, PropertyValue::$type(value));
2217 })*)*
2218 PropertyId::Unset => {
2219 let _ = $map.next_value::<IgnoredAny>()?;
2220 }
2221 }
2222 }
2223}
2224
2225#[cfg(feature = "serde")]
2226impl Serialize for Properties {
2227 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2228 where
2229 S: Serializer,
2230 {
2231 let mut len = 0;
2232 for value in &*self.values {
2233 if !matches!(*value, PropertyValue::None) {
2234 len += 1;
2235 }
2236 }
2237 let mut map = serializer.serialize_map(Some(len))?;
2238 for (id, index) in self.indices.0.iter().copied().enumerate() {
2239 if index == PropertyId::Unset as u8 {
2240 continue;
2241 }
2242 let id = PropertyId::n(id as _).unwrap();
2243 serialize_property!(self, map, index, id, {
2244 NodeIdVec,
2245 NodeId,
2246 String,
2247 F64,
2248 Usize,
2249 Color,
2250 TextDecoration,
2251 LengthSlice,
2252 CoordSlice,
2253 Bool,
2254 Invalid,
2255 Toggled,
2256 Live,
2257 TextDirection,
2258 Orientation,
2259 SortDirection,
2260 AriaCurrent,
2261 AutoComplete,
2262 HasPopup,
2263 ListStyle,
2264 TextAlign,
2265 VerticalOffset,
2266 Affine,
2267 Rect,
2268 TextSelection,
2269 CustomActionVec
2270 });
2271 }
2272 map.end()
2273 }
2274}
2275
2276#[cfg(feature = "serde")]
2277struct PropertiesVisitor;
2278
2279#[cfg(feature = "serde")]
2280impl<'de> Visitor<'de> for PropertiesVisitor {
2281 type Value = Properties;
2282
2283 #[inline]
2284 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2285 formatter.write_str("property map")
2286 }
2287
2288 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
2289 where
2290 V: MapAccess<'de>,
2291 {
2292 let mut props = Properties::default();
2293 while let Some(id) = map.next_key()? {
2294 deserialize_property!(props, map, id, {
2295 NodeIdVec {
2296 Children,
2297 Controls,
2298 Details,
2299 DescribedBy,
2300 FlowTo,
2301 LabelledBy,
2302 Owns,
2303 RadioGroup
2304 },
2305 NodeId {
2306 ActiveDescendant,
2307 ErrorMessage,
2308 InPageLinkTarget,
2309 MemberOf,
2310 NextOnLine,
2311 PreviousOnLine,
2312 PopupFor
2313 },
2314 String {
2315 Label,
2316 Description,
2317 Value,
2318 AccessKey,
2319 AuthorId,
2320 ClassName,
2321 FontFamily,
2322 HtmlTag,
2323 InnerHtml,
2324 KeyboardShortcut,
2325 Language,
2326 Placeholder,
2327 RoleDescription,
2328 StateDescription,
2329 Tooltip,
2330 Url,
2331 RowIndexText,
2332 ColumnIndexText
2333 },
2334 F64 {
2335 ScrollX,
2336 ScrollXMin,
2337 ScrollXMax,
2338 ScrollY,
2339 ScrollYMin,
2340 ScrollYMax,
2341 NumericValue,
2342 MinNumericValue,
2343 MaxNumericValue,
2344 NumericValueStep,
2345 NumericValueJump,
2346 FontSize,
2347 FontWeight
2348 },
2349 Usize {
2350 RowCount,
2351 ColumnCount,
2352 RowIndex,
2353 ColumnIndex,
2354 RowSpan,
2355 ColumnSpan,
2356 Level,
2357 SizeOfSet,
2358 PositionInSet
2359 },
2360 Color {
2361 ColorValue,
2362 BackgroundColor,
2363 ForegroundColor
2364 },
2365 TextDecoration {
2366 Overline,
2367 Strikethrough,
2368 Underline
2369 },
2370 LengthSlice {
2371 CharacterLengths,
2372 WordLengths
2373 },
2374 CoordSlice {
2375 CharacterPositions,
2376 CharacterWidths
2377 },
2378 Bool {
2379 Expanded,
2380 Selected
2381 },
2382 Invalid { Invalid },
2383 Toggled { Toggled },
2384 Live { Live },
2385 TextDirection { TextDirection },
2386 Orientation { Orientation },
2387 SortDirection { SortDirection },
2388 AriaCurrent { AriaCurrent },
2389 AutoComplete { AutoComplete },
2390 HasPopup { HasPopup },
2391 ListStyle { ListStyle },
2392 TextAlign { TextAlign },
2393 VerticalOffset { VerticalOffset },
2394 Affine { Transform },
2395 Rect { Bounds },
2396 TextSelection { TextSelection },
2397 CustomActionVec { CustomActions }
2398 });
2399 }
2400
2401 Ok(props)
2402 }
2403}
2404
2405#[cfg(feature = "serde")]
2406impl<'de> Deserialize<'de> for Properties {
2407 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2408 where
2409 D: Deserializer<'de>,
2410 {
2411 deserializer.deserialize_map(PropertiesVisitor)
2412 }
2413}
2414
2415#[cfg(feature = "schemars")]
2416macro_rules! add_schema_property {
2417 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
2418 let name = format!("{:?}", $enum_value);
2419 let name = name[..1].to_ascii_lowercase() + &name[1..];
2420 let subschema = $gen.subschema_for::<$type>();
2421 $properties.insert(name, subschema);
2422 }};
2423}
2424
2425#[cfg(feature = "schemars")]
2426macro_rules! add_properties_to_schema {
2427 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
2428 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
2429 }
2430}
2431
2432#[cfg(feature = "schemars")]
2433impl JsonSchema for Properties {
2434 #[inline]
2435 fn schema_name() -> String {
2436 "Properties".into()
2437 }
2438
2439 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
2440 let mut properties = SchemaMap::<String, Schema>::new();
2441 add_properties_to_schema!(gen, properties, {
2442 Vec<NodeId> {
2443 Children,
2444 Controls,
2445 Details,
2446 DescribedBy,
2447 FlowTo,
2448 LabelledBy,
2449 Owns,
2450 RadioGroup
2451 },
2452 NodeId {
2453 ActiveDescendant,
2454 ErrorMessage,
2455 InPageLinkTarget,
2456 MemberOf,
2457 NextOnLine,
2458 PreviousOnLine,
2459 PopupFor
2460 },
2461 Box<str> {
2462 Label,
2463 Description,
2464 Value,
2465 AccessKey,
2466 AuthorId,
2467 ClassName,
2468 FontFamily,
2469 HtmlTag,
2470 InnerHtml,
2471 KeyboardShortcut,
2472 Language,
2473 Placeholder,
2474 RoleDescription,
2475 StateDescription,
2476 Tooltip,
2477 Url,
2478 RowIndexText,
2479 ColumnIndexText
2480 },
2481 f64 {
2482 ScrollX,
2483 ScrollXMin,
2484 ScrollXMax,
2485 ScrollY,
2486 ScrollYMin,
2487 ScrollYMax,
2488 NumericValue,
2489 MinNumericValue,
2490 MaxNumericValue,
2491 NumericValueStep,
2492 NumericValueJump,
2493 FontSize,
2494 FontWeight
2495 },
2496 usize {
2497 RowCount,
2498 ColumnCount,
2499 RowIndex,
2500 ColumnIndex,
2501 RowSpan,
2502 ColumnSpan,
2503 Level,
2504 SizeOfSet,
2505 PositionInSet
2506 },
2507 u32 {
2508 ColorValue,
2509 BackgroundColor,
2510 ForegroundColor
2511 },
2512 TextDecoration {
2513 Overline,
2514 Strikethrough,
2515 Underline
2516 },
2517 Box<[u8]> {
2518 CharacterLengths,
2519 WordLengths
2520 },
2521 Box<[f32]> {
2522 CharacterPositions,
2523 CharacterWidths
2524 },
2525 bool {
2526 Expanded,
2527 Selected
2528 },
2529 Invalid { Invalid },
2530 Toggled { Toggled },
2531 Live { Live },
2532 TextDirection { TextDirection },
2533 Orientation { Orientation },
2534 SortDirection { SortDirection },
2535 AriaCurrent { AriaCurrent },
2536 AutoComplete { AutoComplete },
2537 HasPopup { HasPopup },
2538 ListStyle { ListStyle },
2539 TextAlign { TextAlign },
2540 VerticalOffset { VerticalOffset },
2541 Affine { Transform },
2542 Rect { Bounds },
2543 TextSelection { TextSelection },
2544 Vec<CustomAction> { CustomActions }
2545 });
2546 SchemaObject {
2547 instance_type: Some(InstanceType::Object.into()),
2548 object: Some(
2549 ObjectValidation {
2550 properties,
2551 ..Default::default()
2552 }
2553 .into(),
2554 ),
2555 ..Default::default()
2556 }
2557 .into()
2558 }
2559}
2560
2561#[derive(Clone, Debug, PartialEq, Eq)]
2564#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2565#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2566#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2567#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2568pub struct Tree {
2569 pub root: NodeId,
2571 pub toolkit_name: Option<String>,
2573 pub toolkit_version: Option<String>,
2575}
2576
2577impl Tree {
2578 #[inline]
2579 pub fn new(root: NodeId) -> Tree {
2580 Tree {
2581 root,
2582 toolkit_name: None,
2583 toolkit_version: None,
2584 }
2585 }
2586}
2587
2588#[derive(Clone, Debug, PartialEq)]
2600#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2601#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2602#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2603#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2604pub struct TreeUpdate {
2605 pub nodes: Vec<(NodeId, Node)>,
2626
2627 pub tree: Option<Tree>,
2632
2633 pub focus: NodeId,
2639}
2640
2641#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2644#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2645#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2646#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2647#[cfg_attr(
2648 feature = "pyo3",
2649 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
2650)]
2651#[repr(u8)]
2652pub enum ScrollUnit {
2653 Item,
2657 Page,
2659}
2660
2661#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2665#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2666#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2667#[cfg_attr(
2668 feature = "pyo3",
2669 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
2670)]
2671#[repr(u8)]
2672pub enum ScrollHint {
2673 TopLeft,
2674 BottomRight,
2675 TopEdge,
2676 BottomEdge,
2677 LeftEdge,
2678 RightEdge,
2679}
2680
2681#[derive(Clone, Debug, PartialEq)]
2682#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2683#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2684#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2685#[repr(C)]
2686pub enum ActionData {
2687 CustomAction(i32),
2688 Value(Box<str>),
2689 NumericValue(f64),
2690 ScrollUnit(ScrollUnit),
2691 ScrollHint(ScrollHint),
2695 ScrollToPoint(Point),
2698 SetScrollOffset(Point),
2701 SetTextSelection(TextSelection),
2702}
2703
2704#[derive(Clone, Debug, PartialEq)]
2705#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2706#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2707#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2708#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2709pub struct ActionRequest {
2710 pub action: Action,
2711 pub target: NodeId,
2712 pub data: Option<ActionData>,
2713}
2714
2715pub trait ActivationHandler {
2717 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
2739}
2740
2741pub trait ActionHandler {
2743 fn do_action(&mut self, request: ActionRequest);
2753}
2754
2755pub trait DeactivationHandler {
2757 fn deactivate_accessibility(&mut self);
2765}
2766
2767#[cfg(test)]
2768mod tests {
2769 use super::*;
2770 use alloc::format;
2771
2772 #[test]
2773 fn u64_should_be_convertible_to_node_id() {
2774 assert_eq!(NodeId::from(0u64), NodeId(0));
2775 assert_eq!(NodeId::from(1u64), NodeId(1));
2776 }
2777
2778 #[test]
2779 fn node_id_should_be_convertible_to_u64() {
2780 assert_eq!(u64::from(NodeId(0)), 0u64);
2781 assert_eq!(u64::from(NodeId(1)), 1u64);
2782 }
2783
2784 #[test]
2785 fn node_id_should_have_debug_repr() {
2786 assert_eq!(&format!("{:?}", NodeId(0)), "#0");
2787 assert_eq!(&format!("{:?}", NodeId(1)), "#1");
2788 }
2789
2790 #[test]
2791 fn action_n_should_return_the_corresponding_variant() {
2792 assert_eq!(Action::n(0), Some(Action::Click));
2793 assert_eq!(Action::n(1), Some(Action::Focus));
2794 assert_eq!(Action::n(2), Some(Action::Blur));
2795 assert_eq!(Action::n(3), Some(Action::Collapse));
2796 assert_eq!(Action::n(4), Some(Action::Expand));
2797 assert_eq!(Action::n(5), Some(Action::CustomAction));
2798 assert_eq!(Action::n(6), Some(Action::Decrement));
2799 assert_eq!(Action::n(7), Some(Action::Increment));
2800 assert_eq!(Action::n(8), Some(Action::HideTooltip));
2801 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
2802 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
2803 assert_eq!(Action::n(11), Some(Action::ScrollDown));
2804 assert_eq!(Action::n(12), Some(Action::ScrollLeft));
2805 assert_eq!(Action::n(13), Some(Action::ScrollRight));
2806 assert_eq!(Action::n(14), Some(Action::ScrollUp));
2807 assert_eq!(Action::n(15), Some(Action::ScrollIntoView));
2808 assert_eq!(Action::n(16), Some(Action::ScrollToPoint));
2809 assert_eq!(Action::n(17), Some(Action::SetScrollOffset));
2810 assert_eq!(Action::n(18), Some(Action::SetTextSelection));
2811 assert_eq!(
2812 Action::n(19),
2813 Some(Action::SetSequentialFocusNavigationStartingPoint)
2814 );
2815 assert_eq!(Action::n(20), Some(Action::SetValue));
2816 assert_eq!(Action::n(21), Some(Action::ShowContextMenu));
2817 assert_eq!(Action::n(22), None);
2818 }
2819
2820 #[test]
2821 fn empty_action_mask_should_be_converted_to_empty_vec() {
2822 assert_eq!(
2823 Vec::<Action>::new(),
2824 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
2825 );
2826 }
2827
2828 #[test]
2829 fn action_mask_should_be_convertible_to_vec() {
2830 let mut node = Node::new(Role::Unknown);
2831 node.add_action(Action::Click);
2832 assert_eq!(
2833 &[Action::Click],
2834 action_mask_to_action_vec(node.actions).as_slice()
2835 );
2836
2837 let mut node = Node::new(Role::Unknown);
2838 node.add_action(Action::ShowContextMenu);
2839 assert_eq!(
2840 &[Action::ShowContextMenu],
2841 action_mask_to_action_vec(node.actions).as_slice()
2842 );
2843
2844 let mut node = Node::new(Role::Unknown);
2845 node.add_action(Action::Click);
2846 node.add_action(Action::ShowContextMenu);
2847 assert_eq!(
2848 &[Action::Click, Action::ShowContextMenu],
2849 action_mask_to_action_vec(node.actions).as_slice()
2850 );
2851
2852 let mut node = Node::new(Role::Unknown);
2853 node.add_action(Action::Focus);
2854 node.add_action(Action::Blur);
2855 node.add_action(Action::Collapse);
2856 assert_eq!(
2857 &[Action::Focus, Action::Blur, Action::Collapse],
2858 action_mask_to_action_vec(node.actions).as_slice()
2859 );
2860 }
2861
2862 #[test]
2863 fn new_node_should_have_user_provided_role() {
2864 let node = Node::new(Role::Button);
2865 assert_eq!(node.role(), Role::Button);
2866 }
2867
2868 #[test]
2869 fn node_role_setter_should_update_the_role() {
2870 let mut node = Node::new(Role::Button);
2871 node.set_role(Role::CheckBox);
2872 assert_eq!(node.role(), Role::CheckBox);
2873 }
2874
2875 macro_rules! assert_absent_action {
2876 ($node:ident, $action:ident) => {
2877 assert!(!$node.supports_action(Action::$action));
2878 assert!(!$node.child_supports_action(Action::$action));
2879 };
2880 }
2881
2882 #[test]
2883 fn new_node_should_not_support_anyaction() {
2884 let node = Node::new(Role::Unknown);
2885 assert_absent_action!(node, Click);
2886 assert_absent_action!(node, Focus);
2887 assert_absent_action!(node, Blur);
2888 assert_absent_action!(node, Collapse);
2889 assert_absent_action!(node, Expand);
2890 assert_absent_action!(node, CustomAction);
2891 assert_absent_action!(node, Decrement);
2892 assert_absent_action!(node, Increment);
2893 assert_absent_action!(node, HideTooltip);
2894 assert_absent_action!(node, ShowTooltip);
2895 assert_absent_action!(node, ReplaceSelectedText);
2896 assert_absent_action!(node, ScrollDown);
2897 assert_absent_action!(node, ScrollLeft);
2898 assert_absent_action!(node, ScrollRight);
2899 assert_absent_action!(node, ScrollUp);
2900 assert_absent_action!(node, ScrollIntoView);
2901 assert_absent_action!(node, ScrollToPoint);
2902 assert_absent_action!(node, SetScrollOffset);
2903 assert_absent_action!(node, SetTextSelection);
2904 assert_absent_action!(node, SetSequentialFocusNavigationStartingPoint);
2905 assert_absent_action!(node, SetValue);
2906 assert_absent_action!(node, ShowContextMenu);
2907 }
2908
2909 #[test]
2910 fn node_add_action_should_add_the_action() {
2911 let mut node = Node::new(Role::Unknown);
2912 node.add_action(Action::Focus);
2913 assert!(node.supports_action(Action::Focus));
2914 node.add_action(Action::Blur);
2915 assert!(node.supports_action(Action::Blur));
2916 }
2917
2918 #[test]
2919 fn node_add_child_action_should_add_the_action() {
2920 let mut node = Node::new(Role::Unknown);
2921 node.add_child_action(Action::Focus);
2922 assert!(node.child_supports_action(Action::Focus));
2923 node.add_child_action(Action::Blur);
2924 assert!(node.child_supports_action(Action::Blur));
2925 }
2926
2927 #[test]
2928 fn node_add_action_should_do_nothing_if_the_action_is_already_supported() {
2929 let mut node = Node::new(Role::Unknown);
2930 node.add_action(Action::Focus);
2931 node.add_action(Action::Focus);
2932 assert!(node.supports_action(Action::Focus));
2933 }
2934
2935 #[test]
2936 fn node_add_child_action_should_do_nothing_if_the_action_is_already_supported() {
2937 let mut node = Node::new(Role::Unknown);
2938 node.add_child_action(Action::Focus);
2939 node.add_child_action(Action::Focus);
2940 assert!(node.child_supports_action(Action::Focus));
2941 }
2942
2943 #[test]
2944 fn node_remove_action_should_remove_the_action() {
2945 let mut node = Node::new(Role::Unknown);
2946 node.add_action(Action::Blur);
2947 node.remove_action(Action::Blur);
2948 assert!(!node.supports_action(Action::Blur));
2949 }
2950
2951 #[test]
2952 fn node_remove_child_action_should_remove_the_action() {
2953 let mut node = Node::new(Role::Unknown);
2954 node.add_child_action(Action::Blur);
2955 node.remove_child_action(Action::Blur);
2956 assert!(!node.child_supports_action(Action::Blur));
2957 }
2958
2959 #[test]
2960 fn node_clear_actions_should_remove_all_actions() {
2961 let mut node = Node::new(Role::Unknown);
2962 node.add_action(Action::Focus);
2963 node.add_action(Action::Blur);
2964 node.clear_actions();
2965 assert!(!node.supports_action(Action::Focus));
2966 assert!(!node.supports_action(Action::Blur));
2967 }
2968
2969 #[test]
2970 fn node_clear_child_actions_should_remove_all_actions() {
2971 let mut node = Node::new(Role::Unknown);
2972 node.add_child_action(Action::Focus);
2973 node.add_child_action(Action::Blur);
2974 node.clear_child_actions();
2975 assert!(!node.child_supports_action(Action::Focus));
2976 assert!(!node.child_supports_action(Action::Blur));
2977 }
2978
2979 #[test]
2980 fn node_should_have_debug_repr() {
2981 let mut node = Node::new(Role::Unknown);
2982 node.add_action(Action::Click);
2983 node.add_action(Action::Focus);
2984 node.add_child_action(Action::ScrollIntoView);
2985 node.set_hidden();
2986 node.set_multiselectable();
2987 node.set_children([NodeId(0), NodeId(1)]);
2988 node.set_active_descendant(NodeId(2));
2989 node.push_custom_action(CustomAction {
2990 id: 0,
2991 description: "test action".into(),
2992 });
2993
2994 assert_eq!(
2995 &format!("{node:?}"),
2996 r#"Node { role: Unknown, actions: [Click, Focus], child_actions: [ScrollIntoView], is_hidden: true, is_multiselectable: true, children: [#0, #1], active_descendant: #2, custom_actions: [CustomAction { id: 0, description: "test action" }] }"#
2997 );
2998 }
2999
3000 #[test]
3001 fn new_tree_should_have_root_id() {
3002 let tree = Tree::new(NodeId(1));
3003 assert_eq!(tree.root, NodeId(1));
3004 assert_eq!(tree.toolkit_name, None);
3005 assert_eq!(tree.toolkit_version, None);
3006 }
3007}