1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, Component};

use syn::{parse_crate, self};
use walkdir::{DirEntry, WalkDir};

/// Loads a file into a crate.
pub fn load_file(path: &Path) -> io::Result<syn::Crate> {
    let mut buf = String::new();
    File::open(path)?.read_to_string(&mut buf)?;
    parse_crate(&buf).map_err(|_| {
        io::Error::new(io::ErrorKind::InvalidData,
                       format!("{} had a Rust syntax error", path.display()))
    })
}

/// Loads the files for an src directory to a crate.
pub fn load_src_files(path: &Path)
    -> impl Iterator<Item=io::Result<(Vec<syn::Ident>, syn::Crate)>>
{
    WalkDir::new(path)
        .follow_links(true)
        .max_depth(10)
        .into_iter()
        .filter_map(|de| match de {
            Err(err) => Some(Err(io::Error::new(io::ErrorKind::Other, err))),
            Ok(ok) => {
                let loaded = {
                    let path = ok.path();
                    if let Some(ext) = path.extension() {
                        if ext == "rs" {
                            match load_file(path) {
                                Ok(ok) => ok,
                                Err(e) => return Some(Err(e)),
                            }
                        } else {
                            return None;
                        }
                    } else {
                        return None;
                    }
                };
                Some(Ok((make_path(&ok), loaded)))
            },
        })
}

/// Converts a `DirEntry` into the path to a module.
fn make_path(entry: &DirEntry) -> Vec<syn::Ident> {
    let mut v = entry.path().components().rev().take(entry.depth()).filter_map(|comp| match comp {
        Component::Normal(comp) => {
            let other = comp.to_string_lossy().into_owned();
            match &*other {
                "lib.rs" | "mod.rs" => None,
                other => Some(syn::Ident::from(other)),
            }
        },
        _ => None,
    }).collect::<Vec<_>>();
    v.reverse();
    v
}