1use std::fs;
13use std::path::Path;
14
15use anyhow::{Context, Result};
16use syn::{Data, DataEnum, DataStruct, DataUnion, DeriveInput, Item};
17
18pub fn parse_mod<P>(path: P) -> Result<Vec<DeriveInput>>
24where
25 P: AsRef<Path>,
26{
27 let mut out = vec![];
28 collect_items(path, &mut out)?;
29 Ok(out)
30}
31
32fn collect_items<P>(path: P, out: &mut Vec<DeriveInput>) -> Result<()>
33where
34 P: AsRef<Path>,
35{
36 let path = path.as_ref();
37 let dir = path.parent().expect("missing parent directory");
38 let stem = path
39 .file_stem()
40 .expect("missing file stem")
41 .to_str()
42 .expect("file stem is not valid UTF-8");
43
44 let src =
45 fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?;
46 let file = syn::parse_file(&src)?;
47
48 for item in file.items {
49 match item {
50 Item::Mod(item) if item.content.is_none() => {
51 let path = match stem {
52 "mod" | "lib" => dir.join(format!("{}.rs", item.ident)),
53 _ => dir.join(format!("{}/{}.rs", stem, item.ident)),
54 };
55 collect_items(path, out)?;
56 }
57 Item::Struct(item) => {
58 out.push(DeriveInput {
59 ident: item.ident,
60 vis: item.vis,
61 attrs: item.attrs,
62 generics: item.generics,
63 data: Data::Struct(DataStruct {
64 fields: item.fields,
65 struct_token: item.struct_token,
66 semi_token: item.semi_token,
67 }),
68 });
69 }
70 Item::Enum(item) => {
71 out.push(DeriveInput {
72 ident: item.ident,
73 vis: item.vis,
74 attrs: item.attrs,
75 generics: item.generics,
76 data: Data::Enum(DataEnum {
77 enum_token: item.enum_token,
78 brace_token: item.brace_token,
79 variants: item.variants,
80 }),
81 });
82 }
83 Item::Union(item) => {
84 out.push(DeriveInput {
85 ident: item.ident,
86 vis: item.vis,
87 attrs: item.attrs,
88 generics: item.generics,
89 data: Data::Union(DataUnion {
90 union_token: item.union_token,
91 fields: item.fields,
92 }),
93 });
94 }
95 _ => (),
96 }
97 }
98 Ok(())
99}