133d722a9Sopenharmony_ciuse crate::syntax::map::{Entry, UnorderedMap as Map};
233d722a9Sopenharmony_ciuse crate::syntax::report::Errors;
333d722a9Sopenharmony_ciuse crate::syntax::{Api, Struct, Type, Types};
433d722a9Sopenharmony_ci
533d722a9Sopenharmony_cienum Mark {
633d722a9Sopenharmony_ci    Visiting,
733d722a9Sopenharmony_ci    Visited,
833d722a9Sopenharmony_ci}
933d722a9Sopenharmony_ci
1033d722a9Sopenharmony_cipub fn sort<'a>(cx: &mut Errors, apis: &'a [Api], types: &Types<'a>) -> Vec<&'a Struct> {
1133d722a9Sopenharmony_ci    let mut sorted = Vec::new();
1233d722a9Sopenharmony_ci    let ref mut marks = Map::new();
1333d722a9Sopenharmony_ci    for api in apis {
1433d722a9Sopenharmony_ci        if let Api::Struct(strct) = api {
1533d722a9Sopenharmony_ci            let _ = visit(cx, strct, &mut sorted, marks, types);
1633d722a9Sopenharmony_ci        }
1733d722a9Sopenharmony_ci    }
1833d722a9Sopenharmony_ci    sorted
1933d722a9Sopenharmony_ci}
2033d722a9Sopenharmony_ci
2133d722a9Sopenharmony_cifn visit<'a>(
2233d722a9Sopenharmony_ci    cx: &mut Errors,
2333d722a9Sopenharmony_ci    strct: &'a Struct,
2433d722a9Sopenharmony_ci    sorted: &mut Vec<&'a Struct>,
2533d722a9Sopenharmony_ci    marks: &mut Map<*const Struct, Mark>,
2633d722a9Sopenharmony_ci    types: &Types<'a>,
2733d722a9Sopenharmony_ci) -> Result<(), ()> {
2833d722a9Sopenharmony_ci    match marks.entry(strct) {
2933d722a9Sopenharmony_ci        Entry::Occupied(entry) => match entry.get() {
3033d722a9Sopenharmony_ci            Mark::Visiting => return Err(()), // not a DAG
3133d722a9Sopenharmony_ci            Mark::Visited => return Ok(()),
3233d722a9Sopenharmony_ci        },
3333d722a9Sopenharmony_ci        Entry::Vacant(entry) => {
3433d722a9Sopenharmony_ci            entry.insert(Mark::Visiting);
3533d722a9Sopenharmony_ci        }
3633d722a9Sopenharmony_ci    }
3733d722a9Sopenharmony_ci    let mut result = Ok(());
3833d722a9Sopenharmony_ci    for field in &strct.fields {
3933d722a9Sopenharmony_ci        if let Type::Ident(ident) = &field.ty {
4033d722a9Sopenharmony_ci            if let Some(inner) = types.structs.get(&ident.rust) {
4133d722a9Sopenharmony_ci                if visit(cx, inner, sorted, marks, types).is_err() {
4233d722a9Sopenharmony_ci                    cx.error(field, "unsupported cyclic data structure");
4333d722a9Sopenharmony_ci                    result = Err(());
4433d722a9Sopenharmony_ci                }
4533d722a9Sopenharmony_ci            }
4633d722a9Sopenharmony_ci        }
4733d722a9Sopenharmony_ci    }
4833d722a9Sopenharmony_ci    marks.insert(strct, Mark::Visited);
4933d722a9Sopenharmony_ci    sorted.push(strct);
5033d722a9Sopenharmony_ci    result
5133d722a9Sopenharmony_ci}
52