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 ScrollBackward,
311 ScrollDown,
312 ScrollForward,
313 ScrollLeft,
314 ScrollRight,
315 ScrollUp,
316
317 ScrollIntoView,
321
322 ScrollToPoint,
326
327 SetScrollOffset,
329
330 SetTextSelection,
332
333 SetSequentialFocusNavigationStartingPoint,
337
338 SetValue,
342
343 ShowContextMenu,
344}
345
346impl Action {
347 fn mask(self) -> u32 {
348 1 << (self as u8)
349 }
350
351 #[cfg(not(feature = "enumn"))]
352 fn n(value: u8) -> Option<Self> {
353 match value {
357 0 => Some(Action::Click),
358 1 => Some(Action::Focus),
359 2 => Some(Action::Blur),
360 3 => Some(Action::Collapse),
361 4 => Some(Action::Expand),
362 5 => Some(Action::CustomAction),
363 6 => Some(Action::Decrement),
364 7 => Some(Action::Increment),
365 8 => Some(Action::HideTooltip),
366 9 => Some(Action::ShowTooltip),
367 10 => Some(Action::ReplaceSelectedText),
368 11 => Some(Action::ScrollBackward),
369 12 => Some(Action::ScrollDown),
370 13 => Some(Action::ScrollForward),
371 14 => Some(Action::ScrollLeft),
372 15 => Some(Action::ScrollRight),
373 16 => Some(Action::ScrollUp),
374 17 => Some(Action::ScrollIntoView),
375 18 => Some(Action::ScrollToPoint),
376 19 => Some(Action::SetScrollOffset),
377 20 => Some(Action::SetTextSelection),
378 21 => Some(Action::SetSequentialFocusNavigationStartingPoint),
379 22 => Some(Action::SetValue),
380 23 => Some(Action::ShowContextMenu),
381 _ => None,
382 }
383 }
384}
385
386fn action_mask_to_action_vec(mask: u32) -> Vec<Action> {
387 let mut actions = Vec::new();
388 let mut i = 0;
389 while let Some(variant) = Action::n(i) {
390 if mask & variant.mask() != 0 {
391 actions.push(variant);
392 }
393 i += 1;
394 }
395 actions
396}
397
398#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "enumn", derive(enumn::N))]
400#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
401#[cfg_attr(feature = "schemars", derive(JsonSchema))]
402#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
403#[cfg_attr(
404 feature = "pyo3",
405 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
406)]
407#[repr(u8)]
408pub enum Orientation {
409 Horizontal,
411 Vertical,
413}
414
415#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
416#[cfg_attr(feature = "enumn", derive(enumn::N))]
417#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
418#[cfg_attr(feature = "schemars", derive(JsonSchema))]
419#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
420#[cfg_attr(
421 feature = "pyo3",
422 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
423)]
424#[repr(u8)]
425pub enum TextDirection {
426 LeftToRight,
427 RightToLeft,
428 TopToBottom,
429 BottomToTop,
430}
431
432#[derive(Clone, Copy, Debug, PartialEq, Eq)]
437#[cfg_attr(feature = "enumn", derive(enumn::N))]
438#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
439#[cfg_attr(feature = "schemars", derive(JsonSchema))]
440#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
441#[cfg_attr(
442 feature = "pyo3",
443 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
444)]
445#[repr(u8)]
446pub enum Invalid {
447 True,
448 Grammar,
449 Spelling,
450}
451
452#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
453#[cfg_attr(feature = "enumn", derive(enumn::N))]
454#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
455#[cfg_attr(feature = "schemars", derive(JsonSchema))]
456#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
457#[cfg_attr(
458 feature = "pyo3",
459 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
460)]
461#[repr(u8)]
462pub enum Toggled {
463 False,
464 True,
465 Mixed,
466}
467
468#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
469#[cfg_attr(feature = "enumn", derive(enumn::N))]
470#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
471#[cfg_attr(feature = "schemars", derive(JsonSchema))]
472#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
473#[cfg_attr(
474 feature = "pyo3",
475 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
476)]
477#[repr(u8)]
478pub enum SortDirection {
479 Ascending,
480 Descending,
481 Other,
482}
483
484#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
485#[cfg_attr(feature = "enumn", derive(enumn::N))]
486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
487#[cfg_attr(feature = "schemars", derive(JsonSchema))]
488#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
489#[cfg_attr(
490 feature = "pyo3",
491 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
492)]
493#[repr(u8)]
494pub enum AriaCurrent {
495 False,
496 True,
497 Page,
498 Step,
499 Location,
500 Date,
501 Time,
502}
503
504#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
505#[cfg_attr(feature = "enumn", derive(enumn::N))]
506#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
507#[cfg_attr(feature = "schemars", derive(JsonSchema))]
508#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
509#[cfg_attr(
510 feature = "pyo3",
511 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
512)]
513#[repr(u8)]
514pub enum AutoComplete {
515 Inline,
516 List,
517 Both,
518}
519
520#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
521#[cfg_attr(feature = "enumn", derive(enumn::N))]
522#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
523#[cfg_attr(feature = "schemars", derive(JsonSchema))]
524#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
525#[cfg_attr(
526 feature = "pyo3",
527 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
528)]
529#[repr(u8)]
530pub enum Live {
531 Off,
532 Polite,
533 Assertive,
534}
535
536#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
537#[cfg_attr(feature = "enumn", derive(enumn::N))]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539#[cfg_attr(feature = "schemars", derive(JsonSchema))]
540#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
541#[cfg_attr(
542 feature = "pyo3",
543 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
544)]
545#[repr(u8)]
546pub enum HasPopup {
547 Menu,
548 Listbox,
549 Tree,
550 Grid,
551 Dialog,
552}
553
554#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
555#[cfg_attr(feature = "enumn", derive(enumn::N))]
556#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
557#[cfg_attr(feature = "schemars", derive(JsonSchema))]
558#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
559#[cfg_attr(
560 feature = "pyo3",
561 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
562)]
563#[repr(u8)]
564pub enum ListStyle {
565 Circle,
566 Disc,
567 Image,
568 Numeric,
569 Square,
570 Other,
572}
573
574#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
575#[cfg_attr(feature = "enumn", derive(enumn::N))]
576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
577#[cfg_attr(feature = "schemars", derive(JsonSchema))]
578#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
579#[cfg_attr(
580 feature = "pyo3",
581 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
582)]
583#[repr(u8)]
584pub enum TextAlign {
585 Left,
586 Right,
587 Center,
588 Justify,
589}
590
591#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
592#[cfg_attr(feature = "enumn", derive(enumn::N))]
593#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
594#[cfg_attr(feature = "schemars", derive(JsonSchema))]
595#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
596#[cfg_attr(
597 feature = "pyo3",
598 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
599)]
600#[repr(u8)]
601pub enum VerticalOffset {
602 Subscript,
603 Superscript,
604}
605
606#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
607#[cfg_attr(feature = "enumn", derive(enumn::N))]
608#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
609#[cfg_attr(feature = "schemars", derive(JsonSchema))]
610#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
611#[cfg_attr(
612 feature = "pyo3",
613 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
614)]
615#[repr(u8)]
616pub enum TextDecoration {
617 Solid,
618 Dotted,
619 Dashed,
620 Double,
621 Wavy,
622}
623
624pub type NodeIdContent = u64;
625
626#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
628#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
629#[cfg_attr(feature = "schemars", derive(JsonSchema))]
630#[repr(transparent)]
631pub struct NodeId(pub NodeIdContent);
632
633impl From<NodeIdContent> for NodeId {
634 #[inline]
635 fn from(inner: NodeIdContent) -> Self {
636 Self(inner)
637 }
638}
639
640impl From<NodeId> for NodeIdContent {
641 #[inline]
642 fn from(outer: NodeId) -> Self {
643 outer.0
644 }
645}
646
647impl fmt::Debug for NodeId {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 write!(f, "#{}", self.0)
650 }
651}
652
653#[derive(Clone, Debug, PartialEq, Eq)]
658#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
659#[cfg_attr(feature = "schemars", derive(JsonSchema))]
660#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
661#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
662pub struct CustomAction {
663 pub id: i32,
664 pub description: Box<str>,
665}
666
667#[derive(Clone, Copy, Debug, PartialEq, Eq)]
668#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
669#[cfg_attr(feature = "schemars", derive(JsonSchema))]
670#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
671#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
672pub struct TextPosition {
673 pub node: NodeId,
675 pub character_index: usize,
678}
679
680#[derive(Clone, Copy, Debug, PartialEq, Eq)]
681#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
682#[cfg_attr(feature = "schemars", derive(JsonSchema))]
683#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
684#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
685pub struct TextSelection {
686 pub anchor: TextPosition,
691 pub focus: TextPosition,
695}
696
697#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
698#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
699#[cfg_attr(feature = "schemars", derive(JsonSchema))]
700#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
701#[repr(u8)]
702enum Flag {
703 Hidden,
704 Multiselectable,
705 Required,
706 Visited,
707 Busy,
708 LiveAtomic,
709 Modal,
710 TouchTransparent,
711 ReadOnly,
712 Disabled,
713 Bold,
714 Italic,
715 ClipsChildren,
716 IsLineBreakingObject,
717 IsPageBreakingObject,
718 IsSpellingError,
719 IsGrammarError,
720 IsSearchMatch,
721 IsSuggestion,
722}
723
724impl Flag {
725 fn mask(self) -> u32 {
726 1 << (self as u8)
727 }
728}
729
730#[derive(Clone, Debug, PartialEq)]
734enum PropertyValue {
735 None,
736 NodeIdVec(Vec<NodeId>),
737 NodeId(NodeId),
738 String(Box<str>),
739 F64(f64),
740 Usize(usize),
741 Color(u32),
742 TextDecoration(TextDecoration),
743 LengthSlice(Box<[u8]>),
744 CoordSlice(Box<[f32]>),
745 Bool(bool),
746 Invalid(Invalid),
747 Toggled(Toggled),
748 Live(Live),
749 TextDirection(TextDirection),
750 Orientation(Orientation),
751 SortDirection(SortDirection),
752 AriaCurrent(AriaCurrent),
753 AutoComplete(AutoComplete),
754 HasPopup(HasPopup),
755 ListStyle(ListStyle),
756 TextAlign(TextAlign),
757 VerticalOffset(VerticalOffset),
758 Affine(Box<Affine>),
759 Rect(Rect),
760 TextSelection(Box<TextSelection>),
761 CustomActionVec(Vec<CustomAction>),
762}
763
764#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
765#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
766#[cfg_attr(feature = "schemars", derive(JsonSchema))]
767#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
768#[repr(u8)]
769enum PropertyId {
770 Children,
772 Controls,
773 Details,
774 DescribedBy,
775 FlowTo,
776 LabelledBy,
777 Owns,
778 RadioGroup,
779
780 ActiveDescendant,
782 ErrorMessage,
783 InPageLinkTarget,
784 MemberOf,
785 NextOnLine,
786 PreviousOnLine,
787 PopupFor,
788
789 Label,
791 Description,
792 Value,
793 AccessKey,
794 AuthorId,
795 ClassName,
796 FontFamily,
797 HtmlTag,
798 InnerHtml,
799 KeyboardShortcut,
800 Language,
801 Placeholder,
802 RoleDescription,
803 StateDescription,
804 Tooltip,
805 Url,
806 RowIndexText,
807 ColumnIndexText,
808
809 ScrollX,
811 ScrollXMin,
812 ScrollXMax,
813 ScrollY,
814 ScrollYMin,
815 ScrollYMax,
816 NumericValue,
817 MinNumericValue,
818 MaxNumericValue,
819 NumericValueStep,
820 NumericValueJump,
821 FontSize,
822 FontWeight,
823
824 RowCount,
826 ColumnCount,
827 RowIndex,
828 ColumnIndex,
829 RowSpan,
830 ColumnSpan,
831 Level,
832 SizeOfSet,
833 PositionInSet,
834
835 ColorValue,
837 BackgroundColor,
838 ForegroundColor,
839
840 Overline,
842 Strikethrough,
843 Underline,
844
845 CharacterLengths,
847 WordLengths,
848
849 CharacterPositions,
851 CharacterWidths,
852
853 Expanded,
855 Selected,
856
857 Invalid,
859 Toggled,
860 Live,
861 TextDirection,
862 Orientation,
863 SortDirection,
864 AriaCurrent,
865 AutoComplete,
866 HasPopup,
867 ListStyle,
868 TextAlign,
869 VerticalOffset,
870
871 Transform,
873 Bounds,
874 TextSelection,
875 CustomActions,
876
877 Unset,
879}
880
881#[derive(Clone, Copy, Debug, PartialEq, Eq)]
882#[repr(transparent)]
883struct PropertyIndices([u8; PropertyId::Unset as usize]);
884
885impl Default for PropertyIndices {
886 fn default() -> Self {
887 Self([PropertyId::Unset as u8; PropertyId::Unset as usize])
888 }
889}
890
891#[derive(Clone, Debug, Default, PartialEq)]
892struct Properties {
893 indices: PropertyIndices,
894 values: Vec<PropertyValue>,
895}
896
897#[derive(Clone, Default, PartialEq)]
904#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
905#[cfg_attr(feature = "schemars", derive(JsonSchema))]
906#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
907#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
908pub struct Node {
909 role: Role,
910 actions: u32,
911 flags: u32,
912 properties: Properties,
913}
914
915impl PropertyIndices {
916 fn get<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a PropertyValue {
917 let index = self.0[id as usize];
918 if index == PropertyId::Unset as u8 {
919 &PropertyValue::None
920 } else {
921 &values[index as usize]
922 }
923 }
924}
925
926impl Properties {
927 fn get_mut(&mut self, id: PropertyId, default: PropertyValue) -> &mut PropertyValue {
928 let index = self.indices.0[id as usize] as usize;
929 if index == PropertyId::Unset as usize {
930 self.values.push(default);
931 let index = self.values.len() - 1;
932 self.indices.0[id as usize] = index as u8;
933 &mut self.values[index]
934 } else {
935 &mut self.values[index]
936 }
937 }
938
939 fn set(&mut self, id: PropertyId, value: PropertyValue) {
940 let index = self.indices.0[id as usize];
941 if index == PropertyId::Unset as u8 {
942 self.values.push(value);
943 self.indices.0[id as usize] = (self.values.len() - 1) as u8;
944 } else {
945 self.values[index as usize] = value;
946 }
947 }
948
949 fn clear(&mut self, id: PropertyId) {
950 let index = self.indices.0[id as usize];
951 if index != PropertyId::Unset as u8 {
952 self.values[index as usize] = PropertyValue::None;
953 }
954 }
955}
956
957macro_rules! flag_methods {
958 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
959 impl Node {
960 $($(#[$doc])*
961 #[inline]
962 pub fn $getter(&self) -> bool {
963 (self.flags & (Flag::$id).mask()) != 0
964 }
965 #[inline]
966 pub fn $setter(&mut self) {
967 self.flags |= (Flag::$id).mask();
968 }
969 #[inline]
970 pub fn $clearer(&mut self) {
971 self.flags &= !((Flag::$id).mask());
972 })*
973 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
974 $(
975 if self.$getter() {
976 fmt.field(stringify!($getter), &true);
977 }
978 )*
979 }
980 }
981 $(#[cfg(test)]
982 mod $getter {
983 use super::{Node, Role};
984
985 #[test]
986 fn getter_should_return_default_value() {
987 let node = Node::new(Role::Unknown);
988 assert!(!node.$getter());
989 }
990
991 #[test]
992 fn setter_should_update_the_property() {
993 let mut node = Node::new(Role::Unknown);
994 node.$setter();
995 assert!(node.$getter());
996 }
997
998 #[test]
999 fn clearer_should_reset_the_property() {
1000 let mut node = Node::new(Role::Unknown);
1001 node.$setter();
1002 node.$clearer();
1003 assert!(!node.$getter());
1004 }
1005 })*
1006 }
1007}
1008
1009macro_rules! option_ref_type_getters {
1010 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1011 impl PropertyIndices {
1012 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> Option<&'a $type> {
1013 match self.get(values, id) {
1014 PropertyValue::$variant(value) => Some(value),
1015 _ => None,
1016 }
1017 })*
1018 }
1019 }
1020}
1021
1022macro_rules! slice_type_getters {
1023 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1024 impl PropertyIndices {
1025 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a [$type] {
1026 match self.get(values, id) {
1027 PropertyValue::$variant(value) => value,
1028 _ => &[],
1029 }
1030 })*
1031 }
1032 }
1033}
1034
1035macro_rules! copy_type_getters {
1036 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1037 impl PropertyIndices {
1038 $(fn $method(&self, values: &[PropertyValue], id: PropertyId) -> Option<$type> {
1039 match self.get(values, id) {
1040 PropertyValue::$variant(value) => Some(*value),
1041 _ => None,
1042 }
1043 })*
1044 }
1045 }
1046}
1047
1048macro_rules! box_type_setters {
1049 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1050 impl Node {
1051 $(fn $method(&mut self, id: PropertyId, value: impl Into<Box<$type>>) {
1052 self.properties.set(id, PropertyValue::$variant(value.into()));
1053 })*
1054 }
1055 }
1056}
1057
1058macro_rules! copy_type_setters {
1059 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1060 impl Node {
1061 $(fn $method(&mut self, id: PropertyId, value: $type) {
1062 self.properties.set(id, PropertyValue::$variant(value));
1063 })*
1064 }
1065 }
1066}
1067
1068macro_rules! vec_type_methods {
1069 ($(($type:ty, $variant:ident, $getter:ident, $setter:ident, $pusher:ident)),+) => {
1070 $(slice_type_getters! {
1071 ($getter, $type, $variant)
1072 })*
1073 impl Node {
1074 $(fn $setter(&mut self, id: PropertyId, value: impl Into<Vec<$type>>) {
1075 self.properties.set(id, PropertyValue::$variant(value.into()));
1076 }
1077 fn $pusher(&mut self, id: PropertyId, item: $type) {
1078 if let PropertyValue::$variant(v) = self.properties.get_mut(id, PropertyValue::$variant(Vec::new())) {
1079 v.push(item);
1080 }
1081 })*
1082 }
1083 }
1084}
1085
1086macro_rules! property_methods {
1087 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $type_getter:ident, $getter_result:ty, $setter:ident, $type_setter:ident, $setter_param:ty, $clearer:ident)),+) => {
1088 impl Node {
1089 $($(#[$doc])*
1090 #[inline]
1091 pub fn $getter(&self) -> $getter_result {
1092 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1093 }
1094 #[inline]
1095 pub fn $setter(&mut self, value: $setter_param) {
1096 self.$type_setter(PropertyId::$id, value);
1097 }
1098 #[inline]
1099 pub fn $clearer(&mut self) {
1100 self.properties.clear(PropertyId::$id);
1101 })*
1102 }
1103 }
1104}
1105
1106macro_rules! vec_property_methods {
1107 ($($(#[$doc:meta])* ($id:ident, $item_type:ty, $getter:ident, $type_getter:ident, $setter:ident, $type_setter:ident, $pusher:ident, $type_pusher:ident, $clearer:ident)),+) => {
1108 $(property_methods! {
1109 $(#[$doc])*
1110 ($id, $getter, $type_getter, &[$item_type], $setter, $type_setter, impl Into<Vec<$item_type>>, $clearer)
1111 }
1112 impl Node {
1113 #[inline]
1114 pub fn $pusher(&mut self, item: $item_type) {
1115 self.$type_pusher(PropertyId::$id, item);
1116 }
1117 })*
1118 }
1119}
1120
1121macro_rules! slice_properties_debug_method {
1122 ($name:ident, [$($getter:ident,)*]) => {
1123 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1124 $(
1125 let value = self.$getter();
1126 if !value.is_empty() {
1127 fmt.field(stringify!($getter), &value);
1128 }
1129 )*
1130 }
1131 }
1132}
1133
1134macro_rules! node_id_vec_property_methods {
1135 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $pusher:ident, $clearer:ident)),+) => {
1136 $(vec_property_methods! {
1137 $(#[$doc])*
1138 ($id, NodeId, $getter, get_node_id_vec, $setter, set_node_id_vec, $pusher, push_to_node_id_vec, $clearer)
1139 })*
1140 impl Node {
1141 slice_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1142 }
1143 $(#[cfg(test)]
1144 mod $getter {
1145 use super::{Node, NodeId, Role};
1146
1147 #[test]
1148 fn getter_should_return_default_value() {
1149 let node = Node::new(Role::Unknown);
1150 assert!(node.$getter().is_empty());
1151 }
1152 #[test]
1153 fn setter_should_update_the_property() {
1154 let mut node = Node::new(Role::Unknown);
1155 node.$setter([]);
1156 assert!(node.$getter().is_empty());
1157 node.$setter([NodeId(0), NodeId(1)]);
1158 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1159 }
1160 #[test]
1161 fn pusher_should_update_the_property() {
1162 let mut node = Node::new(Role::Unknown);
1163 node.$pusher(NodeId(0));
1164 assert_eq!(node.$getter(), &[NodeId(0)]);
1165 node.$pusher(NodeId(1));
1166 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1167 }
1168 #[test]
1169 fn clearer_should_reset_the_property() {
1170 let mut node = Node::new(Role::Unknown);
1171 node.$setter([NodeId(0)]);
1172 node.$clearer();
1173 assert!(node.$getter().is_empty());
1174 }
1175 })*
1176 }
1177}
1178
1179macro_rules! option_properties_debug_method {
1180 ($name:ident, [$($getter:ident,)*]) => {
1181 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1182 $(
1183 if let Some(value) = self.$getter() {
1184 fmt.field(stringify!($getter), &value);
1185 }
1186 )*
1187 }
1188 }
1189}
1190
1191macro_rules! node_id_property_methods {
1192 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1193 $(property_methods! {
1194 $(#[$doc])*
1195 ($id, $getter, get_node_id_property, Option<NodeId>, $setter, set_node_id_property, NodeId, $clearer)
1196 })*
1197 impl Node {
1198 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1199 }
1200 $(#[cfg(test)]
1201 mod $getter {
1202 use super::{Node, NodeId, Role};
1203
1204 #[test]
1205 fn getter_should_return_default_value() {
1206 let node = Node::new(Role::Unknown);
1207 assert!(node.$getter().is_none());
1208 }
1209 #[test]
1210 fn setter_should_update_the_property() {
1211 let mut node = Node::new(Role::Unknown);
1212 node.$setter(NodeId(1));
1213 assert_eq!(node.$getter(), Some(NodeId(1)));
1214 }
1215 #[test]
1216 fn clearer_should_reset_the_property() {
1217 let mut node = Node::new(Role::Unknown);
1218 node.$setter(NodeId(1));
1219 node.$clearer();
1220 assert!(node.$getter().is_none());
1221 }
1222 })*
1223 }
1224}
1225
1226macro_rules! string_property_methods {
1227 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1228 $(property_methods! {
1229 $(#[$doc])*
1230 ($id, $getter, get_string_property, Option<&str>, $setter, set_string_property, impl Into<Box<str>>, $clearer)
1231 })*
1232 impl Node {
1233 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1234 }
1235 $(#[cfg(test)]
1236 mod $getter {
1237 use super::{Node, Role};
1238
1239 #[test]
1240 fn getter_should_return_default_value() {
1241 let node = Node::new(Role::Unknown);
1242 assert!(node.$getter().is_none());
1243 }
1244 #[test]
1245 fn setter_should_update_the_property() {
1246 let mut node = Node::new(Role::Unknown);
1247 node.$setter("test");
1248 assert_eq!(node.$getter(), Some("test"));
1249 }
1250 #[test]
1251 fn clearer_should_reset_the_property() {
1252 let mut node = Node::new(Role::Unknown);
1253 node.$setter("test");
1254 node.$clearer();
1255 assert!(node.$getter().is_none());
1256 }
1257 })*
1258 }
1259}
1260
1261macro_rules! f64_property_methods {
1262 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1263 $(property_methods! {
1264 $(#[$doc])*
1265 ($id, $getter, get_f64_property, Option<f64>, $setter, set_f64_property, f64, $clearer)
1266 })*
1267 impl Node {
1268 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1269 }
1270 $(#[cfg(test)]
1271 mod $getter {
1272 use super::{Node, Role};
1273
1274 #[test]
1275 fn getter_should_return_default_value() {
1276 let node = Node::new(Role::Unknown);
1277 assert!(node.$getter().is_none());
1278 }
1279 #[test]
1280 fn setter_should_update_the_property() {
1281 let mut node = Node::new(Role::Unknown);
1282 node.$setter(1.0);
1283 assert_eq!(node.$getter(), Some(1.0));
1284 }
1285 #[test]
1286 fn clearer_should_reset_the_property() {
1287 let mut node = Node::new(Role::Unknown);
1288 node.$setter(1.0);
1289 node.$clearer();
1290 assert!(node.$getter().is_none());
1291 }
1292 })*
1293 }
1294}
1295
1296macro_rules! usize_property_methods {
1297 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1298 $(property_methods! {
1299 $(#[$doc])*
1300 ($id, $getter, get_usize_property, Option<usize>, $setter, set_usize_property, usize, $clearer)
1301 })*
1302 impl Node {
1303 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1304 }
1305 $(#[cfg(test)]
1306 mod $getter {
1307 use super::{Node, Role};
1308
1309 #[test]
1310 fn getter_should_return_default_value() {
1311 let node = Node::new(Role::Unknown);
1312 assert!(node.$getter().is_none());
1313 }
1314 #[test]
1315 fn setter_should_update_the_property() {
1316 let mut node = Node::new(Role::Unknown);
1317 node.$setter(1);
1318 assert_eq!(node.$getter(), Some(1));
1319 }
1320 #[test]
1321 fn clearer_should_reset_the_property() {
1322 let mut node = Node::new(Role::Unknown);
1323 node.$setter(1);
1324 node.$clearer();
1325 assert!(node.$getter().is_none());
1326 }
1327 })*
1328 }
1329}
1330
1331macro_rules! color_property_methods {
1332 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1333 $(property_methods! {
1334 $(#[$doc])*
1335 ($id, $getter, get_color_property, Option<u32>, $setter, set_color_property, u32, $clearer)
1336 })*
1337 impl Node {
1338 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1339 }
1340 $(#[cfg(test)]
1341 mod $getter {
1342 use super::{Node, Role};
1343
1344 #[test]
1345 fn getter_should_return_default_value() {
1346 let node = Node::new(Role::Unknown);
1347 assert!(node.$getter().is_none());
1348 }
1349 #[test]
1350 fn setter_should_update_the_property() {
1351 let mut node = Node::new(Role::Unknown);
1352 node.$setter(1);
1353 assert_eq!(node.$getter(), Some(1));
1354 }
1355 #[test]
1356 fn clearer_should_reset_the_property() {
1357 let mut node = Node::new(Role::Unknown);
1358 node.$setter(1);
1359 node.$clearer();
1360 assert!(node.$getter().is_none());
1361 }
1362 })*
1363 }
1364}
1365
1366macro_rules! text_decoration_property_methods {
1367 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1368 $(property_methods! {
1369 $(#[$doc])*
1370 ($id, $getter, get_text_decoration_property, Option<TextDecoration>, $setter, set_text_decoration_property, TextDecoration, $clearer)
1371 })*
1372 impl Node {
1373 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1374 }
1375 $(#[cfg(test)]
1376 mod $getter {
1377 use super::{Node, Role, TextDecoration};
1378
1379 #[test]
1380 fn getter_should_return_default_value() {
1381 let node = Node::new(Role::Unknown);
1382 assert!(node.$getter().is_none());
1383 }
1384 #[test]
1385 fn setter_should_update_the_property() {
1386 let mut node = Node::new(Role::Unknown);
1387 node.$setter(TextDecoration::Dotted);
1388 assert_eq!(node.$getter(), Some(TextDecoration::Dotted));
1389 }
1390 #[test]
1391 fn clearer_should_reset_the_property() {
1392 let mut node = Node::new(Role::Unknown);
1393 node.$setter(TextDecoration::Dotted);
1394 node.$clearer();
1395 assert!(node.$getter().is_none());
1396 }
1397 })*
1398 }
1399}
1400
1401macro_rules! length_slice_property_methods {
1402 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1403 $(property_methods! {
1404 $(#[$doc])*
1405 ($id, $getter, get_length_slice_property, &[u8], $setter, set_length_slice_property, impl Into<Box<[u8]>>, $clearer)
1406 })*
1407 impl Node {
1408 slice_properties_debug_method! { debug_length_slice_properties, [$($getter,)*] }
1409 }
1410 $(#[cfg(test)]
1411 mod $getter {
1412 use super::{Node, Role};
1413
1414 #[test]
1415 fn getter_should_return_default_value() {
1416 let node = Node::new(Role::Unknown);
1417 assert!(node.$getter().is_empty());
1418 }
1419 #[test]
1420 fn setter_should_update_the_property() {
1421 let mut node = Node::new(Role::Unknown);
1422 node.$setter([]);
1423 assert!(node.$getter().is_empty());
1424 node.$setter([1, 2]);
1425 assert_eq!(node.$getter(), &[1, 2]);
1426 }
1427 #[test]
1428 fn clearer_should_reset_the_property() {
1429 let mut node = Node::new(Role::Unknown);
1430 node.$setter([1, 2]);
1431 node.$clearer();
1432 assert!(node.$getter().is_empty());
1433 }
1434 })*
1435 }
1436}
1437
1438macro_rules! coord_slice_property_methods {
1439 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1440 $(property_methods! {
1441 $(#[$doc])*
1442 ($id, $getter, get_coord_slice_property, Option<&[f32]>, $setter, set_coord_slice_property, impl Into<Box<[f32]>>, $clearer)
1443 })*
1444 impl Node {
1445 option_properties_debug_method! { debug_coord_slice_properties, [$($getter,)*] }
1446 }
1447 $(#[cfg(test)]
1448 mod $getter {
1449 use super::{Node, Role};
1450
1451 #[test]
1452 fn getter_should_return_default_value() {
1453 let node = Node::new(Role::Unknown);
1454 assert!(node.$getter().is_none());
1455 }
1456 #[test]
1457 fn setter_should_update_the_property() {
1458 let mut node = Node::new(Role::Unknown);
1459 node.$setter([]);
1460 let expected: Option<&[f32]> = Some(&[]);
1461 assert_eq!(node.$getter(), expected);
1462 node.$setter([1.0, 2.0]);
1463 let expected: Option<&[f32]> = Some(&[1.0, 2.0]);
1464 assert_eq!(node.$getter(), expected);
1465 }
1466 #[test]
1467 fn clearer_should_reset_the_property() {
1468 let mut node = Node::new(Role::Unknown);
1469 node.$setter([1.0, 2.0]);
1470 node.$clearer();
1471 assert!(node.$getter().is_none());
1472 }
1473 })*
1474 }
1475}
1476
1477macro_rules! bool_property_methods {
1478 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1479 $(property_methods! {
1480 $(#[$doc])*
1481 ($id, $getter, get_bool_property, Option<bool>, $setter, set_bool_property, bool, $clearer)
1482 })*
1483 impl Node {
1484 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1485 }
1486 $(#[cfg(test)]
1487 mod $getter {
1488 use super::{Node, Role};
1489
1490 #[test]
1491 fn getter_should_return_default_value() {
1492 let node = Node::new(Role::Unknown);
1493 assert!(node.$getter().is_none());
1494 }
1495 #[test]
1496 fn setter_should_update_the_property() {
1497 let mut node = Node::new(Role::Unknown);
1498 node.$setter(true);
1499 assert_eq!(node.$getter(), Some(true));
1500 }
1501 #[test]
1502 fn clearer_should_reset_the_property() {
1503 let mut node = Node::new(Role::Unknown);
1504 node.$setter(true);
1505 node.$clearer();
1506 assert!(node.$getter().is_none());
1507 }
1508 })*
1509 }
1510}
1511
1512macro_rules! unique_enum_property_methods {
1513 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident, $variant:ident)),+) => {
1514 impl Node {
1515 $($(#[$doc])*
1516 #[inline]
1517 pub fn $getter(&self) -> Option<$id> {
1518 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1519 PropertyValue::$id(value) => Some(*value),
1520 _ => None,
1521 }
1522 }
1523 #[inline]
1524 pub fn $setter(&mut self, value: $id) {
1525 self.properties.set(PropertyId::$id, PropertyValue::$id(value));
1526 }
1527 #[inline]
1528 pub fn $clearer(&mut self) {
1529 self.properties.clear(PropertyId::$id);
1530 })*
1531 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1532 }
1533 $(#[cfg(test)]
1534 mod $getter {
1535 use super::{Node, Role};
1536
1537 #[test]
1538 fn getter_should_return_default_value() {
1539 let node = Node::new(Role::Unknown);
1540 assert!(node.$getter().is_none());
1541 }
1542 #[test]
1543 fn setter_should_update_the_property() {
1544 let mut node = Node::new(Role::Unknown);
1545 let variant = super::$id::$variant;
1546 node.$setter(variant);
1547 assert_eq!(node.$getter(), Some(variant));
1548 }
1549 #[test]
1550 fn clearer_should_reset_the_property() {
1551 let mut node = Node::new(Role::Unknown);
1552 node.$setter(super::$id::$variant);
1553 node.$clearer();
1554 assert!(node.$getter().is_none());
1555 }
1556 })*
1557 }
1558}
1559
1560impl Node {
1561 #[inline]
1562 pub fn new(role: Role) -> Self {
1563 Self {
1564 role,
1565 ..Default::default()
1566 }
1567 }
1568}
1569
1570impl Node {
1571 #[inline]
1572 pub fn role(&self) -> Role {
1573 self.role
1574 }
1575 #[inline]
1576 pub fn set_role(&mut self, value: Role) {
1577 self.role = value;
1578 }
1579
1580 #[inline]
1581 pub fn supports_action(&self, action: Action) -> bool {
1582 (self.actions & action.mask()) != 0
1583 }
1584 #[inline]
1585 pub fn add_action(&mut self, action: Action) {
1586 self.actions |= action.mask();
1587 }
1588 #[inline]
1589 pub fn remove_action(&mut self, action: Action) {
1590 self.actions &= !(action.mask());
1591 }
1592 #[inline]
1593 pub fn clear_actions(&mut self) {
1594 self.actions = 0;
1595 }
1596}
1597
1598flag_methods! {
1599 (Hidden, is_hidden, set_hidden, clear_hidden),
1602 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1603 (Required, is_required, set_required, clear_required),
1604 (Visited, is_visited, set_visited, clear_visited),
1605 (Busy, is_busy, set_busy, clear_busy),
1606 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1607 (Modal, is_modal, set_modal, clear_modal),
1609 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1613 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1615 (Disabled, is_disabled, set_disabled, clear_disabled),
1617 (Bold, is_bold, set_bold, clear_bold),
1618 (Italic, is_italic, set_italic, clear_italic),
1619 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1622 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1625 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1627 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1628 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1629 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1630 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1631}
1632
1633option_ref_type_getters! {
1634 (get_affine_property, Affine, Affine),
1635 (get_string_property, str, String),
1636 (get_coord_slice_property, [f32], CoordSlice),
1637 (get_text_selection_property, TextSelection, TextSelection)
1638}
1639
1640slice_type_getters! {
1641 (get_length_slice_property, u8, LengthSlice)
1642}
1643
1644copy_type_getters! {
1645 (get_rect_property, Rect, Rect),
1646 (get_node_id_property, NodeId, NodeId),
1647 (get_f64_property, f64, F64),
1648 (get_usize_property, usize, Usize),
1649 (get_color_property, u32, Color),
1650 (get_text_decoration_property, TextDecoration, TextDecoration),
1651 (get_bool_property, bool, Bool)
1652}
1653
1654box_type_setters! {
1655 (set_affine_property, Affine, Affine),
1656 (set_string_property, str, String),
1657 (set_length_slice_property, [u8], LengthSlice),
1658 (set_coord_slice_property, [f32], CoordSlice),
1659 (set_text_selection_property, TextSelection, TextSelection)
1660}
1661
1662copy_type_setters! {
1663 (set_rect_property, Rect, Rect),
1664 (set_node_id_property, NodeId, NodeId),
1665 (set_f64_property, f64, F64),
1666 (set_usize_property, usize, Usize),
1667 (set_color_property, u32, Color),
1668 (set_text_decoration_property, TextDecoration, TextDecoration),
1669 (set_bool_property, bool, Bool)
1670}
1671
1672vec_type_methods! {
1673 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
1674 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
1675}
1676
1677node_id_vec_property_methods! {
1678 (Children, children, set_children, push_child, clear_children),
1679 (Controls, controls, set_controls, push_controlled, clear_controls),
1680 (Details, details, set_details, push_detail, clear_details),
1681 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
1682 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
1683 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
1684 (Owns, owns, set_owns, push_owned, clear_owns),
1690 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
1693}
1694
1695node_id_property_methods! {
1696 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
1697 (ErrorMessage, error_message, set_error_message, clear_error_message),
1698 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
1699 (MemberOf, member_of, set_member_of, clear_member_of),
1700 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
1701 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
1702 (PopupFor, popup_for, set_popup_for, clear_popup_for)
1703}
1704
1705string_property_methods! {
1706 (Label, label, set_label, clear_label),
1711 (Description, description, set_description, clear_description),
1712 (Value, value, set_value, clear_value),
1713 (AccessKey, access_key, set_access_key, clear_access_key),
1721 (AuthorId, author_id, set_author_id, clear_author_id),
1724 (ClassName, class_name, set_class_name, clear_class_name),
1725 (FontFamily, font_family, set_font_family, clear_font_family),
1727 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
1728 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
1731 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
1735 (Language, language, set_language, clear_language),
1737 (Placeholder, placeholder, set_placeholder, clear_placeholder),
1742 (RoleDescription, role_description, set_role_description, clear_role_description),
1746 (StateDescription, state_description, set_state_description, clear_state_description),
1751 (Tooltip, tooltip, set_tooltip, clear_tooltip),
1756 (Url, url, set_url, clear_url),
1757 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
1758 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text)
1759}
1760
1761f64_property_methods! {
1762 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
1763 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
1764 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
1765 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
1766 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
1767 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
1768 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
1769 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
1770 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
1771 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
1772 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump),
1773 (FontSize, font_size, set_font_size, clear_font_size),
1775 (FontWeight, font_weight, set_font_weight, clear_font_weight)
1778}
1779
1780usize_property_methods! {
1781 (RowCount, row_count, set_row_count, clear_row_count),
1782 (ColumnCount, column_count, set_column_count, clear_column_count),
1783 (RowIndex, row_index, set_row_index, clear_row_index),
1784 (ColumnIndex, column_index, set_column_index, clear_column_index),
1785 (RowSpan, row_span, set_row_span, clear_row_span),
1786 (ColumnSpan, column_span, set_column_span, clear_column_span),
1787 (Level, level, set_level, clear_level),
1788 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
1790 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
1795}
1796
1797color_property_methods! {
1798 (ColorValue, color_value, set_color_value, clear_color_value),
1800 (BackgroundColor, background_color, set_background_color, clear_background_color),
1802 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
1804}
1805
1806text_decoration_property_methods! {
1807 (Overline, overline, set_overline, clear_overline),
1808 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
1809 (Underline, underline, set_underline, clear_underline)
1810}
1811
1812length_slice_property_methods! {
1813 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
1832
1833 (WordLengths, word_lengths, set_word_lengths, clear_word_lengths)
1856}
1857
1858coord_slice_property_methods! {
1859 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
1876
1877 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
1896}
1897
1898bool_property_methods! {
1899 (Expanded, is_expanded, set_expanded, clear_expanded),
1904
1905 (Selected, is_selected, set_selected, clear_selected)
1915}
1916
1917unique_enum_property_methods! {
1918 (Invalid, invalid, set_invalid, clear_invalid, Grammar),
1919 (Toggled, toggled, set_toggled, clear_toggled, True),
1920 (Live, live, set_live, clear_live, Polite),
1921 (TextDirection, text_direction, set_text_direction, clear_text_direction, RightToLeft),
1922 (Orientation, orientation, set_orientation, clear_orientation, Vertical),
1923 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction, Descending),
1924 (AriaCurrent, aria_current, set_aria_current, clear_aria_current, True),
1925 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete, List),
1926 (HasPopup, has_popup, set_has_popup, clear_has_popup, Menu),
1927 (ListStyle, list_style, set_list_style, clear_list_style, Disc),
1929 (TextAlign, text_align, set_text_align, clear_text_align, Right),
1930 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset, Superscript)
1931}
1932
1933property_methods! {
1934 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
1947
1948 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
1959
1960 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection)
1961}
1962
1963impl Node {
1964 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1965}
1966
1967#[cfg(test)]
1968mod transform {
1969 use super::{Affine, Node, Role};
1970
1971 #[test]
1972 fn getter_should_return_default_value() {
1973 let node = Node::new(Role::Unknown);
1974 assert!(node.transform().is_none());
1975 }
1976 #[test]
1977 fn setter_should_update_the_property() {
1978 let mut node = Node::new(Role::Unknown);
1979 node.set_transform(Affine::IDENTITY);
1980 assert_eq!(node.transform(), Some(&Affine::IDENTITY));
1981 }
1982 #[test]
1983 fn clearer_should_reset_the_property() {
1984 let mut node = Node::new(Role::Unknown);
1985 node.set_transform(Affine::IDENTITY);
1986 node.clear_transform();
1987 assert!(node.transform().is_none());
1988 }
1989}
1990
1991#[cfg(test)]
1992mod bounds {
1993 use super::{Node, Rect, Role};
1994
1995 #[test]
1996 fn getter_should_return_default_value() {
1997 let node = Node::new(Role::Unknown);
1998 assert!(node.bounds().is_none());
1999 }
2000 #[test]
2001 fn setter_should_update_the_property() {
2002 let mut node = Node::new(Role::Unknown);
2003 let value = Rect {
2004 x0: 0.0,
2005 y0: 1.0,
2006 x1: 2.0,
2007 y1: 3.0,
2008 };
2009 node.set_bounds(value);
2010 assert_eq!(node.bounds(), Some(value));
2011 }
2012 #[test]
2013 fn clearer_should_reset_the_property() {
2014 let mut node = Node::new(Role::Unknown);
2015 node.set_bounds(Rect {
2016 x0: 0.0,
2017 y0: 1.0,
2018 x1: 2.0,
2019 y1: 3.0,
2020 });
2021 node.clear_bounds();
2022 assert!(node.bounds().is_none());
2023 }
2024}
2025
2026#[cfg(test)]
2027mod text_selection {
2028 use super::{Node, NodeId, Role, TextPosition, TextSelection};
2029
2030 #[test]
2031 fn getter_should_return_default_value() {
2032 let node = Node::new(Role::Unknown);
2033 assert!(node.text_selection().is_none());
2034 }
2035 #[test]
2036 fn setter_should_update_the_property() {
2037 let mut node = Node::new(Role::Unknown);
2038 let value = TextSelection {
2039 anchor: TextPosition {
2040 node: NodeId(0),
2041 character_index: 0,
2042 },
2043 focus: TextPosition {
2044 node: NodeId(0),
2045 character_index: 2,
2046 },
2047 };
2048 node.set_text_selection(value);
2049 assert_eq!(node.text_selection(), Some(&value));
2050 }
2051 #[test]
2052 fn clearer_should_reset_the_property() {
2053 let mut node = Node::new(Role::Unknown);
2054 node.set_text_selection(TextSelection {
2055 anchor: TextPosition {
2056 node: NodeId(0),
2057 character_index: 0,
2058 },
2059 focus: TextPosition {
2060 node: NodeId(0),
2061 character_index: 2,
2062 },
2063 });
2064 node.clear_text_selection();
2065 assert!(node.text_selection().is_none());
2066 }
2067}
2068
2069vec_property_methods! {
2070 (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)
2071}
2072
2073#[cfg(test)]
2074mod custom_actions {
2075 use super::{CustomAction, Node, Role};
2076
2077 #[test]
2078 fn getter_should_return_default_value() {
2079 let node = Node::new(Role::Unknown);
2080 assert!(node.custom_actions().is_empty());
2081 }
2082 #[test]
2083 fn setter_should_update_the_property() {
2084 let mut node = Node::new(Role::Unknown);
2085 let value = alloc::vec![
2086 CustomAction {
2087 id: 0,
2088 description: "first test action".into(),
2089 },
2090 CustomAction {
2091 id: 1,
2092 description: "second test action".into(),
2093 },
2094 ];
2095 node.set_custom_actions(value.clone());
2096 assert_eq!(node.custom_actions(), value);
2097 }
2098 #[test]
2099 fn pusher_should_update_the_property() {
2100 let mut node = Node::new(Role::Unknown);
2101 let first_action = CustomAction {
2102 id: 0,
2103 description: "first test action".into(),
2104 };
2105 let second_action = CustomAction {
2106 id: 1,
2107 description: "second test action".into(),
2108 };
2109 node.push_custom_action(first_action.clone());
2110 assert_eq!(node.custom_actions(), &[first_action.clone()]);
2111 node.push_custom_action(second_action.clone());
2112 assert_eq!(node.custom_actions(), &[first_action, second_action]);
2113 }
2114 #[test]
2115 fn clearer_should_reset_the_property() {
2116 let mut node = Node::new(Role::Unknown);
2117 node.set_custom_actions([CustomAction {
2118 id: 0,
2119 description: "test action".into(),
2120 }]);
2121 node.clear_custom_actions();
2122 assert!(node.custom_actions().is_empty());
2123 }
2124}
2125
2126impl fmt::Debug for Node {
2127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2128 let mut fmt = f.debug_struct("Node");
2129
2130 fmt.field("role", &self.role());
2131
2132 let supported_actions = action_mask_to_action_vec(self.actions);
2133 if !supported_actions.is_empty() {
2134 fmt.field("actions", &supported_actions);
2135 }
2136
2137 self.debug_flag_properties(&mut fmt);
2138 self.debug_node_id_vec_properties(&mut fmt);
2139 self.debug_node_id_properties(&mut fmt);
2140 self.debug_string_properties(&mut fmt);
2141 self.debug_f64_properties(&mut fmt);
2142 self.debug_usize_properties(&mut fmt);
2143 self.debug_color_properties(&mut fmt);
2144 self.debug_text_decoration_properties(&mut fmt);
2145 self.debug_length_slice_properties(&mut fmt);
2146 self.debug_coord_slice_properties(&mut fmt);
2147 self.debug_bool_properties(&mut fmt);
2148 self.debug_unique_enum_properties(&mut fmt);
2149 self.debug_option_properties(&mut fmt);
2150
2151 let custom_actions = self.custom_actions();
2152 if !custom_actions.is_empty() {
2153 fmt.field("custom_actions", &custom_actions);
2154 }
2155
2156 fmt.finish()
2157 }
2158}
2159
2160#[cfg(feature = "serde")]
2161macro_rules! serialize_property {
2162 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
2163 match &$self.values[$index as usize] {
2164 PropertyValue::None => (),
2165 $(PropertyValue::$variant(value) => {
2166 $map.serialize_entry(&$id, &value)?;
2167 })*
2168 }
2169 }
2170}
2171
2172#[cfg(feature = "serde")]
2173macro_rules! deserialize_property {
2174 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
2175 match $key {
2176 $($(PropertyId::$id => {
2177 let value = $map.next_value()?;
2178 $props.set(PropertyId::$id, PropertyValue::$type(value));
2179 })*)*
2180 PropertyId::Unset => {
2181 let _ = $map.next_value::<IgnoredAny>()?;
2182 }
2183 }
2184 }
2185}
2186
2187#[cfg(feature = "serde")]
2188impl Serialize for Properties {
2189 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2190 where
2191 S: Serializer,
2192 {
2193 let mut len = 0;
2194 for value in &*self.values {
2195 if !matches!(*value, PropertyValue::None) {
2196 len += 1;
2197 }
2198 }
2199 let mut map = serializer.serialize_map(Some(len))?;
2200 for (id, index) in self.indices.0.iter().copied().enumerate() {
2201 if index == PropertyId::Unset as u8 {
2202 continue;
2203 }
2204 let id = PropertyId::n(id as _).unwrap();
2205 serialize_property!(self, map, index, id, {
2206 NodeIdVec,
2207 NodeId,
2208 String,
2209 F64,
2210 Usize,
2211 Color,
2212 TextDecoration,
2213 LengthSlice,
2214 CoordSlice,
2215 Bool,
2216 Invalid,
2217 Toggled,
2218 Live,
2219 TextDirection,
2220 Orientation,
2221 SortDirection,
2222 AriaCurrent,
2223 AutoComplete,
2224 HasPopup,
2225 ListStyle,
2226 TextAlign,
2227 VerticalOffset,
2228 Affine,
2229 Rect,
2230 TextSelection,
2231 CustomActionVec
2232 });
2233 }
2234 map.end()
2235 }
2236}
2237
2238#[cfg(feature = "serde")]
2239struct PropertiesVisitor;
2240
2241#[cfg(feature = "serde")]
2242impl<'de> Visitor<'de> for PropertiesVisitor {
2243 type Value = Properties;
2244
2245 #[inline]
2246 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2247 formatter.write_str("property map")
2248 }
2249
2250 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
2251 where
2252 V: MapAccess<'de>,
2253 {
2254 let mut props = Properties::default();
2255 while let Some(id) = map.next_key()? {
2256 deserialize_property!(props, map, id, {
2257 NodeIdVec {
2258 Children,
2259 Controls,
2260 Details,
2261 DescribedBy,
2262 FlowTo,
2263 LabelledBy,
2264 Owns,
2265 RadioGroup
2266 },
2267 NodeId {
2268 ActiveDescendant,
2269 ErrorMessage,
2270 InPageLinkTarget,
2271 MemberOf,
2272 NextOnLine,
2273 PreviousOnLine,
2274 PopupFor
2275 },
2276 String {
2277 Label,
2278 Description,
2279 Value,
2280 AccessKey,
2281 AuthorId,
2282 ClassName,
2283 FontFamily,
2284 HtmlTag,
2285 InnerHtml,
2286 KeyboardShortcut,
2287 Language,
2288 Placeholder,
2289 RoleDescription,
2290 StateDescription,
2291 Tooltip,
2292 Url,
2293 RowIndexText,
2294 ColumnIndexText
2295 },
2296 F64 {
2297 ScrollX,
2298 ScrollXMin,
2299 ScrollXMax,
2300 ScrollY,
2301 ScrollYMin,
2302 ScrollYMax,
2303 NumericValue,
2304 MinNumericValue,
2305 MaxNumericValue,
2306 NumericValueStep,
2307 NumericValueJump,
2308 FontSize,
2309 FontWeight
2310 },
2311 Usize {
2312 RowCount,
2313 ColumnCount,
2314 RowIndex,
2315 ColumnIndex,
2316 RowSpan,
2317 ColumnSpan,
2318 Level,
2319 SizeOfSet,
2320 PositionInSet
2321 },
2322 Color {
2323 ColorValue,
2324 BackgroundColor,
2325 ForegroundColor
2326 },
2327 TextDecoration {
2328 Overline,
2329 Strikethrough,
2330 Underline
2331 },
2332 LengthSlice {
2333 CharacterLengths,
2334 WordLengths
2335 },
2336 CoordSlice {
2337 CharacterPositions,
2338 CharacterWidths
2339 },
2340 Bool {
2341 Expanded,
2342 Selected
2343 },
2344 Invalid { Invalid },
2345 Toggled { Toggled },
2346 Live { Live },
2347 TextDirection { TextDirection },
2348 Orientation { Orientation },
2349 SortDirection { SortDirection },
2350 AriaCurrent { AriaCurrent },
2351 AutoComplete { AutoComplete },
2352 HasPopup { HasPopup },
2353 ListStyle { ListStyle },
2354 TextAlign { TextAlign },
2355 VerticalOffset { VerticalOffset },
2356 Affine { Transform },
2357 Rect { Bounds },
2358 TextSelection { TextSelection },
2359 CustomActionVec { CustomActions }
2360 });
2361 }
2362
2363 Ok(props)
2364 }
2365}
2366
2367#[cfg(feature = "serde")]
2368impl<'de> Deserialize<'de> for Properties {
2369 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2370 where
2371 D: Deserializer<'de>,
2372 {
2373 deserializer.deserialize_map(PropertiesVisitor)
2374 }
2375}
2376
2377#[cfg(feature = "schemars")]
2378macro_rules! add_schema_property {
2379 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
2380 let name = format!("{:?}", $enum_value);
2381 let name = name[..1].to_ascii_lowercase() + &name[1..];
2382 let subschema = $gen.subschema_for::<$type>();
2383 $properties.insert(name, subschema);
2384 }};
2385}
2386
2387#[cfg(feature = "schemars")]
2388macro_rules! add_properties_to_schema {
2389 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
2390 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
2391 }
2392}
2393
2394#[cfg(feature = "schemars")]
2395impl JsonSchema for Properties {
2396 #[inline]
2397 fn schema_name() -> String {
2398 "Properties".into()
2399 }
2400
2401 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
2402 let mut properties = SchemaMap::<String, Schema>::new();
2403 add_properties_to_schema!(gen, properties, {
2404 Vec<NodeId> {
2405 Children,
2406 Controls,
2407 Details,
2408 DescribedBy,
2409 FlowTo,
2410 LabelledBy,
2411 Owns,
2412 RadioGroup
2413 },
2414 NodeId {
2415 ActiveDescendant,
2416 ErrorMessage,
2417 InPageLinkTarget,
2418 MemberOf,
2419 NextOnLine,
2420 PreviousOnLine,
2421 PopupFor
2422 },
2423 Box<str> {
2424 Label,
2425 Description,
2426 Value,
2427 AccessKey,
2428 AuthorId,
2429 ClassName,
2430 FontFamily,
2431 HtmlTag,
2432 InnerHtml,
2433 KeyboardShortcut,
2434 Language,
2435 Placeholder,
2436 RoleDescription,
2437 StateDescription,
2438 Tooltip,
2439 Url,
2440 RowIndexText,
2441 ColumnIndexText
2442 },
2443 f64 {
2444 ScrollX,
2445 ScrollXMin,
2446 ScrollXMax,
2447 ScrollY,
2448 ScrollYMin,
2449 ScrollYMax,
2450 NumericValue,
2451 MinNumericValue,
2452 MaxNumericValue,
2453 NumericValueStep,
2454 NumericValueJump,
2455 FontSize,
2456 FontWeight
2457 },
2458 usize {
2459 RowCount,
2460 ColumnCount,
2461 RowIndex,
2462 ColumnIndex,
2463 RowSpan,
2464 ColumnSpan,
2465 Level,
2466 SizeOfSet,
2467 PositionInSet
2468 },
2469 u32 {
2470 ColorValue,
2471 BackgroundColor,
2472 ForegroundColor
2473 },
2474 TextDecoration {
2475 Overline,
2476 Strikethrough,
2477 Underline
2478 },
2479 Box<[u8]> {
2480 CharacterLengths,
2481 WordLengths
2482 },
2483 Box<[f32]> {
2484 CharacterPositions,
2485 CharacterWidths
2486 },
2487 bool {
2488 Expanded,
2489 Selected
2490 },
2491 Invalid { Invalid },
2492 Toggled { Toggled },
2493 Live { Live },
2494 TextDirection { TextDirection },
2495 Orientation { Orientation },
2496 SortDirection { SortDirection },
2497 AriaCurrent { AriaCurrent },
2498 AutoComplete { AutoComplete },
2499 HasPopup { HasPopup },
2500 ListStyle { ListStyle },
2501 TextAlign { TextAlign },
2502 VerticalOffset { VerticalOffset },
2503 Affine { Transform },
2504 Rect { Bounds },
2505 TextSelection { TextSelection },
2506 Vec<CustomAction> { CustomActions }
2507 });
2508 SchemaObject {
2509 instance_type: Some(InstanceType::Object.into()),
2510 object: Some(
2511 ObjectValidation {
2512 properties,
2513 ..Default::default()
2514 }
2515 .into(),
2516 ),
2517 ..Default::default()
2518 }
2519 .into()
2520 }
2521}
2522
2523#[derive(Clone, Debug, PartialEq, Eq)]
2526#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2527#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2528#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2529#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2530pub struct Tree {
2531 pub root: NodeId,
2533 pub toolkit_name: Option<String>,
2535 pub toolkit_version: Option<String>,
2537}
2538
2539impl Tree {
2540 #[inline]
2541 pub fn new(root: NodeId) -> Tree {
2542 Tree {
2543 root,
2544 toolkit_name: None,
2545 toolkit_version: None,
2546 }
2547 }
2548}
2549
2550#[derive(Clone, Debug, PartialEq)]
2562#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2563#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2564#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2565#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2566pub struct TreeUpdate {
2567 pub nodes: Vec<(NodeId, Node)>,
2588
2589 pub tree: Option<Tree>,
2594
2595 pub focus: NodeId,
2601}
2602
2603#[derive(Clone, Debug, PartialEq)]
2604#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2605#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2606#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2607#[repr(C)]
2608pub enum ActionData {
2609 CustomAction(i32),
2610 Value(Box<str>),
2611 NumericValue(f64),
2612 ScrollTargetRect(Rect),
2615 ScrollToPoint(Point),
2618 SetScrollOffset(Point),
2621 SetTextSelection(TextSelection),
2622}
2623
2624#[derive(Clone, Debug, PartialEq)]
2625#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2626#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2627#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2628#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2629pub struct ActionRequest {
2630 pub action: Action,
2631 pub target: NodeId,
2632 pub data: Option<ActionData>,
2633}
2634
2635pub trait ActivationHandler {
2637 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
2659}
2660
2661pub trait ActionHandler {
2663 fn do_action(&mut self, request: ActionRequest);
2673}
2674
2675pub trait DeactivationHandler {
2677 fn deactivate_accessibility(&mut self);
2685}
2686
2687#[cfg(test)]
2688mod tests {
2689 use super::*;
2690 use alloc::format;
2691
2692 #[test]
2693 fn u64_should_be_convertible_to_node_id() {
2694 assert_eq!(NodeId::from(0u64), NodeId(0));
2695 assert_eq!(NodeId::from(1u64), NodeId(1));
2696 }
2697
2698 #[test]
2699 fn node_id_should_be_convertible_to_u64() {
2700 assert_eq!(u64::from(NodeId(0)), 0u64);
2701 assert_eq!(u64::from(NodeId(1)), 1u64);
2702 }
2703
2704 #[test]
2705 fn node_id_should_have_debug_repr() {
2706 assert_eq!(&format!("{:?}", NodeId(0)), "#0");
2707 assert_eq!(&format!("{:?}", NodeId(1)), "#1");
2708 }
2709
2710 #[test]
2711 fn action_n_should_return_the_corresponding_variant() {
2712 assert_eq!(Action::n(0), Some(Action::Click));
2713 assert_eq!(Action::n(1), Some(Action::Focus));
2714 assert_eq!(Action::n(2), Some(Action::Blur));
2715 assert_eq!(Action::n(3), Some(Action::Collapse));
2716 assert_eq!(Action::n(4), Some(Action::Expand));
2717 assert_eq!(Action::n(5), Some(Action::CustomAction));
2718 assert_eq!(Action::n(6), Some(Action::Decrement));
2719 assert_eq!(Action::n(7), Some(Action::Increment));
2720 assert_eq!(Action::n(8), Some(Action::HideTooltip));
2721 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
2722 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
2723 assert_eq!(Action::n(11), Some(Action::ScrollBackward));
2724 assert_eq!(Action::n(12), Some(Action::ScrollDown));
2725 assert_eq!(Action::n(13), Some(Action::ScrollForward));
2726 assert_eq!(Action::n(14), Some(Action::ScrollLeft));
2727 assert_eq!(Action::n(15), Some(Action::ScrollRight));
2728 assert_eq!(Action::n(16), Some(Action::ScrollUp));
2729 assert_eq!(Action::n(17), Some(Action::ScrollIntoView));
2730 assert_eq!(Action::n(18), Some(Action::ScrollToPoint));
2731 assert_eq!(Action::n(19), Some(Action::SetScrollOffset));
2732 assert_eq!(Action::n(20), Some(Action::SetTextSelection));
2733 assert_eq!(
2734 Action::n(21),
2735 Some(Action::SetSequentialFocusNavigationStartingPoint)
2736 );
2737 assert_eq!(Action::n(22), Some(Action::SetValue));
2738 assert_eq!(Action::n(23), Some(Action::ShowContextMenu));
2739 assert_eq!(Action::n(24), None);
2740 }
2741
2742 #[test]
2743 fn empty_action_mask_should_be_converted_to_empty_vec() {
2744 assert_eq!(
2745 Vec::<Action>::new(),
2746 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
2747 );
2748 }
2749
2750 #[test]
2751 fn action_mask_should_be_convertible_to_vec() {
2752 let mut node = Node::new(Role::Unknown);
2753 node.add_action(Action::Click);
2754 assert_eq!(
2755 &[Action::Click],
2756 action_mask_to_action_vec(node.actions).as_slice()
2757 );
2758
2759 let mut node = Node::new(Role::Unknown);
2760 node.add_action(Action::ShowContextMenu);
2761 assert_eq!(
2762 &[Action::ShowContextMenu],
2763 action_mask_to_action_vec(node.actions).as_slice()
2764 );
2765
2766 let mut node = Node::new(Role::Unknown);
2767 node.add_action(Action::Click);
2768 node.add_action(Action::ShowContextMenu);
2769 assert_eq!(
2770 &[Action::Click, Action::ShowContextMenu],
2771 action_mask_to_action_vec(node.actions).as_slice()
2772 );
2773
2774 let mut node = Node::new(Role::Unknown);
2775 node.add_action(Action::Focus);
2776 node.add_action(Action::Blur);
2777 node.add_action(Action::Collapse);
2778 assert_eq!(
2779 &[Action::Focus, Action::Blur, Action::Collapse],
2780 action_mask_to_action_vec(node.actions).as_slice()
2781 );
2782 }
2783
2784 #[test]
2785 fn new_node_should_have_user_provided_role() {
2786 let node = Node::new(Role::Button);
2787 assert_eq!(node.role(), Role::Button);
2788 }
2789
2790 #[test]
2791 fn node_role_setter_should_update_the_role() {
2792 let mut node = Node::new(Role::Button);
2793 node.set_role(Role::CheckBox);
2794 assert_eq!(node.role(), Role::CheckBox);
2795 }
2796
2797 #[test]
2798 fn new_node_should_not_support_anyaction() {
2799 let node = Node::new(Role::Unknown);
2800 assert!(!node.supports_action(Action::Click));
2801 assert!(!node.supports_action(Action::Focus));
2802 assert!(!node.supports_action(Action::Blur));
2803 assert!(!node.supports_action(Action::Collapse));
2804 assert!(!node.supports_action(Action::Expand));
2805 assert!(!node.supports_action(Action::CustomAction));
2806 assert!(!node.supports_action(Action::Decrement));
2807 assert!(!node.supports_action(Action::Increment));
2808 assert!(!node.supports_action(Action::HideTooltip));
2809 assert!(!node.supports_action(Action::ShowTooltip));
2810 assert!(!node.supports_action(Action::ReplaceSelectedText));
2811 assert!(!node.supports_action(Action::ScrollBackward));
2812 assert!(!node.supports_action(Action::ScrollDown));
2813 assert!(!node.supports_action(Action::ScrollForward));
2814 assert!(!node.supports_action(Action::ScrollLeft));
2815 assert!(!node.supports_action(Action::ScrollRight));
2816 assert!(!node.supports_action(Action::ScrollUp));
2817 assert!(!node.supports_action(Action::ScrollIntoView));
2818 assert!(!node.supports_action(Action::ScrollToPoint));
2819 assert!(!node.supports_action(Action::SetScrollOffset));
2820 assert!(!node.supports_action(Action::SetTextSelection));
2821 assert!(!node.supports_action(Action::SetSequentialFocusNavigationStartingPoint));
2822 assert!(!node.supports_action(Action::SetValue));
2823 assert!(!node.supports_action(Action::ShowContextMenu));
2824 }
2825
2826 #[test]
2827 fn node_add_action_should_add_the_action() {
2828 let mut node = Node::new(Role::Unknown);
2829 node.add_action(Action::Focus);
2830 assert!(node.supports_action(Action::Focus));
2831 node.add_action(Action::Blur);
2832 assert!(node.supports_action(Action::Blur));
2833 }
2834
2835 #[test]
2836 fn node_add_action_should_do_nothing_if_the_action_is_already_supported() {
2837 let mut node = Node::new(Role::Unknown);
2838 node.add_action(Action::Focus);
2839 node.add_action(Action::Focus);
2840 assert!(node.supports_action(Action::Focus));
2841 }
2842
2843 #[test]
2844 fn node_remove_action_should_remove_the_action() {
2845 let mut node = Node::new(Role::Unknown);
2846 node.add_action(Action::Blur);
2847 node.remove_action(Action::Blur);
2848 assert!(!node.supports_action(Action::Blur));
2849 }
2850
2851 #[test]
2852 fn node_clear_actions_should_remove_all_actions() {
2853 let mut node = Node::new(Role::Unknown);
2854 node.add_action(Action::Focus);
2855 node.add_action(Action::Blur);
2856 node.clear_actions();
2857 assert!(!node.supports_action(Action::Focus));
2858 assert!(!node.supports_action(Action::Blur));
2859 }
2860
2861 #[test]
2862 fn node_should_have_debug_repr() {
2863 let mut node = Node::new(Role::Unknown);
2864 node.add_action(Action::Click);
2865 node.add_action(Action::Focus);
2866 node.set_hidden();
2867 node.set_multiselectable();
2868 node.set_children([NodeId(0), NodeId(1)]);
2869 node.set_active_descendant(NodeId(2));
2870 node.push_custom_action(CustomAction {
2871 id: 0,
2872 description: "test action".into(),
2873 });
2874
2875 assert_eq!(
2876 &format!("{:?}", node),
2877 r#"Node { role: Unknown, actions: [Click, Focus], is_hidden: true, is_multiselectable: true, children: [#0, #1], active_descendant: #2, custom_actions: [CustomAction { id: 0, description: "test action" }] }"#
2878 );
2879 }
2880
2881 #[test]
2882 fn new_tree_should_have_root_id() {
2883 let tree = Tree::new(NodeId(1));
2884 assert_eq!(tree.root, NodeId(1));
2885 assert_eq!(tree.toolkit_name, None);
2886 assert_eq!(tree.toolkit_version, None);
2887 }
2888}