use crate::syntax::map::{Entry, UnorderedMap as Map}; use crate::syntax::report::Errors; use crate::syntax::{Api, Struct, Type, Types}; enum Mark { Visiting, Visited, } pub fn sort<'a>(cx: &mut Errors, apis: &'a [Api], types: &Types<'a>) -> Vec<&'a Struct> { let mut sorted = Vec::new(); let ref mut marks = Map::new(); for api in apis { if let Api::Struct(strct) = api { let _ = visit(cx, strct, &mut sorted, marks, types); } } sorted } fn visit<'a>( cx: &mut Errors, strct: &'a Struct, sorted: &mut Vec<&'a Struct>, marks: &mut Map<*const Struct, Mark>, types: &Types<'a>, ) -> Result<(), ()> { match marks.entry(strct) { Entry::Occupied(entry) => match entry.get() { Mark::Visiting => return Err(()), // not a DAG Mark::Visited => return Ok(()), }, Entry::Vacant(entry) => { entry.insert(Mark::Visiting); } } let mut result = Ok(()); for field in &strct.fields { if let Type::Ident(ident) = &field.ty { if let Some(inner) = types.structs.get(&ident.rust) { if visit(cx, inner, sorted, marks, types).is_err() { cx.error(field, "unsupported cyclic data structure"); result = Err(()); } } } } marks.insert(strct, Mark::Visited); sorted.push(strct); result }