fn check_no_cycles()

in shed/facet/proc_macros/factory_impl.rs [630:669]


fn check_no_cycles(
    top_ident: &Ident,
    ident_map: &BTreeMap<&Ident, &Vec<FactoryParam>>,
) -> Result<(), Error> {
    // A map from seen idents to a vector of the route to them from top_ident.
    let mut seen = BTreeMap::new();
    // A queue of idents to expand and the routes to them so far.
    let mut queue = VecDeque::new();
    queue.push_back((top_ident, vec![]));
    while let Some((ident, route)) = queue.pop_front() {
        if let Some(params) = ident_map.get(&ident) {
            for param in *params {
                if let FactoryParam::Facet(param_ident) = param {
                    seen.entry(param_ident).or_insert_with(|| {
                        let mut param_route = route.clone();
                        param_route.push(param_ident);
                        queue.push_back((param_ident, param_route));
                        route.clone()
                    });
                }
            }
        }
    }
    if let Some(route) = seen.get(&top_ident) {
        let via = if route.is_empty() {
            String::from("directly")
        } else {
            let route = route.iter().map(ToString::to_string).collect::<Vec<_>>();
            format!("via {}", route.join(" -> "))
        };
        return Err(Error::new(
            top_ident.span(),
            format!(
                "cyclic facet dependency: {} depends on itself {}",
                top_ident, via
            ),
        ));
    }
    Ok(())
}