use iced::Element; use super::{Message, Navigation}; #[derive(PartialEq)] pub enum InsertOptionResult { InsertedOptions, NoSuchOption, } impl<'a, TOption> Navigation where TOption: Clone + PartialEq + 'a, Element<'a, Message>: From<&'a TOption>, { pub fn insert_after_first

(&'a mut self, pred: P, new: &Vec) -> InsertOptionResult where P: Fn(&TOption) -> bool, { if let Some(index) = self.options_before_active.iter().position(&pred) { self.options_before_active .splice((index + 1)..(index + 1), new.clone()); InsertOptionResult::InsertedOptions } else if self .active_option .as_ref() .is_some_and(|active_option| pred(&active_option)) { self.options_after_active.splice(0..0, new.clone()); InsertOptionResult::InsertedOptions } else if let Some(index) = self.options_after_active.iter().position(&pred) { self.options_after_active .splice((index + 1)..(index + 1), new.clone()); InsertOptionResult::InsertedOptions } else { InsertOptionResult::NoSuchOption } } } #[cfg(test)] mod test { use itertools::Itertools; use crate::{ gui::components::{ navigation::{self, dummy_navigation_option::DummyNavigationOption}, Navigation, }, traits::Component, }; macro_rules! assert_active_option_eq { ($nav:expr, $option:expr) => { if !$nav .active_option .as_ref() .is_some_and(|o| o.name == $option) { panic!( "navigation active option should have been Some(\"{}\"), but was {:?}", $option, $nav.active_option ); } }; } macro_rules! assert_options_before_eq { ($nav:expr, $options:expr) => { let options_before_eq = $options.len() == $nav.options_before_active.len() && (|| { (0..$options.len()).all(|i| $options[i] == $nav.options_before_active[i].name) })(); if !options_before_eq { panic!( "navigation should have had options ({}) before active option, but were ({})", $options.iter().join(", "), $nav.options_before_active.iter().join(", "), ); } }; } macro_rules! assert_options_after_eq { ($nav:expr, $options:expr) => { let options_after_eq = $options.len() == $nav.options_after_active.len() && (|| { (0..$options.len()).all(|i| $options[i] == $nav.options_after_active[i].name) })(); if !options_after_eq { panic!( "navigation should have had options ({}) after active option, but were ({})", $options.iter().join(", "), $nav.options_after_active.iter().join(", "), ); } }; } fn make_dummy_nav_with_options_a_to_g() -> Navigation { Navigation::new( None, vec![ DummyNavigationOption::new("a"), DummyNavigationOption::new("b"), DummyNavigationOption::new("c"), DummyNavigationOption::new("d"), DummyNavigationOption::new("e"), DummyNavigationOption::new("f"), DummyNavigationOption::new("g"), ], ) } fn select_dummy_nav_option(nav: &mut Navigation, option: &str) { nav.update(navigation::Message::SelectOption( DummyNavigationOption::new(option), )); } #[test] fn insert_after_first_option_before_active_with_one() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, ["a", "z", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_first_option_before_active_with_many() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, ["a", "x", "y", "z", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_last_option_before_active_with_one() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "c", &new); assert_options_before_eq!(nav, ["a", "b", "c", "z"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_last_option_before_active_with_many() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "c", &new); assert_options_before_eq!(nav, ["a", "b", "c", "x", "y", "z"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_active_option_with_one() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "d", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["z", "e", "f", "g"]); } #[test] fn insert_after_active_option_with_one_when_active_option_is_first() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "a"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, [] as [String; 0]); assert_active_option_eq!(nav, "a"); assert_options_after_eq!(nav, ["z", "b", "c", "d", "e", "f", "g"]); } #[test] fn insert_after_active_option_with_one_when_active_option_is_last() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "g"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "g", &new); assert_options_before_eq!(nav, ["a", "b", "c", "d", "e", "f",]); assert_active_option_eq!(nav, "g"); assert_options_after_eq!(nav, ["z"]); } #[test] fn insert_after_active_option_with_one_when_active_option_is_only() { let active_option = DummyNavigationOption::new("a"); let mut nav = Navigation::new(Some(active_option.clone()), vec![active_option]); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, [] as [String; 0]); assert_active_option_eq!(nav, "a"); assert_options_after_eq!(nav, ["z"]); } #[test] fn insert_after_active_option_with_many() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "d", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["x", "y", "z", "e", "f", "g"]); } #[test] fn insert_after_active_option_with_many_when_active_option_is_first() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "a"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, [] as [String; 0]); assert_active_option_eq!(nav, "a"); assert_options_after_eq!(nav, ["x", "y", "z", "b", "c", "d", "e", "f", "g"]); } #[test] fn insert_after_active_option_with_many_when_active_option_is_last() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "g"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "g", &new); assert_options_before_eq!(nav, ["a", "b", "c", "d", "e", "f"]); assert_active_option_eq!(nav, "g"); assert_options_after_eq!(nav, ["x", "y", "z"]); } #[test] fn insert_after_active_option_with_many_when_active_option_is_only() { let active_option = DummyNavigationOption::new("a"); let mut nav = Navigation::new(Some(active_option.clone()), vec![active_option]); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, [] as [String; 0]); assert_active_option_eq!(nav, "a"); assert_options_after_eq!(nav, ["x", "y", "z"]); } #[test] fn insert_after_first_option_after_active_with_one() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "e", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "z", "f", "g"]); } #[test] fn insert_after_first_option_after_active_with_many() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "e", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "x", "y", "z", "f", "g"]); } #[test] fn insert_after_last_option_after_active_with_one() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "g", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g", "z"]); } #[test] fn insert_after_last_option_after_active_with_many() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); let new = vec![ DummyNavigationOption::new("x"), DummyNavigationOption::new("y"), DummyNavigationOption::new("z"), ]; nav.insert_after_first(|o| o.name == "g", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g", "x", "y", "z"]); } #[test] fn insert_after_first_option_before_active_when_duplicates() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); nav.insert_after_first(|o| o.name == "c", &vec![DummyNavigationOption::new("a")]); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, ["a", "z", "b", "c", "a"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_first_option_before_active_when_duplicate_in_active_option() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); nav.insert_after_first(|o| o.name == "a", &vec![DummyNavigationOption::new("d")]); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "d", &new); assert_options_before_eq!(nav, ["a", "d", "z", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "g"]); } #[test] fn insert_after_first_option_before_active_when_duplicate_in_options_after_active() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); nav.insert_after_first(|o| o.name == "f", &vec![DummyNavigationOption::new("a")]); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "a", &new); assert_options_before_eq!(nav, ["a", "z", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["e", "f", "a", "g"]); } #[test] fn insert_after_active_option_when_duplicate_in_options_after_active() { let mut nav = make_dummy_nav_with_options_a_to_g(); select_dummy_nav_option(&mut nav, "d"); nav.insert_after_first(|o| o.name == "f", &vec![DummyNavigationOption::new("d")]); let new = vec![DummyNavigationOption::new("z")]; nav.insert_after_first(|o| o.name == "d", &new); assert_options_before_eq!(nav, ["a", "b", "c"]); assert_active_option_eq!(nav, "d"); assert_options_after_eq!(nav, ["z", "e", "f", "d", "g"]); } }