willbe/entity/
workspace.rs

1#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ]
2mod private
3{
4
5  use crate::*;
6  // qqq : for Bohdan : bad
7  // use std::*;
8  use std::slice;
9  use former::Former;
10
11  /// Stores information about the current workspace.
12  #[ derive( Debug, Clone ) ]
13  pub struct Workspace
14  {
15    /// Metadata of the workspace, containing detailed information about the packages, dependencies, and other workspace-related data.
16    pub metadata : cargo_metadata::Metadata,
17    /// The directory containing the manifest file (`Cargo.toml`) of the workspace.
18    pub crate_dir : CrateDir,
19  }
20
21  /// Represents errors related to workspace operations.
22  #[ derive( Debug, error::typed::Error ) ]
23  pub enum WorkspaceInitError
24  {
25    /// Something went wrong with path to a workspace.
26    #[ error( "Path error. Details: {0}" ) ]
27    Path( #[ from ] PathError ),
28    /// Something went wrong with the workspace' data
29    #[ error( "Can not load workspace data. Details: {0}" ) ]
30    Metadata( #[ from ] cargo_metadata::Error ),
31    /// Files error
32    #[ error( "I/O error: {0}" ) ]
33    IO( #[ from ] std::io::Error ),
34  }
35
36  impl TryFrom< CrateDir > for Workspace
37  {
38    type Error = WorkspaceInitError;
39
40    /// Load data from current directory
41    fn try_from( mut crate_dir : CrateDir ) -> Result< Self, Self::Error >
42    {
43      let metadata = cargo_metadata::MetadataCommand::new()
44      .current_dir( crate_dir.as_ref() )
45      .no_deps()
46      .exec()?;
47      // inout crate dir may refer on crate's manifest dir, not workspace's manifest dir
48      crate_dir = ( &metadata.workspace_root ).try_into()?;
49      Result::Ok( Self
50      {
51        metadata,
52        crate_dir,
53      })
54    }
55
56  }
57
58  impl TryFrom< CurrentPath > for Workspace
59  {
60    type Error = WorkspaceInitError;
61
62    /// Load data from current directory
63    fn try_from( _cd : CurrentPath ) -> Result< Self, Self::Error >
64    {
65      let abs_path = AbsolutePath::try_from( std::env::current_dir()? )?;
66      let crate_dir = CrateDir::try_from( abs_path )?;
67      Self::try_from( crate_dir )
68    }
69
70  }
71
72  impl From< cargo_metadata::Metadata > for Workspace
73  {
74    fn from( metadata : cargo_metadata::Metadata ) -> Self
75    {
76      // SAFE: `workspace_root` is a path to a`Cargo.toml` file, therefor the parent is the directory
77      let path = metadata.workspace_root.as_std_path().parent().unwrap().to_path_buf();
78      let crate_dir = CrateDir::try_from( path ).unwrap();
79      Self
80      {
81        metadata,
82        crate_dir,
83      }
84    }
85  }
86
87  impl Workspace
88  {
89
90    /// Returns list of all packages
91    pub fn packages< 'a >( &'a self )
92    -> core::iter::Map
93    <
94      slice::Iter< 'a, cargo_metadata::Package >,
95      impl Fn( &'a cargo_metadata::Package ) -> WorkspacePackageRef< 'a > + Clone,
96    >
97    {
98      self.metadata.packages.iter().map( WorkspacePackageRef::from )
99    }
100
101    /// Returns the path to workspace root
102    ///
103    /// # Panics
104    /// qqq: doc
105    #[ must_use ]
106    pub fn workspace_root( &self ) -> CrateDir
107    {
108      // Safe because workspace_root.as_std_path() is always a path to a directory
109      CrateDir::try_from( self.metadata.workspace_root.as_std_path() ).unwrap()
110    }
111
112    /// Returns the path to target directory
113    #[ must_use ]
114    pub fn target_directory( &self ) -> &std::path::Path
115    {
116      self.metadata.target_directory.as_std_path()
117    }
118
119    /// Find a package by its manifest file path
120    ///
121    /// # Panics
122    /// qqq: doc
123    pub fn package_find_by_manifest< P >( &self, manifest_file : P ) -> Option< WorkspacePackageRef< '_ > >
124    where
125      P : AsRef< std::path::Path >,
126    {
127      self
128      .packages()
129      .find( | &p | p.manifest_file().unwrap().as_ref() == manifest_file.as_ref() )
130    }
131
132    /// Filter of packages.
133    #[ must_use ]
134    pub fn packages_which( &self ) -> PackagesFilterFormer< '_ >
135    {
136      // PackagesFilter::new( self )
137      PackagesFilter::former().workspace( self )
138    }
139
140  }
141
142
143  #[ derive( Former ) ]
144  // #[ debug ]
145  #[ allow( missing_debug_implementations ) ]
146  pub struct PackagesFilter< 'a >
147  {
148    workspace : &'a Workspace,
149    crate_dir : Box< dyn PackageFilter >,
150    manifest_file : Box< dyn PackageFilter >,
151  }
152
153  pub trait PackageFilter
154  {
155    fn include( &self, package : WorkspacePackageRef< '_ > ) -> bool;
156  }
157
158  impl Default for Box< dyn PackageFilter >
159  {
160    fn default() -> Self
161    {
162      Box::new( PackageFilterAll )
163    }
164  }
165
166  pub struct PackageFilterAll;
167  impl PackageFilter for PackageFilterAll
168  {
169    #[ inline( always ) ]
170    fn include( &self, _package : WorkspacePackageRef< '_ > ) -> bool
171    {
172      true
173    }
174  }
175
176  pub struct PackageFilterCrateDir( CrateDir );
177  impl PackageFilter for PackageFilterCrateDir
178  {
179    #[ inline( always ) ]
180    fn include( &self, package : WorkspacePackageRef< '_ > ) -> bool
181    {
182      self.0 == package.crate_dir().unwrap()
183    }
184  }
185
186  impl From< CrateDir > for Box< dyn PackageFilter >
187  {
188    #[ inline( always ) ]
189    fn from( src : CrateDir ) -> Self
190    {
191      Box::new( PackageFilterCrateDir( src ) )
192    }
193  }
194
195  pub struct PackageFilterManifestFile( ManifestFile );
196  impl PackageFilter for PackageFilterManifestFile
197  {
198    #[ inline( always ) ]
199    fn include( &self, package : WorkspacePackageRef< '_ > ) -> bool
200    {
201      self.0 == package.manifest_file().unwrap()
202    }
203  }
204
205  impl From< ManifestFile > for Box< dyn PackageFilter >
206  {
207    #[ inline( always ) ]
208    fn from( src : ManifestFile ) -> Self
209    {
210      Box::new( PackageFilterManifestFile( src ) )
211    }
212  }
213
214  impl< 'a > PackagesFilter< 'a >
215  {
216
217    pub fn new( workspace : &'a Workspace ) -> Self
218    {
219      Self
220      {
221        workspace,
222        crate_dir : Box::default(),
223        manifest_file : Box::default(),
224      }
225    }
226
227    #[ inline( always ) ]
228    #[ allow( clippy::unused_self ) ]
229    pub fn iter( &'a self ) -> impl Iterator< Item = WorkspacePackageRef< 'a > > + Clone
230    {
231
232      // self
233      // .workspace
234      // .packages()
235      // .find( | &p | p.manifest_file().unwrap().as_ref() == manifest_file.as_ref() )
236
237      // let filter_crate_dir = if Some( crate_dir ) = self.crate_dir
238      // {
239      //   | p | p.manifest_file().unwrap().as_ref() == manifest_file.as_ref()
240      // }
241
242      std::iter::empty()
243    }
244
245  }
246
247  impl< 'a > PackagesFilterFormer< 'a >
248  {
249    #[ inline( always ) ]
250    // pub fn find< 'a >( self ) -> impl Iterator< Item = WorkspacePackageRef< 'a > > + Clone
251    pub fn find( self ) -> Option< WorkspacePackageRef< 'a > >
252    {
253      let formed = self.form();
254
255      formed
256      .workspace
257      .packages()
258      .find( | &p |
259      {
260        if !formed.crate_dir.include( p ) { return false }
261        if !formed.manifest_file.include( p ) { return false }
262        true
263      })
264      // .unwrap()
265
266      // let filter_crate_dir = if Some( crate_dir ) = self.crate_dir
267      // {
268      //   | p | p.manifest_file().unwrap().as_ref() == manifest_file.as_ref()
269      // }
270
271      // std::iter::empty()
272    }
273  }
274
275  impl Entries for Workspace
276  {
277    fn entries( &self ) -> impl IterTrait< '_, SourceFile >
278    {
279      self
280      .packages()
281      .flat_map( | package | package.entries().collect::< Vec< _ > >() )
282      .collect::< Vec< _ > >()
283      .into_iter()
284    }
285  }
286
287  impl Sources for Workspace
288  {
289    fn sources( &self ) -> impl IterTrait< '_, SourceFile >
290    {
291      self
292      .packages()
293      .flat_map( | package | package.sources().collect::< Vec< _ > >() )
294      .collect::< Vec< _ > >().into_iter()
295      // .into_iter()
296    }
297  }
298
299}
300
301//
302
303crate::mod_interface!
304{
305  exposed use WorkspaceInitError;
306  exposed use Workspace;
307}