fidl_fuchsia_ui_focus_ext/
lib.rs1use fidl_fuchsia_ui_focus::{FocusChain, FocusKoidChain};
8use fidl_fuchsia_ui_views_ext::ViewRefExt;
9use fuchsia_scenic as scenic;
10use zx::{Koid, Status};
11
12pub trait FocusChainExt
15where
16 Self: Sized,
17{
18 fn len(&self) -> usize;
20
21 fn is_empty(&self) -> bool {
23 self.len() == 0
24 }
25
26 fn duplicate(&self) -> Result<Self, Status>;
29
30 fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_>;
33
34 fn equivalent<O: FocusChainExt>(&self, other: &O) -> Result<bool, Status> {
37 let self_len = self.len();
38 if self_len != other.len() {
39 return Ok(false);
40 }
41 if self_len == 0 {
42 return Ok(true);
43 }
44
45 let mut zipped = std::iter::zip(self.koids(), other.koids());
46 while let Some((a, b)) = zipped.next() {
47 if a? != b? {
48 return Ok(false);
49 }
50 }
51 Ok(true)
52 }
53
54 fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status>;
57}
58
59impl FocusChainExt for FocusChain {
60 fn len(&self) -> usize {
61 match self.focus_chain.as_ref() {
62 None => 0,
63 Some(v) => v.len(),
64 }
65 }
66
67 fn duplicate(&self) -> Result<Self, Status> {
68 let v = match self.focus_chain.as_ref() {
69 None => None,
70 Some(v) => Some(
71 v.iter().map(|vr| scenic::duplicate_view_ref(vr)).collect::<Result<Vec<_>, _>>()?,
72 ),
73 };
74 let output = FocusChain { focus_chain: v, ..Default::default() };
75 Ok(output)
76 }
77
78 fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_> {
79 match &self.focus_chain {
80 None => Box::new(std::iter::empty()),
81 Some(v) => Box::new(v.iter().map(|vr| vr.get_koid())),
82 }
83 }
84
85 fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status> {
86 let raw_koids = match self.focus_chain.as_ref() {
87 None => None,
88 Some(_) => Some(
89 self.koids()
90 .map(|result| -> Result<u64, Status> { result.map(|koid| koid.raw_koid()) })
91 .collect::<Result<Vec<_>, _>>()?,
92 ),
93 };
94 Ok(FocusKoidChain { focus_chain: raw_koids, ..Default::default() })
95 }
96}
97
98impl FocusChainExt for FocusKoidChain {
99 fn len(&self) -> usize {
100 match self.focus_chain.as_ref() {
101 None => 0,
102 Some(v) => v.len(),
103 }
104 }
105
106 fn duplicate(&self) -> Result<Self, Status> {
108 Ok(self.clone())
109 }
110
111 fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_> {
112 match &self.focus_chain {
113 None => Box::new(std::iter::empty()),
114 Some(v) => Box::new(v.iter().map(|raw| Ok(Koid::from_raw(*raw)))),
115 }
116 }
117
118 fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status> {
120 self.duplicate()
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use fidl_fuchsia_ui_focus_test_helpers::make_focus_chain;
128
129 #[test]
130 fn focus_chain_duplicate() {
131 let (source, _control_refs) = make_focus_chain(2);
132 let target = source.duplicate().expect("error in duplicate()");
133
134 let source_koids = source.koids().collect::<Result<Vec<_>, _>>().unwrap();
135 let target_koids = target.koids().collect::<Result<Vec<_>, _>>().unwrap();
136
137 assert_eq!(source_koids, target_koids,);
138 }
139
140 #[test]
141 fn focus_chain_duplicate_empty() {
142 let source = FocusChain::default();
143 let target = source.duplicate().expect("error in duplicate()");
144
145 assert_eq!(target.focus_chain, None);
146 }
147
148 #[test]
149 fn focus_chain_equivalent_empty() {
150 let a = FocusChain::default();
151 let b = FocusChain::default();
152 assert!(a.equivalent(&b).unwrap());
153
154 let (a, _) = make_focus_chain(0);
155 let (b, _) = make_focus_chain(0);
156 assert!(a.equivalent(&b).unwrap());
157 }
158
159 #[test]
160 fn focus_chain_equivalent_same_lengths() {
161 let (a, _a) = make_focus_chain(3);
162 let (b, _b) = make_focus_chain(3);
163 assert!(!a.equivalent(&b).unwrap());
164 }
165
166 #[test]
167 fn focus_chain_equivalent_different_lengths() {
168 let (a, _a) = make_focus_chain(3);
169 let (b, _b) = make_focus_chain(5);
170 assert!(!a.equivalent(&b).unwrap());
171 }
172
173 #[test]
174 fn focus_chain_equivalent_duplicates() {
175 let (a, _a) = make_focus_chain(3);
176 let b = a.duplicate().expect("duplicate");
177 assert!(a.equivalent(&b).unwrap());
178 }
179
180 #[test]
181 fn focus_chain_to_focus_koid_chain() {
182 let (focus_chain, _view_control_refs) = make_focus_chain(2);
183 let raw_koids = vec![
184 focus_chain.focus_chain.as_ref().unwrap()[0].get_koid().unwrap().raw_koid(),
185 focus_chain.focus_chain.as_ref().unwrap()[1].get_koid().unwrap().raw_koid(),
186 ];
187
188 let expected = FocusKoidChain { focus_chain: Some(raw_koids), ..Default::default() };
189
190 let actual = focus_chain.to_focus_koid_chain().unwrap();
191
192 assert_eq!(expected, actual);
193 }
194
195 #[test]
196 fn focus_chain_equivalent_focus_koid_chain() {
197 let (chain_a, _vcr_a) = make_focus_chain(2);
198 let (chain_b, _vcr_b) = make_focus_chain(2);
199
200 let koid_chain_a = chain_a.to_focus_koid_chain().unwrap();
201 let koid_chain_b = chain_b.to_focus_koid_chain().unwrap();
202
203 assert!(chain_a.equivalent(&koid_chain_a).unwrap());
204 assert!(!chain_a.equivalent(&koid_chain_b).unwrap())
205 }
206}