use std::collections::{BTreeMap, BTreeSet};
#[must_use]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
pub fn is_power_of_two(value: i64) -> Option<u8> {
if value <= 0 {
return None;
}
let value = value as u64;
if value.is_power_of_two() {
Some(value.trailing_zeros() as u8)
} else {
None
}
}
#[must_use]
pub fn resolve_chain<K>(map: &BTreeMap<K, K>, start: K) -> K
where
K: Copy + Ord,
{
let mut current = start;
let mut visited = BTreeSet::new();
while let Some(&next) = map.get(¤t) {
if !visited.insert(current) {
break;
}
current = next;
}
current
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn follows_mappings() {
let mut map = BTreeMap::new();
map.insert(1, 2);
map.insert(2, 3);
map.insert(3, 4);
assert_eq!(resolve_chain(&map, 1), 4);
assert_eq!(resolve_chain(&map, 2), 4);
assert_eq!(resolve_chain(&map, 3), 4);
assert_eq!(resolve_chain(&map, 4), 4);
}
#[test]
fn handles_cycles() {
let mut map = BTreeMap::new();
map.insert(1, 2);
map.insert(2, 1);
let result = resolve_chain(&map, 1);
assert!(result == 1 || result == 2);
}
#[test]
fn single_step() {
let mut map = BTreeMap::new();
map.insert(5, 10);
assert_eq!(resolve_chain(&map, 5), 10);
}
#[test]
fn empty_map() {
let map: BTreeMap<usize, usize> = BTreeMap::new();
assert_eq!(resolve_chain(&map, 42), 42);
}
#[test]
fn self_loop() {
let mut map = BTreeMap::new();
map.insert(1, 1);
assert_eq!(resolve_chain(&map, 1), 1);
}
}