diff --git a/Cargo.lock b/Cargo.lock index 0a761c4..7d7caeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,20 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "agenda" -version = "0.1.0" -dependencies = [ - "chrono", - "clap", - "colored", - "dirs", - "fuzzydate", - "prettytable-rs", - "serde", - "serde_json", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -301,6 +287,12 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.4.1" @@ -346,6 +338,31 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inertia" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "colored", + "dirs", + "fuzzydate", + "prettytable-rs", + "serde", + "serde_json", + "toml", +] + [[package]] name = "io-lifetimes" version = "1.0.5" @@ -595,6 +612,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "strsim" version = "0.10.0" @@ -663,6 +689,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "toml" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.6" @@ -843,3 +903,12 @@ name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winnow" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c06e7dbfe731192c512aa707249279d720876a868eb08f21ea93eb9de1eca9" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index d9b4463..234ef24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "agenda" +name = "inertia" version = "0.1.0" edition = "2021" @@ -15,3 +15,4 @@ dirs = "4.0.0" colored = "2.0.0" prettytable-rs = "0.10.0" fuzzydate = "0.2.1" +toml = "0.7.2" diff --git a/src/args.rs b/src/args.rs index c9e1b0c..853d46d 100644 --- a/src/args.rs +++ b/src/args.rs @@ -7,7 +7,7 @@ pub struct TasksArgs { pub command: Commands, } -#[derive(Subcommand, PartialEq, Debug)] +#[derive(Subcommand, PartialEq, Eq, Debug)] pub enum Commands { /// Creates a new task Add(CreateTask), @@ -25,7 +25,7 @@ pub enum Commands { Stop(StopTask), /// Edit a task with $EDITOR Edit(EditTask), - /// Modify a task at the cli + /// Modify a task at the command line Modify(ModifyTask), /// Passes git commands to the repository Git(GitExecute), @@ -35,7 +35,7 @@ pub enum Commands { Undo(UndoExecute), } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct CreateTask { /// Title of the task pub title: String, @@ -65,44 +65,43 @@ pub struct CreateTask { #[clap(default_value=None)] pub reminder: Option, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct DeleteTask { /// ID of the task pub id: usize, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct ShowTask { /// ID of the task #[clap(default_value=None)] pub id: Option, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct CompleteTask { /// ID of the task pub id: usize, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct StartTask { /// ID of the task pub id: usize, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct StopTask { /// ID of the task pub id: usize, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct EditTask { /// ID of the task pub id: usize, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct ModifyTask { /// ID of the task pub id: usize, /// Title of the task - #[arg(short, long)] #[clap(default_value=None)] pub title: Option, @@ -131,18 +130,18 @@ pub struct ModifyTask { #[clap(default_value=None)] pub reminder: Option, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct GitExecute { /// Git command to run pub command: String, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct SyncTasks { /// Git remote to use #[clap(default_value = "origin")] pub remote: String, } -#[derive(Args, PartialEq, Debug)] +#[derive(Args, PartialEq, Eq, Debug)] pub struct UndoExecute { /// Number of times to undo #[clap(default_value = "1")] diff --git a/src/cli.rs b/src/cli.rs index fd2dae6..40e5052 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,86 +1,14 @@ +mod dates; +pub mod output; +mod tables; + +mod cmds; + use crate::args::{Commands, TasksArgs}; -use crate::args::{CompleteTask, CreateTask, DeleteTask, ShowTask, StartTask, StopTask, ModifyTask}; -use crate::tasks::{Status, Task, Tasks, TasksError}; -use chrono::{Local, NaiveDateTime}; -use colored::*; -use fuzzydate; -use prettytable::{format, row, Row, Table}; -use std::panic; - -pub fn warning(msg: &str) { - println!("{} {}", "warning:".yellow().bold(), msg); -} - -pub fn info(msg: String) { - println!("{} {}", "info:".blue().bold(), msg); -} - -fn success(msg: String) { - println!("{} {}", "success:".green().bold(), msg); -} - -fn task_msg(msg: &str, task: &Task, id: usize) -> String { - format!( - "{} task: {}({})", - msg, - task.title.blue(), - id.to_string().cyan() - ) -} - -fn parse_date(date_string: Option) -> Option { - if date_string.is_some() { - match fuzzydate::parse(date_string.unwrap()) { - Ok(date) => Some(date), - Err(err) => panic!("{} {:?}", "error:".red().bold(), err), - } - } else { - None - } -} - -fn date_to_string(date: &Option) -> ColoredString { - if date.is_some() { - let date = date.unwrap().date(); - let date_string = format!("{}", date.format("%Y-%m-%d")); - let now = Local::now().date_naive(); - - if date <= now { - // If the date is today or past today - date_string.bright_red() - } else if now.succ_opt().unwrap() == date { - // If the date is tomorrow - date_string.yellow() - } else { - // Otherwise the date is too far in the past - date_string.white() - } - } else { - "N/A".bright_black() - } -} - -fn calc_row(task: &Task, id: usize) -> Row { - if task.status == Status::Complete { - // Generate greyed out rows for complete tasks - Row::from([ - id.to_string().bright_black().italic(), - task.status.as_string().bright_black().italic(), - task.title.clone().bright_black().italic(), - date_to_string(&task.when).bright_black().italic(), - date_to_string(&task.deadline).bright_black().italic(), - ]) - } else { - // Generate normal colored rows for uncompleted tasks - Row::from([ - id.to_string().cyan(), - task.status.as_string(), - task.title.clone().white(), - date_to_string(&task.when), - date_to_string(&task.deadline), - ]) - } -} +use crate::args::{ + CompleteTask, CreateTask, DeleteTask, ModifyTask, ShowTask, StartTask, StopTask, +}; +use crate::tasks::{Tasks, TasksError}; pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<&mut Tasks, TasksError> { match arguments.command { @@ -91,133 +19,48 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<&mut Tasks, Ta when, deadline, reminder, - .. }) => { - let when = parse_date(when); - let deadline = parse_date(deadline); - let reminder = parse_date(reminder); - let tags: Option> = if tags.is_some() { - Some(tags.unwrap().split(",").map(str::to_string).collect()) - } else { - None - }; - - let task = Task::new(title, notes, tags, when, deadline, reminder); - tasks.push(task.clone()); - - let id = tasks.len() - 1; - - success(task_msg("created", &task, id)); - Ok(tasks) + cmds::add(tasks, title, notes, tags, when, deadline, reminder); } - Commands::Modify(ModifyTask { id, title, notes, tags, when, deadline, reminder }) => { - let when = parse_date(when); - let deadline = parse_date(deadline); - let reminder = parse_date(reminder); - let tags: Option> = if tags.is_some() { - Some(tags.unwrap().split(",").map(str::to_string).collect()) - } else { - None - }; - - let task = tasks.get_task(id)?; - - if title.is_some() { - info(task_msg("renaming task", &task, id)) - }; - - task.modify(title, notes, tags, when, deadline, reminder); - - success(task_msg("modified", &task, id)); - Ok(tasks) + Commands::Modify(ModifyTask { + id, + title, + notes, + tags, + when, + deadline, + reminder, + }) => { + cmds::modify(tasks, id, title, notes, tags, when, deadline, reminder)?; } Commands::Del(DeleteTask { id }) => { - let mut binding = tasks.clone(); - let task = binding.get_task(id)?; - tasks.remove(id)?; - - success(task_msg("deleted", &task, id)); - Ok(tasks) + cmds::delete(tasks, id)?; } Commands::Done(CompleteTask { id }) => { - let task = tasks.get_task(id)?; - task.complete(); - - success(task_msg("completed", &task, id)); - Ok(tasks) + cmds::done(tasks, id)?; } Commands::Start(StartTask { id }) => { - let task = tasks.get_task(id)?; - task.start(); - - success(task_msg("started", &task, id)); - Ok(tasks) + cmds::start(tasks, id)?; } Commands::Stop(StopTask { id }) => { - let task = tasks.get_task(id)?; - task.stop(); - - success(task_msg("stopped", &task, id)); - Ok(tasks) + cmds::stop(tasks, id)?; } Commands::Clear => { - tasks.clear()?; - - success(String::from("cleared all tasks")); - Ok(tasks) + cmds::clear(tasks)?; } Commands::Show(ShowTask { id }) => { - if id.is_none() { - if tasks.is_empty() { - info(String::from("no tasks found")) - } else { - // Create the table for printing - let mut table = Table::new(); - table.set_titles(row![ - "ID".magenta().bold(), - "Status".magenta().bold(), - "Title".magenta().bold(), - "When".magenta().bold(), - "Deadline".magenta().bold(), - ]); - table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR); - - // Iterate through each task - let mut id = 0; - for task in tasks.tasks.as_ref().unwrap() { - table.add_row(calc_row(task, id)); - id += 1; - } - - // Print the table - println!("{}", table); - }; - } else { - // Get the task - let id = id.unwrap(); - let task = tasks.get_task(id)?; - - // Generate and print the table - let mut table = Table::new(); - table.set_titles(row![ - "Item".magenta().bold(), - "Value".magenta().bold(), - ]); - table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR); - table.add_row(calc_row(&task, id)); - println!("{}", table) - }; - - Ok(tasks) + cmds::show(tasks, id)?; } _ => todo!(), - } + }; + + Ok(tasks) } diff --git a/src/cli/cmds.rs b/src/cli/cmds.rs new file mode 100644 index 0000000..176252e --- /dev/null +++ b/src/cli/cmds.rs @@ -0,0 +1,153 @@ +use crate::cli::dates; +use crate::cli::output; +use crate::cli::tables; +use crate::tasks::{Task, Tasks, TasksError}; + +fn parse_tags(tags: Option) -> Option> { + if let Some(..) = tags { + Some(tags.unwrap().split(',').map(str::to_string).collect()) + } else { + None + } +} + +pub fn show(tasks: &mut Tasks, id: Option) -> Result<(), TasksError> { + // If no id is given, print out all tasks + if let Some(..) = id { + if tasks.is_empty() { + // Output when no tasks are available + output::info(String::from("no tasks found")) + } else { + // Generate the table of all tasks + let table = tables::tasks_table(tasks); + // Print the table + println!("{}", table); + }; + } else { + // Get the task the user wants to see + let id = id.unwrap(); + let task = tasks.get_task(id)?; + + // Generate the table for the singular task + let table = tables::task_table(task, id); + // Print the table + println!("{}", table); + }; + + // Success + Ok(()) +} + +pub fn add( + tasks: &mut Tasks, + title: String, + notes: Option, + tags: Option, + when: Option, + deadline: Option, + reminder: Option, +) { + // Parse dates and tags + let when = dates::parse_fuzzy_date(when); + let deadline = dates::parse_fuzzy_date(deadline); + let reminder = dates::parse_fuzzy_date(reminder); + let tags = parse_tags(tags); + + // Generate a new task + let task = Task::new(title, notes, tags, when, deadline, reminder); + // Add the task to the tasks + tasks.push(task.clone()); + + // Calculate the id for output + let id = tasks.len() - 1; + + // Success + output::success(output::task_msg("created", &task, id)); +} + +pub fn modify( + tasks: &mut Tasks, + id: usize, + title: Option, + notes: Option, + tags: Option, + when: Option, + deadline: Option, + reminder: Option, +) -> Result<(), TasksError> { + // Parse dates and tags + let when = dates::parse_fuzzy_date(when); + let deadline = dates::parse_fuzzy_date(deadline); + let reminder = dates::parse_fuzzy_date(reminder); + let tags = parse_tags(tags); + + // Get the task the user wants + let task = tasks.get_task(id)?; + + // If the the user changes the title, show that here + if title.is_some() { + output::info(output::task_msg("renaming task", task, id)) + }; + + // Modify the task + task.modify(title, notes, tags, when, deadline, reminder); + + // Success + output::success(output::task_msg("modified", task, id)); + Ok(()) +} + +pub fn delete(tasks: &mut Tasks, id: usize) -> Result<(), TasksError> { + // Get the task the user wants to delete for output later + let mut binding = tasks.clone(); + let task = binding.get_task(id)?; + + // Delete the task + tasks.remove(id)?; + + // Success + output::success(output::task_msg("deleted", task, id)); + Ok(()) +} + +pub fn clear(tasks: &mut Tasks) -> Result<(), TasksError> { + // Clear all tasks + tasks.clear()?; + + // Success + output::success(String::from("cleared all tasks")); + Ok(()) +} + +pub fn stop(tasks: &mut Tasks, id: usize) -> Result<(), TasksError> { + // Get the task the user wants to stop + let task = tasks.get_task(id)?; + // Stop the task + task.stop(); + + // Success + output::success(output::task_msg("stopped", task, id)); + Ok(()) +} + +pub fn start(tasks: &mut Tasks, id: usize) -> Result<(), TasksError> { + // Get the task the user wants to start + let task = tasks.get_task(id)?; + // Start the task + task.start(); + + // Success + output::success(output::task_msg("started", task, id)); + Ok(()) +} + +pub fn done(tasks: &mut Tasks, id: usize) -> Result<(), TasksError> { + // Get the task the user wants to complete + let task = tasks.get_task(id)?; + // Complete the task + task.complete(); + + // Success + output::success(output::task_msg("completed", task, id)); + Ok(()) +} diff --git a/src/cli/dates.rs b/src/cli/dates.rs new file mode 100644 index 0000000..d23dd32 --- /dev/null +++ b/src/cli/dates.rs @@ -0,0 +1,34 @@ +use chrono::{Local, NaiveDateTime}; +use colored::{ColoredString, Colorize}; + +pub fn parse_fuzzy_date(date_string: Option) -> Option { + if let Some(..) = date_string { + match fuzzydate::parse(date_string.unwrap()) { + Ok(date) => Some(date), + Err(err) => panic!("{} {:?}", "error:".red().bold(), err), + } + } else { + None + } +} + +pub fn date_as_string(date: &Option) -> ColoredString { + if date.is_some() { + let date = date.unwrap().date(); + let date_string = format!("{}", date.format("%Y-%m-%d")); + let now = Local::now().date_naive(); + + if date <= now { + // If the date is today or past today + date_string.bright_red() + } else if now.succ_opt().unwrap() == date { + // If the date is tomorrow + date_string.yellow() + } else { + // Otherwise the date is too far in the past + date_string.white() + } + } else { + "N/A".bright_black() + } +} diff --git a/src/cli/output.rs b/src/cli/output.rs new file mode 100644 index 0000000..52551ec --- /dev/null +++ b/src/cli/output.rs @@ -0,0 +1,23 @@ +use crate::tasks::Task; +use colored::Colorize; + +pub fn warning(msg: &str) { + println!("{} {}", "warning:".yellow().bold(), msg); +} + +pub fn info(msg: String) { + println!("{} {}", "info:".blue().bold(), msg); +} + +pub fn success(msg: String) { + println!("{} {}", "success:".green().bold(), msg); +} + +pub fn task_msg(msg: &str, task: &Task, id: usize) -> String { + format!( + "{} task: {}({})", + msg, + task.title.blue(), + id.to_string().cyan() + ) +} diff --git a/src/cli/tables.rs b/src/cli/tables.rs new file mode 100644 index 0000000..570837a --- /dev/null +++ b/src/cli/tables.rs @@ -0,0 +1,58 @@ +use colored::Colorize; +use prettytable::{format, row, Row, Table}; + +use crate::cli::dates; +use crate::tasks::{Status, Task, Tasks}; + +pub fn calc_row(task: &Task, id: usize) -> Row { + if task.status == Status::Complete { + // Generate greyed out rows for complete tasks + Row::from([ + id.to_string().bright_black().italic(), + task.status.as_string().bright_black().italic(), + task.title.clone().bright_black().italic(), + dates::date_as_string(&task.when).bright_black().italic(), + dates::date_as_string(&task.deadline) + .bright_black() + .italic(), + ]) + } else { + // Generate normal colored rows for uncompleted tasks + Row::from([ + id.to_string().cyan(), + task.status.as_string(), + task.title.clone().white(), + dates::date_as_string(&task.when), + dates::date_as_string(&task.deadline), + ]) + } +} + +pub fn tasks_table(tasks: &Tasks) -> Table { + // Create the table for printing + let mut table = Table::new(); + table.set_titles(row![ + "ID".magenta().bold(), + "Status".magenta().bold(), + "Title".magenta().bold(), + "When".magenta().bold(), + "Deadline".magenta().bold(), + ]); + table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR); + + // Iterate through each task + for (id, task) in tasks.tasks.as_ref().unwrap().iter().enumerate() { + table.add_row(calc_row(task, id)); + } + + table +} + +pub fn task_table(task: &Task, id: usize) -> Table { + let mut table = Table::new(); + table.set_titles(row!["Item".magenta().bold(), "Value".magenta().bold()]); + table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR); + table.add_row(calc_row(task, id)); + + table +} diff --git a/src/data.rs b/src/data.rs index d1f4885..8c9d13e 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,5 +1,4 @@ use dirs::home_dir; -use serde_json; use std::error::Error; use std::fs; use std::path::Path; @@ -9,8 +8,8 @@ use crate::tasks::Tasks; const TASKS_FILE_PATH: &str = "/.local/share/tasks"; pub fn save_tasks>(path: P, tasks: &Tasks) -> Result<(), Box> { - // Convert the tasks to JSON form - let data = serde_json::to_string_pretty(&tasks)?; + // Convert the tasks to TOML format + let data = toml::to_string_pretty(&tasks)?; // Write the JSON to the file fs::write(path, data)?; @@ -22,13 +21,14 @@ pub fn load_tasks>(path: P) -> Result> { // Read JSON from the file let data = fs::read_to_string(path)?; - // Load the tasks from JSON form - let tasks: Tasks = serde_json::from_str(&data)?; + // Load the tasks from TOML form + let tasks: Tasks = toml::from_str(&data)?; Ok(tasks) } pub fn tasks_file_path() -> String { + // Generate the path for the location of tasks format!( "{}{}", home_dir().unwrap().to_str().unwrap(), diff --git a/src/main.rs b/src/main.rs index 9b20c76..fa9391a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ fn main() { // If the tasks file doesn't exist, create it first if !Path::new(&tasks_file_path).exists() { - cli::warning("file '~/.local/share/tasks' does not exist. creating.."); + cli::output::warning("file '~/.local/share/tasks' does not exist. creating..."); let tasks = Tasks::new(&tasks_file_path); data::save_tasks(&tasks_file_path, &tasks).unwrap(); }; @@ -34,5 +34,5 @@ fn main() { }; // Save any changes - data::save_tasks(tasks_file_path, &tasks).unwrap() + data::save_tasks(tasks_file_path, tasks).unwrap() } diff --git a/src/tasks.rs b/src/tasks.rs index df7fb2c..ef45c59 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug)] pub struct TasksError(String); -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub enum Status { Inbox, Pending, @@ -64,28 +64,36 @@ impl Task { } } - pub fn modify(&mut self, title: Option, notes: Option, tags: Option>, when: Option, deadline: Option, reminder: Option) { - if title.is_some() { + pub fn modify( + &mut self, + title: Option, + notes: Option, + tags: Option>, + when: Option, + deadline: Option, + reminder: Option, + ) { + if let Some(..) = title { self.title = title.unwrap(); }; - if notes.is_some() { + if let Some(..) = notes { self.notes = Some(notes.unwrap()); }; - if tags.is_some() { + if let Some(..) = tags { self.tags = Some(tags.unwrap()); }; - if when.is_some() { + if let Some(..) = when { self.when = Some(when.unwrap()); }; - if deadline.is_some() { + if let Some(..) = deadline { self.deadline = Some(deadline.unwrap()); }; - if reminder.is_some() { + if let Some(..) = reminder { self.reminder = Some(reminder.unwrap()); }; } @@ -116,30 +124,20 @@ impl Tasks { } pub fn task_exists(&self, id: usize) -> bool { - if id >= self.len() { - false - } else { - true - } + id < self.len() } pub fn is_empty(&self) -> bool { - if self.len() == 0 { - true - } else { - false - } + self.len() == 0 } pub fn get_task(&mut self, id: usize) -> Result<&mut Task, TasksError> { if self.is_empty() { Err(no_tasks_available()) + } else if self.task_exists(id) { + Ok(&mut self.tasks.as_mut().unwrap()[id]) } else { - if self.task_exists(id) { - Ok(&mut self.tasks.as_mut().unwrap()[id]) - } else { - Err(task_not_found(id)) - } + Err(task_not_found(id)) } }