use crate::identifier::TaskId;
use crate::project::ProjectResult;
use crate::project::Project;
use std::collections::HashSet;
use std::fmt::{Debug, Formatter};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
pub trait IntoBuildable {
type Buildable: Buildable;
fn into_buildable(self) -> Self::Buildable;
}
pub trait GetBuildable {
fn as_buildable(&self) -> BuildableObject;
}
assert_obj_safe!(GetBuildable);
impl<B: IntoBuildable + Clone> GetBuildable for B
where
<B as IntoBuildable>::Buildable: 'static,
{
fn as_buildable(&self) -> BuildableObject {
BuildableObject::new(self.clone().into_buildable())
}
}
impl<B: Buildable> IntoBuildable for B {
type Buildable = B;
fn into_buildable(self) -> B {
self
}
}
pub trait Buildable: Send + Sync + Debug {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>>;
}
assert_obj_safe!(Buildable);
impl<B: Buildable> Buildable for &B {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
(*self).get_dependencies(project)
}
}
impl Buildable for Box<dyn Buildable + '_> {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
self.as_ref().get_dependencies(project)
}
}
impl Buildable for Arc<dyn Buildable + '_> {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
self.as_ref().get_dependencies(project)
}
}
impl<B: Buildable> Buildable for Vec<B> {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
self.iter()
.map(|b| b.get_dependencies(project))
.collect::<Result<Vec<HashSet<_>>, _>>()
.map(|v| v.into_iter().flatten().collect())
}
}
#[derive(Default, Clone)]
pub struct BuiltByContainer(Vec<Arc<dyn Buildable>>);
impl BuiltByContainer {
pub const fn new() -> Self {
Self(Vec::new())
}
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
pub fn with_buildable<B: IntoBuildable>(buildable: B) -> Self
where
<B as IntoBuildable>::Buildable: 'static,
{
let mut output = BuiltByContainer::with_capacity(1);
output.add(buildable);
output
}
pub fn join(self, other: Self) -> Self {
let mut inner = self.0;
inner.extend(other.0);
Self(inner)
}
pub fn add<T: IntoBuildable>(&mut self, buildable: T)
where
<T as IntoBuildable>::Buildable: 'static,
{
let buildable: Arc<dyn Buildable> = Arc::new(buildable.into_buildable());
self.0.push(buildable);
}
}
impl Debug for BuiltByContainer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "BuiltByContainer ")?;
f.debug_set().entries(&self.0).finish()
}
}
impl Buildable for BuiltByContainer {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
let mut output = HashSet::new();
for dep in &self.0 {
trace!("Getting dependencies for buildable: {:#?}", dep);
output.extend(dep.get_dependencies(project)?);
}
Ok(output)
}
}
#[derive(Debug)]
pub struct BuiltBy<T: Debug> {
built_by: Arc<dyn Buildable>,
value: T,
}
impl<T: Debug + Clone> Clone for BuiltBy<T> {
fn clone(&self) -> Self {
Self {
built_by: self.built_by.clone(),
value: self.value.clone(),
}
}
}
impl<T: Debug> DerefMut for BuiltBy<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<T: Debug> Deref for BuiltBy<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T: Debug> IntoBuildable for BuiltBy<T> {
type Buildable = Arc<dyn Buildable>;
fn into_buildable(self) -> Self::Buildable {
self.built_by
}
}
impl<T: Debug> BuiltBy<T> {
pub fn new<B: IntoBuildable + 'static>(built_by: B, value: T) -> Self {
Self {
built_by: Arc::new(built_by.into_buildable()),
value,
}
}
pub fn into_inner(self) -> T {
self.value
}
pub fn as_ref(&self) -> BuiltBy<&T> {
BuiltBy {
built_by: self.built_by.clone(),
value: &self.value,
}
}
pub fn built_by(&self) -> &dyn Buildable {
&self.built_by
}
}
#[derive(Clone, Debug)]
pub enum BuildableObject {
Container(BuiltByContainer),
Id(TaskId),
Other(Arc<dyn Buildable>),
None,
}
impl BuildableObject {
pub fn new<B: IntoBuildable>(buildable: B) -> Self
where
<B as IntoBuildable>::Buildable: 'static,
{
Self::Other(Arc::new(buildable.into_buildable()))
}
}
impl Buildable for BuildableObject {
fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
match self {
BuildableObject::Container(c) => c.get_dependencies(project),
BuildableObject::Id(id) => id.get_dependencies(project),
BuildableObject::Other(o) => o.get_dependencies(project),
BuildableObject::None => Ok(HashSet::new()),
}
}
}
impl From<BuiltByContainer> for BuildableObject {
fn from(c: BuiltByContainer) -> Self {
BuildableObject::Container(c)
}
}
impl From<TaskId> for BuildableObject {
fn from(c: TaskId) -> Self {
BuildableObject::Id(c)
}
}
impl From<Box<dyn Buildable>> for BuildableObject {
fn from(boxed: Box<dyn Buildable>) -> Self {
let arc = Arc::from(boxed);
BuildableObject::Other(arc)
}
}
assert_impl_all!(BuildableObject: Buildable, IntoBuildable, GetBuildable);