crate::ix!();
#[derive(Builder,MutGetters,Getters,Debug)]
#[getset(get="pub",get_mut="pub")]
#[builder(setter(into))]
pub struct Workspace<P,H:CrateHandleInterface<P>>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
path: P,
crates: Vec<Arc<AsyncMutex<H>>>,
}
impl<P,H:CrateHandleInterface<P>> WorkspaceInterface<P,H> for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Clone + Send + Sync + 'async_trait
{ }
impl<P,H:CrateHandleInterface<P>> AsRef<Path> for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
fn as_ref(&self) -> &Path {
self.path.as_ref()
}
}
impl<P,H:CrateHandleInterface<P>> GetCrates<P,H> for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
fn crates(&self) -> &[Arc<AsyncMutex<H>>] {
&self.crates
}
}
impl<P,H:CrateHandleInterface<P>> GetCratesMut<P,H> for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
fn crates_mut(&mut self) -> &mut Vec<Arc<AsyncMutex<H>>> {
&mut self.crates
}
}
#[async_trait]
impl<P,H:CrateHandleInterface<P>> FindCrateByName<P,H> for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
async fn find_crate_by_name(&self, name: &str) -> Option<Arc<AsyncMutex<H>>> {
for item in self.crates() {
let crate_guard = item.lock().await;
if crate_guard.name() == name {
return Some(item.clone());
}
}
None
}
}
#[async_trait]
impl<P,H:CrateHandleInterface<P>> GetAllCrateNames for Workspace<P,H>
where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
{
async fn get_all_crate_names(&self) -> Vec<String> {
let mut names = Vec::new();
for item in self.crates() {
let crate_guard = item.lock().await;
names.push(crate_guard.name().to_string());
}
names
}
}
#[async_trait]
impl<P,H:CrateHandleInterface<P>> AsyncTryFrom<P> for Workspace<P,H>
where
for<'async_trait> P: From<PathBuf> + AsRef<Path> + Clone + Send + Sync + 'async_trait,
{
type Error = WorkspaceError;
async fn new(path: &P) -> Result<Self, Self::Error> {
let path_buf = path.as_ref().to_path_buf();
let cargo_toml = path_buf.join("Cargo.toml");
if !cargo_toml.exists() {
return Err(WorkspaceError::InvalidWorkspace {
invalid_workspace_path: path_buf,
});
}
let cargo_toml_str = tokio::fs::read_to_string(&cargo_toml).await.map_err(|e| {
WorkspaceError::IoError {
io_error: e.into(),
context: format!("Failed to read {:?}", cargo_toml),
}
})?;
let parsed: toml::Value = toml::from_str(&cargo_toml_str).map_err(|_e| {
WorkspaceError::InvalidWorkspace {
invalid_workspace_path: path_buf.clone(),
}
})?;
let is_workspace = parsed
.as_table()
.map_or(false, |tbl| tbl.contains_key("workspace"));
if !is_workspace {
return Err(WorkspaceError::ActuallyInSingleCrate {
path: path_buf,
});
}
if !Self::is_valid(&path_buf).await {
return Err(WorkspaceError::InvalidWorkspace {
invalid_workspace_path: path_buf,
});
}
let crates = Self::find_items(&path_buf).await?;
Ok(Self { path: path.clone(), crates })
}
}