myd/
lib.rs

1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3#![deny(clippy::missing_docs_in_private_items)]
4
5use std::collections::{HashMap, HashSet};
6
7pub use cargo_metadata::CargoOpt;
8use ego_tree::NodeId;
9use syn::Item;
10
11mod module;
12pub mod parse;
13pub mod platforms;
14pub use module::Module;
15mod module_information;
16pub use module_information::ModuleInformation;
17mod syn_helpers;
18
19/// A list of [`syn::Item`]s
20pub type Items = Vec<Item>;
21/// A map of depends to their features
22type Features = HashMap<String, HashSet<String>>;
23
24/// A representation of an import
25#[derive(Debug)]
26struct Import {
27    /// The path to the item of which this points
28    pub item: syn::Path,
29    /// The strength of the import
30    pub strength: ImportStrength,
31    /// The alias
32    ///
33    /// For example in the case of `use std::vec::Vec as List` this would be `List`
34    pub az: Option<syn::Ident>,
35}
36
37impl Import {
38    /// Returns the identifier of this Import
39    ///
40    /// This will be the `az` if present, elsewise the last
41    /// identifier in the path.
42    pub fn ident(&self) -> &syn::Ident {
43        match &self.az {
44            Some(az) => az,
45            None => &self.item.segments.last().unwrap().ident,
46        }
47    }
48}
49
50impl Import {
51    /// Creates a new Import
52    pub fn new(item: syn::Path, strength: ImportStrength, az: Option<syn::Ident>) -> Self {
53        Self { item, strength, az }
54    }
55}
56
57/// Represents the 'strength' of an import.
58///
59/// This is used by the program to determine whether an import
60/// is imported via a glob or not; if it is imported via a glob
61/// then it can be safely overriden by another import that is not from a glob.
62///
63/// However, if two imports of the same strength are present then that is an error.
64#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
65enum ImportStrength {
66    /// Strong - the user explicitely imported this
67    Strong,
68    /// Weak - this was resolved through a glob
69    Weak,
70}
71
72/// A reference to an item on the tree.
73///
74/// Only useful with [`ModuleInformation`]
75#[derive(Debug, PartialEq, Eq, Clone, Copy)]
76pub struct ItemId {
77    /// The Node that this points to
78    node: NodeId,
79    /// The position in the list of the module for the item
80    item_id: usize,
81}
82
83impl ItemId {
84    /// Gets the ID of the module this
85    /// item is under.
86    pub fn module_id(&self) -> NodeId {
87        self.node
88    }
89}
90
91/// A reference either fo a module or an item on the tree
92#[derive(Debug, PartialEq, Eq, Clone, Copy)]
93pub enum ModuleOrItem {
94    /// A module
95    ///
96    /// Can be accessed through the `tree` field on [`ModuleInformation`]
97    Module(NodeId),
98    /// An item, can be accessed by [`ModuleInformation::get`]
99    Item(ItemId),
100}
101
102impl ModuleOrItem {
103    /// Unwraps a module in this
104    ///
105    /// # Panics
106    ///
107    /// Panics if this is not a module
108    pub fn unwrap_module(self) -> NodeId {
109        match self {
110            ModuleOrItem::Module(x) => x,
111            ModuleOrItem::Item(_) => panic!(
112                "Tried to unwrap a Module from a ModuleOrItem::Item: {:?}",
113                self
114            ),
115        }
116    }
117
118    /// Unwraps a item in this
119    ///
120    /// # Panics
121    ///
122    /// Panics if this is not a item
123    pub fn unwrap_item(self) -> ItemId {
124        match self {
125            ModuleOrItem::Item(x) => x,
126            ModuleOrItem::Module(_) => panic!(
127                "Tried to unwrap an Item from a ModuleOrItem::Module: {:?}",
128                self
129            ),
130        }
131    }
132}
133
134impl From<ItemId> for ModuleOrItem {
135    fn from(them: ItemId) -> Self {
136        Self::Item(them)
137    }
138}
139impl From<NodeId> for ModuleOrItem {
140    fn from(them: NodeId) -> Self {
141        Self::Module(them)
142    }
143}
144
145/// An error occuring when resolving a path
146/// with [`ModuleInformation::path`]
147#[derive(thiserror::Error, Debug)]
148pub enum ResolveError {
149    /// The item the path points to does not exist,
150    ///
151    /// ie `std::collections::Bashmap`
152    #[error("path not found")]
153    NotFound,
154    /// AN item is prematurely reached in the path
155    ///
156    /// ie `std::collections::HashMap::mything`
157    // TODO: This should not be an error
158    #[error("premature non module item")]
159    PrematureItem,
160    /// An item is found at the root
161    ///
162    /// ie `::Item` being a struct not a module
163    #[error("items should not exist from the root in rust.")]
164    RootItem,
165    /// Conflicting imports
166    ///
167    /// ie:
168    ///
169    /// ```rust
170    /// use a::*;
171    /// use b::*;
172    ///
173    /// mod a {
174    ///     pub struct Foo;
175    /// }
176    ///
177    /// mod b {
178    ///     pub struct Foo;
179    /// }
180    ///
181    /// // Could refer to `a::Foo` or `b::Foo`
182    /// Foo
183    /// ```
184    #[error("conflicting imports")]
185    Conflicting,
186    /// When the supers go out of the crate
187    ///
188    /// ie `std::super::super`
189    #[error("too many supers!")]
190    TooManySupers,
191}