cmc/learn

My personal learning area.

clone: git clone https://gitbay.org/cmc/learn.git

0828f6d7fbf59165980e17d126b1c4730c0a3ee0

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2025-05-05T23:51:06Z

add rust project
 rust/todo/Cargo.lock  | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++
 rust/todo/Cargo.toml  |   7 ++
 rust/todo/src/main.rs | 137 ++++++++++++++++++++++++++++
 3 files changed, 388 insertions(+)

diff --git a/rust/todo/Cargo.lock b/rust/todo/Cargo.lock
new file mode 100644
index 0000000..e95a25b
--- /dev/null
+++ b/rust/todo/Cargo.lock
@@ -0,0 +1,244 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+dependencies = [
+ "anstyle",
+ "once_cell",
+ "windows-sys",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "todo"
+version = "0.1.0"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/rust/todo/Cargo.toml b/rust/todo/Cargo.toml
new file mode 100644
index 0000000..3c3a310
--- /dev/null
+++ b/rust/todo/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "todo"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+clap = { version = "4.5.37", features = ["derive"] }
diff --git a/rust/todo/src/main.rs b/rust/todo/src/main.rs
new file mode 100644
index 0000000..e009712
--- /dev/null
+++ b/rust/todo/src/main.rs
@@ -0,0 +1,137 @@
+use clap::{Arg, Command};
+use std::fs::{self, OpenOptions};
+use std::io::{self, Write};
+use std::path::Path;
+
+#[derive(Debug)]
+struct Task {
+    id: usize,
+    description: String,
+    completed: bool,
+}
+
+impl Task {
+    fn to_string(&self) -> String {
+        let status = if self.completed { "[X]" } else { "[ ]" };
+        format!("{} {}", status, self.description)
+    }
+}
+
+fn main() {
+    let matches = Command::new("Task Echo")
+        .version("1.0")
+        .about("Echoes tasks to a file")
+        .arg(
+            Arg::new("task")
+                .short('t')
+                .long("task")
+                .value_name("TASK")
+                .help("Sets the task to be saved")
+                .num_args(1..),
+        )
+        .arg(
+            Arg::new("done")
+                .short('d')
+                .long("done")
+                .value_name("TASK_ID")
+                .help("Marks the specified task(s) as complete")
+                .num_args(1..),
+        )
+        .get_matches();
+
+    let file_path = "tasks.txt";
+
+    // Handle task completion
+    if let Some(ids) = matches.get_many::<String>("done") {
+        let mut tasks = load_tasks(file_path);
+        let mut completed_tasks = Vec::new();
+        for id in ids {
+            if let Ok(index) = id.parse::<usize>() {
+                if index > 0 && index <= tasks.len() {
+                    tasks[index - 1].completed = true; // Mark task as complete
+                } else {
+                    completed_tasks.push(id.clone()); // Collect invalid task IDs
+                }
+            }
+        }
+        save_tasks(file_path, &tasks);
+
+        // Alert for nonexistent tasks
+        if !completed_tasks.is_empty() {
+            for id in completed_tasks {
+                println!("Task {} doesn't exist.", id);
+            }
+        } else {
+            println!("Tasks marked as complete.");
+        }
+
+        // Display the updated task list
+        display_tasks(file_path);
+    }
+
+    // Handle new tasks
+    if let Some(new_tasks) = matches.get_many::<String>("task") {
+        let mut tasks = load_tasks(file_path);
+        let next_id = tasks.len() + 1; // Determine the next task ID
+        for task_desc in new_tasks {
+            tasks.push(Task {
+                id: next_id,
+                description: task_desc.to_string(),
+                completed: false,
+            });
+        }
+        save_tasks(file_path, &tasks);
+        println!("Tasks saved to {}", file_path);
+
+        // Display the updated task list
+        display_tasks(file_path);
+    }
+
+    // Display saved tasks if no new tasks or done tasks were provided
+    if !matches.contains_id("task") && !matches.contains_id("done") {
+        display_tasks(file_path);
+    }
+}
+
+fn load_tasks(file_path: &str) -> Vec<Task> {
+    let mut tasks = Vec::new();
+    if Path::new(file_path).exists() {
+        let contents = fs::read_to_string(file_path).expect("Unable to read file");
+        for (id, line) in contents.lines().enumerate() {
+            let completed = line.starts_with("[X]");
+            let description = line[4..].trim().to_string();
+            tasks.push(Task {
+                id: id + 1,
+                description,
+                completed,
+            });
+        }
+    }
+    tasks
+}
+
+fn save_tasks(file_path: &str, tasks: &[Task]) {
+    let mut file = OpenOptions::new()
+        .create(true)
+        .write(true)
+        .truncate(true) // Clear the file before writing
+        .open(file_path)
+        .expect("Unable to open file");
+
+    for task in tasks {
+        writeln!(file, "{}", task.to_string()).expect("Unable to write to file");
+    }
+}
+
+fn display_tasks(file_path: &str) {
+    let tasks = load_tasks(file_path);
+    if tasks.is_empty() {
+        println!("No tasks saved yet.");
+    } else {
+        println!("Saved tasks:");
+        for task in tasks {
+            // Pad the task ID to a width of 3 for alignment
+            println!("{:>3}: {}", task.id, task.to_string()); // Display task ID
+        }
+    }
+}