pub struct Project { /* private fields */ }Expand description
Represents a project with a name and a list of resources.
Implementations§
Source§impl Project
impl Project
Sourcepub fn builder() -> ProjectBuilder
pub fn builder() -> ProjectBuilder
Create an instance of Project using the builder syntax
Source§impl Project
impl Project
Sourcepub fn name(&self) -> &str
pub fn name(&self) -> &str
Returns the name of the project.
§Example
use planter_core::project::Project;
let project = Project::new("World domination");
assert_eq!(project.name(), "World domination");Sourcepub fn description(&self) -> Option<&str>
pub fn description(&self) -> Option<&str>
Returns the description of the project.
§Example
use planter_core::project::Project;
let project = Project::new("World domination");
assert_eq!(project.description(), None);Sourcepub fn add_task(&mut self, task: Task) -> Uuid
pub fn add_task(&mut self, task: Task) -> Uuid
Adds a task to the project and returns its stable Uuid.
Adding a task whose id already exists in the project replaces it in place, without
duplicating its slot in Self::tasks.
§Arguments
task- The task to add to the project.
§Returns
The stable Uuid assigned to the task.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);Sourcepub fn add_sibling_before(
&mut self,
task: Task,
sibling_id: Uuid,
) -> Result<Uuid>
pub fn add_sibling_before( &mut self, task: Task, sibling_id: Uuid, ) -> Result<Uuid>
Inserts a new task as a sibling right before sibling_id in the task order.
If the sibling has a parent, the new task becomes a child of the same parent. This only
ever inserts a new task, it never moves an existing one.
§Errors
Returns an error if sibling_id doesn’t exist, or if task’s id is already used by
another task in the project.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_sibling_before(Task::new("Gather allies"), b).unwrap();
let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);Sourcepub fn add_sibling_after(
&mut self,
task: Task,
sibling_id: Uuid,
) -> Result<Uuid>
pub fn add_sibling_after( &mut self, task: Task, sibling_id: Uuid, ) -> Result<Uuid>
Inserts a new task as a sibling right after sibling_id in the task order.
If the sibling has a parent, the new task becomes a child of the same parent. This only
ever inserts a new task, it never moves an existing one.
§Errors
Returns an error if sibling_id doesn’t exist, or if task’s id is already used by
another task in the project.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_sibling_after(Task::new("Gather allies"), a).unwrap();
let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);Sourcepub fn rm_task(&mut self, id: Uuid) -> Result<Task>
pub fn rm_task(&mut self, id: Uuid) -> Result<Task>
Deletes a task and all references to it from the project. Any direct subtasks of the removed task are promoted to the removed task’s own parent (or to top-level, if it had none).
§Arguments
id- TheUuidof the task to remove.
§Errors
Returns an error if the task doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);
assert!(project.rm_task(id).is_ok());
assert_eq!(project.tasks().count(), 0);Sourcepub fn tasks(&self) -> impl Iterator<Item = &Task>
pub fn tasks(&self) -> impl Iterator<Item = &Task>
Returns the tasks of the project in insertion order.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
project.add_task(Task::new("Become world leader"));
assert_eq!(project.tasks().count(), 1);Sourcepub fn add_time_relationship(
&mut self,
predecessor: Uuid,
successor: Uuid,
kind: TimeRelationship,
) -> Result<()>
pub fn add_time_relationship( &mut self, predecessor: Uuid, successor: Uuid, kind: TimeRelationship, ) -> Result<()>
Adds a relationship between tasks, where one is the predecessor and the other a successor.
§Arguments
predecessor- TheUuidof the predecessor task.successor- TheUuidof the successor task.kind- The type of relationship.
§Errors
Returns an error if either task doesn’t exist, if the relationship already exists, if the relationship would create a cycle, or if one task is a subtask ancestor/descendant of the other.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
assert_eq!(project.successors(pred).next().unwrap().name(), "Become world leader")Sourcepub fn rm_time_relationship(
&mut self,
predecessor: Uuid,
successor: Uuid,
) -> Result<()>
pub fn rm_time_relationship( &mut self, predecessor: Uuid, successor: Uuid, ) -> Result<()>
Removes a relationship between tasks.
§Arguments
§Errors
Returns an error if no relationship exists between the tasks.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
project.rm_time_relationship(pred, succ).unwrap();
assert_eq!(project.successors(pred).count(), 0);Sourcepub fn successors(&self, id: Uuid) -> impl Iterator<Item = &Task>
pub fn successors(&self, id: Uuid) -> impl Iterator<Item = &Task>
Gets the successors of a given task.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
assert_eq!(project.successors(pred).next().unwrap().name(), "Become world leader")Sourcepub fn successors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>
pub fn successors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>
Gets the Uuids of all successors for a given task.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
assert_eq!(project.successors_ids(pred).next().unwrap(), succ)Sourcepub fn predecessors(&self, id: Uuid) -> impl Iterator<Item = &Task>
pub fn predecessors(&self, id: Uuid) -> impl Iterator<Item = &Task>
Gets the predecessors of a given task.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
assert_eq!(project.predecessors(succ).next().unwrap().name(), "Get rich")Sourcepub fn predecessors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>
pub fn predecessors_ids(&self, id: Uuid) -> impl Iterator<Item = Uuid>
Gets the Uuids of all predecessors for a given task.
§Example
use planter_core::{project::{Project, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let pred = project.add_task(Task::new("Get rich"));
let succ = project.add_task(Task::new("Become world leader"));
project.add_time_relationship(pred, succ, TimeRelationship::default());
assert_eq!(project.predecessors_ids(succ).next().unwrap(), pred)Sourcepub fn update_relationships(
&mut self,
task_id: Uuid,
ids: &[Uuid],
dir: RelDir,
kind: TimeRelationship,
) -> Result<()>
pub fn update_relationships( &mut self, task_id: Uuid, ids: &[Uuid], dir: RelDir, kind: TimeRelationship, ) -> Result<()>
Sets the predecessors or successors of a task to exactly the given set of tasks.
§Arguments
task_id- TheUuidof the task whose relationships need updating.ids- The tasks to set as predecessors or successors.dir- Whether to update predecessors or successors.kind- The type of time relationship.
§Errors
Returns an error if:
- Any task doesn’t exist.
- The update would create a cycle.
- Any id in
idsis a subtask ancestor/descendant oftask_id.
§Example
use planter_core::{project::{Project, RelDir, TimeRelationship}, task::Task};
let mut project = Project::new("World domination");
let id0 = project.add_task(Task::new("Become world leader"));
let id1 = project.add_task(Task::new("Get rich"));
let id2 = project.add_task(Task::new("Be evil"));
project.update_relationships(id2, &[id0, id1], RelDir::Predecessors, TimeRelationship::FinishToStart).unwrap();
assert_eq!(project.predecessors(id2).count(), 2);Sourcepub fn move_task_after(&mut self, id: Uuid, after_id: Uuid) -> Result<()>
pub fn move_task_after(&mut self, id: Uuid, after_id: Uuid) -> Result<()>
Moves id right after after_id in the global task order, affecting display order.
§Errors
Returns an error if id or after_id doesn’t exist, or if they’re the same task (there’s
nothing to move relative to).
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let a = project.add_task(Task::new("Build an army"));
let b = project.add_task(Task::new("Train troops"));
let c = project.add_task(Task::new("Gather allies"));
project.move_task_after(c, a).unwrap();
let ids: Vec<_> = project.tasks().map(|t| t.id()).collect();
assert_eq!(ids, vec![a, c, b]);Sourcepub fn add_subtask(&mut self, parent_id: Uuid, child_id: Uuid) -> Result<()>
pub fn add_subtask(&mut self, parent_id: Uuid, child_id: Uuid) -> Result<()>
Adds a subtask to a given task, marking the child as a component of the parent. The parent task is completed when all children are completed.
§Arguments
§Errors
Returns an error if either task doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let parent = project.add_task(Task::new("Build a house"));
let child1 = project.add_task(Task::new("Lay foundations"));
let child2 = project.add_task(Task::new("Build roof"));
project.add_subtask(parent, child1).unwrap();
project.add_subtask(parent, child2).unwrap();
assert_eq!(project.subtasks(parent).count(), 2);Sourcepub fn remove_subtask(&mut self, child_id: Uuid) -> Result<()>
pub fn remove_subtask(&mut self, child_id: Uuid) -> Result<()>
Removes a subtask relationship, promoting the child back to a top-level task.
§Errors
Returns an error if the task is not a subtask.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();
assert!(project.task_parent(supplies).is_some());
project.remove_subtask(supplies).unwrap();
assert!(project.task_parent(supplies).is_none());Sourcepub fn task_parent(&self, child_id: Uuid) -> Option<Uuid>
pub fn task_parent(&self, child_id: Uuid) -> Option<Uuid>
Returns the parent Uuid of a subtask, or None if the task is at root level.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
assert!(project.task_parent(supplies).is_none());
project.add_subtask(army, supplies).unwrap();
assert_eq!(project.task_parent(supplies), Some(army));Sourcepub fn subtasks(&self, parent_id: Uuid) -> impl Iterator<Item = Uuid> + '_
pub fn subtasks(&self, parent_id: Uuid) -> impl Iterator<Item = Uuid> + '_
Gets the Uuids of all subtasks of the given task.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let parent = project.add_task(Task::new("Build a house"));
let child = project.add_task(Task::new("Lay foundations"));
assert_eq!(project.subtasks(parent).count(), 0);
project.add_subtask(parent, child).unwrap();
assert_eq!(project.subtasks(parent).count(), 1);Sourcepub fn edit_task_start(&mut self, id: Uuid, start: DateTime<Utc>) -> Result<()>
pub fn edit_task_start(&mut self, id: Uuid, start: DateTime<Utc>) -> Result<()>
Sets a task’s start date, then rolls the change up through every ancestor so each one’s
own start/finish keeps covering all of its descendants. If the task has a finish date
earlier than start, the finish date is pulled forward to match it instead of leaving a
negative duration.
§Errors
Returns an error if id doesn’t exist.
§Example
use chrono::Utc;
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();
let now = Utc::now();
project.edit_task_start(supplies, now).unwrap();
// `army`'s own start followed along automatically, no separate step needed.
assert_eq!(project.task(army).unwrap().start(), Some(now));Sourcepub fn edit_task_finish(
&mut self,
id: Uuid,
finish: DateTime<Utc>,
) -> Result<()>
pub fn edit_task_finish( &mut self, id: Uuid, finish: DateTime<Utc>, ) -> Result<()>
Sets a task’s finish date, then rolls the change up through every ancestor so each one’s
own start/finish keeps covering all of its descendants. If the task has a start date
later than finish, the start date is pulled back to match it instead of leaving a
negative duration.
§Errors
Returns an error if id doesn’t exist.
§Example
use chrono::Utc;
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let army = project.add_task(Task::new("Build an army"));
let supplies = project.add_task(Task::new("Gather supplies"));
project.add_subtask(army, supplies).unwrap();
let now = Utc::now();
project.edit_task_finish(supplies, now).unwrap();
assert_eq!(project.task(army).unwrap().finish(), Some(now));Sourcepub fn edit_task_duration(
&mut self,
id: Uuid,
duration: NonNegativeDuration,
) -> Result<()>
pub fn edit_task_duration( &mut self, id: Uuid, duration: NonNegativeDuration, ) -> Result<()>
Sets a task’s duration, then rolls the change up through every ancestor so each one’s own start/finish keeps covering all of its descendants.
§Errors
Returns an error if id doesn’t exist.
§Example
use chrono::Duration;
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Build an army"));
project.edit_task_duration(task_id, Duration::hours(4).try_into().unwrap()).unwrap();
assert!(project.task(task_id).unwrap().duration().is_some());Sourcepub fn edit_task_name(
&mut self,
id: Uuid,
name: impl Into<String>,
) -> Result<()>
pub fn edit_task_name( &mut self, id: Uuid, name: impl Into<String>, ) -> Result<()>
Edits a task’s name.
§Errors
Returns an error if id doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_name(id, "Become world's biggest loser").unwrap();
assert_eq!(project.task(id).unwrap().name(), "Become world's biggest loser");Sourcepub fn edit_task_description(
&mut self,
id: Uuid,
description: impl Into<String>,
) -> Result<()>
pub fn edit_task_description( &mut self, id: Uuid, description: impl Into<String>, ) -> Result<()>
Edits a task’s description.
§Errors
Returns an error if id doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_description(id, "Step one of the plan").unwrap();
assert_eq!(project.task(id).unwrap().description(), Some("Step one of the plan"));Sourcepub fn clear_task_description(&mut self, id: Uuid) -> Result<()>
pub fn clear_task_description(&mut self, id: Uuid) -> Result<()>
Clears a task’s description, setting it to None.
§Errors
Returns an error if id doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
project.edit_task_description(id, "Step one of the plan").unwrap();
project.clear_task_description(id).unwrap();
assert!(project.task(id).unwrap().description().is_none());Sourcepub fn toggle_task_completed(&mut self, id: Uuid) -> Result<()>
pub fn toggle_task_completed(&mut self, id: Uuid) -> Result<()>
Toggles a task’s completed status.
§Errors
Returns an error if id doesn’t exist.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let id = project.add_task(Task::new("Become world leader"));
assert!(!project.task(id).unwrap().completed());
project.toggle_task_completed(id).unwrap();
assert!(project.task(id).unwrap().completed());Sourcepub const fn start_date(&self) -> Option<DateTime<Utc>>
pub const fn start_date(&self) -> Option<DateTime<Utc>>
Returns the start date of the project.
§Example
use planter_core::project::Project;
use chrono::Utc;
let start_date = Utc::now();
let project = Project::builder().name("World domination").start_date(start_date).build();
assert_eq!(project.start_date(), Some(start_date));Sourcepub const fn end_date(&self) -> Option<DateTime<Utc>>
pub const fn end_date(&self) -> Option<DateTime<Utc>>
Returns the end date of the project.
§Example
use planter_core::project::Project;
use chrono::Utc;
let mut project = Project::new("World domination");
assert!(project.end_date().is_none());
let end_date = Utc::now();
project.set_end_date(end_date);
assert_eq!(project.end_date(), Some(end_date));Sourcepub const fn set_end_date(&mut self, end_date: DateTime<Utc>)
pub const fn set_end_date(&mut self, end_date: DateTime<Utc>)
Sets the end date of the project.
§Example
use planter_core::project::Project;
use chrono::Utc;
let mut project = Project::new("World domination");
let end_date = Utc::now();
project.set_end_date(end_date);
assert_eq!(project.end_date(), Some(end_date));Sourcepub fn add_resource(&mut self, resource: Resource) -> Uuid
pub fn add_resource(&mut self, resource: Resource) -> Uuid
Adds a resource to the project’s pool and returns its stable Uuid. One-time purchase
costs belong on the Resource itself (via Resource::add_purchase), recorded once
regardless of how many tasks engage it via Self::assign_resource.
Adding a resource whose id already exists in the pool replaces it in place, without
duplicating its slot in Self::resources.
§Arguments
resource- The resource to add to the project.
§Example
use planter_core::{resources::Resource, project::Project};
let mut project = Project::new("World domination");
project.add_resource(Resource::new("Stimpack".parse().unwrap()));
assert_eq!(project.resources().count(), 1);Sourcepub fn resource(&self, id: Uuid) -> Option<&Resource>
pub fn resource(&self, id: Uuid) -> Option<&Resource>
Get a reference to a resource in the project, by its stable Uuid.
§Example
use planter_core::{resources::Resource, project::Project};
let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
assert!(project.resource(id).is_some());Sourcepub fn rm_resource(&mut self, id: Uuid) -> Result<(Resource, Vec<(Uuid, u32)>)>
pub fn rm_resource(&mut self, id: Uuid) -> Result<(Resource, Vec<(Uuid, u32)>)>
Remove a resource from the project, by its stable Uuid. Any task assignments that
referred to it are dropped too, so no task is left pointing at a resource that no longer
exists. The returned (task_id, quantity) pairs record what those were, so a caller
that wants to undo the removal can restore them with Self::assign_resource_units.
§Errors
Returns an error if id doesn’t refer to a resource in Self::resources.
§Example
use planter_core::{resources::Resource, project::Project};
let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
assert!(project.resource(id).is_some());
project.rm_resource(id).unwrap();
assert!(project.resource(id).is_none());
assert!(project.rm_resource(id).is_err());Sourcepub fn resource_mut(&mut self, id: Uuid) -> Option<&mut Resource>
pub fn resource_mut(&mut self, id: Uuid) -> Option<&mut Resource>
Get a mutable reference to a resource in the project, by its stable Uuid.
§Example
use planter_core::{resources::Resource, project::Project};
let mut project = Project::new("World domination");
let id = project.add_resource(Resource::new("Crobwar".parse().unwrap()));
// Fixing a typo in a resource's title:
project.resource_mut(id).unwrap().set_title("Crowbar".parse().unwrap());
assert_eq!(project.resource(id).unwrap().title(), "Crowbar");Sourcepub fn resources(&self) -> impl Iterator<Item = &Resource>
pub fn resources(&self) -> impl Iterator<Item = &Resource>
Returns the list of resources in the project.
§Example
use planter_core::{resources::Resource, project::Project};
let mut project = Project::new("World domination");
project.add_resource(Resource::new("Crowbar".parse().unwrap()));
assert_eq!(project.resources().count(), 1);Sourcepub fn add_purchase(
&mut self,
resource_id: Uuid,
purchase: Purchase,
) -> Result<Uuid>
pub fn add_purchase( &mut self, resource_id: Uuid, purchase: Purchase, ) -> Result<Uuid>
Records a Purchase against a resource in the project’s pool, returning its
Purchase::id. The project-level counterpart to Resource::add_purchase.
§Errors
Returns an error if resource_id doesn’t refer to a resource in Self::resources.
§Example
use planter_core::{resources::{Purchase, Resource}, project::Project, money::{Money, Currency}};
let mut project = Project::new("Build");
let stimpack = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
project.add_purchase(
stimpack,
Purchase::builder().quantity(10).unit_price(Money::from_minor_units(400, Currency::EUR)).build(),
).unwrap();
assert_eq!(project.resource(stimpack).unwrap().purchases().count(), 1);Sourcepub fn rm_purchase(
&mut self,
resource_id: Uuid,
purchase_id: Uuid,
) -> Result<Purchase>
pub fn rm_purchase( &mut self, resource_id: Uuid, purchase_id: Uuid, ) -> Result<Purchase>
Removes a resource’s purchase by id, returning it. The project-level counterpart to
Resource::rm_purchase.
§Errors
Returns an error if resource_id doesn’t refer to a resource in Self::resources, or
if that resource has no purchase with purchase_id.
Sourcepub fn purchase_mut(
&mut self,
resource_id: Uuid,
purchase_id: Uuid,
) -> Result<&mut Purchase>
pub fn purchase_mut( &mut self, resource_id: Uuid, purchase_id: Uuid, ) -> Result<&mut Purchase>
Mutable access to one of a resource’s purchases, for editing it in place. The
project-level counterpart to Resource::purchase_mut.
§Errors
Returns an error if resource_id doesn’t refer to a resource in Self::resources, or
if that resource has no purchase with purchase_id.
§Example
use planter_core::{resources::{Purchase, Resource}, project::Project, money::{Money, Currency}};
let mut project = Project::new("Build");
let stimpack = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
let purchase = project.add_purchase(
stimpack,
Purchase::builder().quantity(10).unit_price(Money::from_minor_units(400, Currency::EUR)).build(),
).unwrap();
project.purchase_mut(stimpack, purchase).unwrap().set_unit_price(Money::from_minor_units(420, Currency::EUR));
assert_eq!(
project.resource(stimpack).unwrap().purchases().next().unwrap().unit_price(),
Money::from_minor_units(420, Currency::EUR),
);Sourcepub fn assign_resource(
&mut self,
task_id: Uuid,
resource_id: Uuid,
) -> Result<()>
pub fn assign_resource( &mut self, task_id: Uuid, resource_id: Uuid, ) -> Result<()>
Records that task_id engages one unit of resource_id, checking that both the task and
the resource exist in the project. For more than one unit, use
Self::assign_resource_units.
A task engages any given resource at most once: a second call for the same resource replaces the quantity.
§Errors
Returns an error if task_id doesn’t refer to a task in the project, or if
resource_id doesn’t refer to a resource in Self::resources.
§Example
use planter_core::{project::Project, task::Task, resources::Resource};
let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Find a crowbar"));
let resource_id = project.add_resource(Resource::new("Crowbar".parse().unwrap()));
project.assign_resource(task_id, resource_id).unwrap();
assert_eq!(project.task(task_id).unwrap().assignments().count(), 1);Sourcepub fn assign_resource_units(
&mut self,
task_id: Uuid,
resource_id: Uuid,
units: NonZeroU32,
) -> Result<()>
pub fn assign_resource_units( &mut self, task_id: Uuid, resource_id: Uuid, units: NonZeroU32, ) -> Result<()>
Records that task_id engages units of resource_id, checking that both the task and
the resource exist in the project.
A task engages any given resource at most once: a second call for the same resource
replaces the quantity. units is how many of the resource the task draws at once, e.g.
2 of a 4-person crew, or 3 units of a material. To remove an assignment, use
Self::unassign_resource instead of trying to assign zero units.
§Errors
Returns an error if task_id doesn’t refer to a task in the project, or if
resource_id doesn’t refer to a resource in Self::resources.
Sourcepub fn unassign_resource(
&mut self,
task_id: Uuid,
resource_id: Uuid,
) -> Result<u32>
pub fn unassign_resource( &mut self, task_id: Uuid, resource_id: Uuid, ) -> Result<u32>
Removes task_id’s assignment for resource_id, returning the quantity it engaged. The
counterpart to Self::assign_resource.
§Errors
Returns an error if task_id doesn’t refer to a task in the project, or if the task
didn’t engage resource_id.
§Example
use planter_core::{project::Project, task::Task, resources::Resource};
use std::num::NonZeroU32;
let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Find a stimpack"));
let resource_id = project.add_resource(Resource::new("Stimpack".parse().unwrap()));
project.assign_resource_units(task_id, resource_id, NonZeroU32::new(5).unwrap()).unwrap();
assert_eq!(project.unassign_resource(task_id, resource_id).unwrap(), 5);
assert!(project.unassign_resource(task_id, resource_id).is_err());
assert_eq!(project.task(task_id).unwrap().assignments().count(), 0);Sourcepub fn total_cost(&self) -> MultiCurrencyAmount
pub fn total_cost(&self) -> MultiCurrencyAmount
Sums the project’s total cost: every resource’s one-time
purchase_cost, plus, for every task, each assignment’s
hourly cost over the task’s duration (see Self::task_cost).
Each amount is priced in its resource’s own currency; amounts in different currencies are kept as separate entries, never combined. Arithmetic saturates instead of overflowing.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
project.add_task(Task::new("Become world leader"));
assert!(project.total_cost().is_empty());Sourcepub fn task_cost(&self, task_id: Uuid) -> Result<MultiCurrencyAmount>
pub fn task_cost(&self, task_id: Uuid) -> Result<MultiCurrencyAmount>
The cost of a single task: each assignment’s hourly_rate * hours * quantity, priced in
the resource’s own currency and grouped into a MultiCurrencyAmount. A resource with
no rate, or an assignment whose resource isn’t in the project, contributes nothing.
One-time purchase costs aren’t counted here; those belong to the resource.
§Errors
Returns an error if task_id doesn’t refer to a task in the project.
§Example
use planter_core::{project::Project, task::Task};
let mut project = Project::new("World domination");
let task_id = project.add_task(Task::new("Become world leader"));
assert!(project.task_cost(task_id).unwrap().is_empty());Sourcepub fn resource_cost(&self, resource_id: Uuid) -> Result<MultiCurrencyAmount>
pub fn resource_cost(&self, resource_id: Uuid) -> Result<MultiCurrencyAmount>
The total a single resource has cost the project: its one-time
purchase_cost plus its hourly cost across every task that
engages it.
Summing this over every resource gives the same figure as Self::total_cost.
§Errors
Returns an error if resource_id doesn’t refer to a resource in Self::resources.
§Example
use planter_core::{project::Project, task::Task, resources::{Purchase, Resource}, money::{Currency, Money}};
use chrono::Duration;
let mut project = Project::new("Build");
let digger_id = project.add_resource(
Resource::new("Crowbar".parse().unwrap()).at_hourly_rate(Money::from_minor_units(30, Currency::EUR)),
);
project.add_purchase(
digger_id,
Purchase::builder().quantity(1).unit_price(Money::from_minor_units(1_000, Currency::EUR)).build(),
).unwrap();
let task_id = project.add_task(Task::new("Dig"));
project.edit_task_duration(task_id, Duration::hours(4).try_into().unwrap()).unwrap();
project.assign_resource(task_id, digger_id).unwrap();
// 1000 purchased + 30 * 4h used
assert_eq!(
project.resource_cost(digger_id).unwrap().in_currency(Currency::EUR),
Some(Money::from_minor_units(1_120, Currency::EUR)),
);Sourcepub fn add_stakeholder(&mut self, stakeholder: Stakeholder)
pub fn add_stakeholder(&mut self, stakeholder: Stakeholder)
Adds a stakeholder to the project.
§Arguments
stakeholder- The stakeholder to add to the project.
§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};
let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual {
person,
description: None,
});
assert_eq!(project.stakeholders().len(), 1);Sourcepub fn stakeholders(&self) -> &[Stakeholder]
pub fn stakeholders(&self) -> &[Stakeholder]
Returns a reference to the list of stakeholders associated with the project.
§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};
let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual {
person,
description: None,
});
assert_eq!(project.stakeholders().len(), 1);Sourcepub fn rm_stakeholder(&mut self, index: usize) -> Option<Stakeholder>
pub fn rm_stakeholder(&mut self, index: usize) -> Option<Stakeholder>
Removes a stakeholder from the project by index.
§Arguments
index- The index of the stakeholder to remove.
§Returns
The removed stakeholder, or None if the index is out of bounds.
§Example
use planter_core::{stakeholders::Stakeholder, project::Project, person::Person};
let mut project = Project::new("World domination");
let person = Person::new("Margherita", "Hack").unwrap();
project.add_stakeholder(Stakeholder::Individual { person, description: None });
assert_eq!(project.stakeholders().len(), 1);
let removed = project.rm_stakeholder(0);
assert!(removed.is_some());
assert_eq!(project.stakeholders().len(), 0);Trait Implementations§
Auto Trait Implementations§
impl Freeze for Project
impl RefUnwindSafe for Project
impl Send for Project
impl Sync for Project
impl Unpin for Project
impl UnsafeUnpin for Project
impl UnwindSafe for Project
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more