fidl_fuchsia_ui_focus_ext/
lib.rsuse fidl_fuchsia_ui_focus::{FocusChain, FocusKoidChain};
use fidl_fuchsia_ui_views_ext::ViewRefExt;
use fuchsia_scenic as scenic;
use zx::{Koid, Status};
pub trait FocusChainExt
where
Self: Sized,
{
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn duplicate(&self) -> Result<Self, Status>;
fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_>;
fn equivalent<O: FocusChainExt>(&self, other: &O) -> Result<bool, Status> {
let self_len = self.len();
if self_len != other.len() {
return Ok(false);
}
if self_len == 0 {
return Ok(true);
}
let mut zipped = std::iter::zip(self.koids(), other.koids());
while let Some((a, b)) = zipped.next() {
if a? != b? {
return Ok(false);
}
}
Ok(true)
}
fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status>;
}
impl FocusChainExt for FocusChain {
fn len(&self) -> usize {
match self.focus_chain.as_ref() {
None => 0,
Some(v) => v.len(),
}
}
fn duplicate(&self) -> Result<Self, Status> {
let v = match self.focus_chain.as_ref() {
None => None,
Some(v) => Some(
v.iter().map(|vr| scenic::duplicate_view_ref(vr)).collect::<Result<Vec<_>, _>>()?,
),
};
let output = FocusChain { focus_chain: v, ..Default::default() };
Ok(output)
}
fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_> {
match &self.focus_chain {
None => Box::new(std::iter::empty()),
Some(v) => Box::new(v.iter().map(|vr| vr.get_koid())),
}
}
fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status> {
let raw_koids = match self.focus_chain.as_ref() {
None => None,
Some(_) => Some(
self.koids()
.map(|result| -> Result<u64, Status> { result.map(|koid| koid.raw_koid()) })
.collect::<Result<Vec<_>, _>>()?,
),
};
Ok(FocusKoidChain { focus_chain: raw_koids, ..Default::default() })
}
}
impl FocusChainExt for FocusKoidChain {
fn len(&self) -> usize {
match self.focus_chain.as_ref() {
None => 0,
Some(v) => v.len(),
}
}
fn duplicate(&self) -> Result<Self, Status> {
Ok(self.clone())
}
fn koids(&self) -> Box<dyn ExactSizeIterator<Item = Result<Koid, Status>> + '_> {
match &self.focus_chain {
None => Box::new(std::iter::empty()),
Some(v) => Box::new(v.iter().map(|raw| Ok(Koid::from_raw(*raw)))),
}
}
fn to_focus_koid_chain(&self) -> Result<FocusKoidChain, Status> {
self.duplicate()
}
}
#[cfg(test)]
mod tests {
use super::*;
use fidl_fuchsia_ui_focus_test_helpers::make_focus_chain;
#[test]
fn focus_chain_duplicate() {
let (source, _control_refs) = make_focus_chain(2);
let target = source.duplicate().expect("error in duplicate()");
let source_koids = source.koids().collect::<Result<Vec<_>, _>>().unwrap();
let target_koids = target.koids().collect::<Result<Vec<_>, _>>().unwrap();
assert_eq!(source_koids, target_koids,);
}
#[test]
fn focus_chain_duplicate_empty() {
let source = FocusChain::default();
let target = source.duplicate().expect("error in duplicate()");
assert_eq!(target.focus_chain, None);
}
#[test]
fn focus_chain_equivalent_empty() {
let a = FocusChain::default();
let b = FocusChain::default();
assert!(a.equivalent(&b).unwrap());
let (a, _) = make_focus_chain(0);
let (b, _) = make_focus_chain(0);
assert!(a.equivalent(&b).unwrap());
}
#[test]
fn focus_chain_equivalent_same_lengths() {
let (a, _a) = make_focus_chain(3);
let (b, _b) = make_focus_chain(3);
assert!(!a.equivalent(&b).unwrap());
}
#[test]
fn focus_chain_equivalent_different_lengths() {
let (a, _a) = make_focus_chain(3);
let (b, _b) = make_focus_chain(5);
assert!(!a.equivalent(&b).unwrap());
}
#[test]
fn focus_chain_equivalent_duplicates() {
let (a, _a) = make_focus_chain(3);
let b = a.duplicate().expect("duplicate");
assert!(a.equivalent(&b).unwrap());
}
#[test]
fn focus_chain_to_focus_koid_chain() {
let (focus_chain, _view_control_refs) = make_focus_chain(2);
let raw_koids = vec![
focus_chain.focus_chain.as_ref().unwrap()[0].get_koid().unwrap().raw_koid(),
focus_chain.focus_chain.as_ref().unwrap()[1].get_koid().unwrap().raw_koid(),
];
let expected = FocusKoidChain { focus_chain: Some(raw_koids), ..Default::default() };
let actual = focus_chain.to_focus_koid_chain().unwrap();
assert_eq!(expected, actual);
}
#[test]
fn focus_chain_equivalent_focus_koid_chain() {
let (chain_a, _vcr_a) = make_focus_chain(2);
let (chain_b, _vcr_b) = make_focus_chain(2);
let koid_chain_a = chain_a.to_focus_koid_chain().unwrap();
let koid_chain_b = chain_b.to_focus_koid_chain().unwrap();
assert!(chain_a.equivalent(&koid_chain_a).unwrap());
assert!(!chain_a.equivalent(&koid_chain_b).unwrap())
}
}