sphinx_rustdocgen/
utils.rs

1// sphinxcontrib_rust - Sphinx extension for the Rust programming language
2// Copyright (C) 2024  Munir Contractor
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Module for various utility classes and structs.
18
19use std::fs::read_to_string;
20use std::path::{Path, PathBuf};
21
22use cargo_toml::{Manifest, Product};
23
24/// Check the provided paths for the Cargo.toml file.
25///
26/// Returns:
27///     A Some value of the path that contained the Cargo manifest and the
28///     associated manifest for the first path contains a ``Cargo.toml`` file.
29pub(crate) fn check_for_manifest(paths: Vec<&Path>) -> Option<(PathBuf, CargoManifest)> {
30    for path in paths {
31        let manifest_path = path.join("Cargo.toml");
32        if manifest_path.is_file() {
33            return Some((
34                path.into(),
35                CargoManifest(Manifest::from_path(manifest_path).unwrap()),
36            ));
37        }
38    }
39    None
40}
41
42/// Struct for the source code files encountered when scanning the crate.
43#[derive(Clone, Debug)]
44pub(crate) struct SourceCodeFile {
45    /// The path to the file.
46    pub(crate) path: PathBuf,
47    /// The name of the item in the file.
48    pub(crate) item: String,
49}
50
51impl SourceCodeFile {
52    /// Generate and return the AST for the file.
53    pub(crate) fn ast(&self) -> syn::File {
54        syn::parse_file(&read_to_string(&self.path).unwrap()).unwrap()
55    }
56
57    /// Get the parent directory of the file for the item.
58    ///
59    /// The item of the returned struct is the same as this struct's item.
60    /// This is mainly used for ``mod.rs`` and ``lib.rs`` files, where the
61    /// directory name determines the item's name.
62    pub(crate) fn to_parent_directory(&self) -> Self {
63        SourceCodeFile {
64            path: self.path.parent().as_ref().unwrap().into(),
65            item: self.item.clone(),
66        }
67    }
68
69    /// Create an instance for the product in the crate.
70    ///
71    /// Args:
72    ///     :prd: The product for which the file should be created.
73    ///     :crate_dir: The path for the crate's directory, used to
74    ///         generate the absolute path for the file.
75    fn from_product(prd: &Product, crate_dir: &Path) -> Self {
76        SourceCodeFile {
77            path: crate_dir.join(prd.path.as_ref().unwrap()),
78            item: prd.name.as_ref().unwrap().clone(),
79        }
80    }
81
82    /// Returns the name of the crate from the item name.
83    pub(crate) fn crate_name(&self) -> &str {
84        &self.item[0..self.item.find("::").unwrap_or(self.item.len())]
85    }
86}
87
88/// Newtype struct for the Cargo manifest from cargo_toml.
89pub(crate) struct CargoManifest(Manifest);
90
91impl CargoManifest {
92    /// Get the library file for the crate, if any.
93    pub(crate) fn lib_file(&self, crate_dir: &Path) -> Option<SourceCodeFile> {
94        self.0
95            .lib
96            .as_ref()
97            .map(|lib| SourceCodeFile::from_product(lib, crate_dir))
98    }
99
100    /// Get all the executable files in the crate.
101    pub(crate) fn executable_files(&self, crate_dir: &Path) -> Vec<SourceCodeFile> {
102        self.0
103            .bin
104            .iter()
105            .map(|prd| SourceCodeFile::from_product(prd, crate_dir))
106            .collect()
107    }
108}