diff --git a/Cargo.lock b/Cargo.lock index 2c4734b..b7cfc44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,6 +22,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "achievement-counter-server" +version = "0.1.0" +dependencies = [ + "achievement-counter-core", + "anyhow", + "chrono", + "clap", + "thiserror", +] + [[package]] name = "android-tzdata" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 304f453..d74f2b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,10 @@ members = [ "cli", - "core", + "core", "server", ] [workspace.dependencies] anyhow = "1.0.98" chrono = "0.4.40" -thiserror = "2.0.12" \ No newline at end of file +thiserror = "2.0.12" diff --git a/cli/src/error.rs b/cli/src/error.rs new file mode 100644 index 0000000..73b396d --- /dev/null +++ b/cli/src/error.rs @@ -0,0 +1,18 @@ +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Parser error")] + Clap(#[from] clap::Error), + #[error("Parse int error")] + ParseIntError(#[from] std::num::ParseIntError), + #[error("IO Error")] + IoError(#[from] std::io::Error), +} + +impl Error { + pub fn print(&self) -> Result<(), Error> { + match self { + Error::Clap(x) => Ok(x.print()?), + _ => unimplemented!(), + } + } +} \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 89d0a2d..88d7d45 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,33 +1,56 @@ +pub mod error; //mod label; mod record; //use label::LabelArgs; +use error::Error; use record::{RecordArgs,RecordAddArgs}; -use clap::{Parser, Subcommand}; +use clap::{Args, CommandFactory, Parser, Subcommand}; + +use std::ffi::OsString; #[derive(Parser)] #[command(version, about, long_about = None)] #[command(propagate_version=true)] struct Cli { - #[command(flatten)] - add_args: Option, #[command(subcommand)] - command: Option, + command: Command, } -#[derive(Subcommand)] + +#[derive(Clone, Debug, Subcommand)] enum Command { - //Add(RecordAddArgs), - //Label(LabelArgs), Record(RecordArgs), } -fn main() { - let cli = Cli::parse(); - match &cli.command { - //Some(Commands::Add(x)) => x.run(), - //Some(Commands::Label(x)) => x.run(), - Some(Command::Record(x)) => x.run(), - None => {unimplemented!()}, - } +fn try_parse() -> Result { + Ok(try_parse_from(std::env::args_os())?) +} + +fn try_parse_from(itr: I) -> Result +where I: IntoIterator, +T: Into + Clone, +{ + let os_string_vec: Vec = itr.into_iter().map(|x| Into::::into(x)).collect(); + Cli::try_parse_from(os_string_vec.clone()).or_else(|err| match err.kind() { + clap::error::ErrorKind::InvalidSubcommand => { + try_parse_from(vec![OsString::from("record"), OsString::from("add")].into_iter().chain(os_string_vec.clone().into_iter())) + }, + _ => Err(err)?, + + }) +} + +fn main() -> Result<(), Error> { + let cli = try_parse(); + match cli { + Err(_) => Ok(Cli::command().print_help()?), + Ok(x) => match x.command { + //Some(Commands::Add(x)) => x.run(), + //Some(Commands::Label(x)) => x.run(), + Command::Record(x) => x.run(), + } + } + + } diff --git a/cli/src/record.rs b/cli/src/record.rs index 23941ea..050521a 100644 --- a/cli/src/record.rs +++ b/cli/src/record.rs @@ -1,37 +1,56 @@ use achievement_counter_core::Record; use chrono::prelude::*; use clap::{Args, Subcommand}; +use crate::Error; +use std::str::FromStr; -#[derive(Args)] -pub struct RecordAddArgs { +#[derive(Args, Clone, Debug)] +pub struct AchievementArgValues { pub label: String, + pub value: i8, +} + +impl FromStr for AchievementArgValues { + type Err = Error; + fn from_str(s: &str) -> Result { + let strvec: Vec<&str> = s.split(':').collect(); + Ok(AchievementArgValues{ + label: strvec.get(0).unwrap().to_string(), + value: strvec.get(1).unwrap().parse()? + }) + } +} + + +#[derive(Args, Clone, Debug)] +pub struct RecordAddArgs { #[arg(short, long)] pub comment: Option, #[arg(short, long)] pub time: Option>, - #[arg(default_value_t = 1)] - pub count: u8, + //pub achievements: Vec, } + impl RecordAddArgs { - pub fn run(&self) { + pub fn run(self) -> Result<(), Error> { unimplemented!(); } } -#[derive(Subcommand)] +#[derive(Clone, Debug, Subcommand)] pub enum RecordCommand { Add(RecordAddArgs), } -#[derive(Args)] +#[derive(Args, Clone, Debug)] pub struct RecordArgs { #[command(subcommand)] command: RecordCommand, } impl RecordArgs { - pub fn run(&self) { - match &self.command { + pub fn run(self) -> Result<(), Error> { + match self.command { RecordCommand::Add(x) => x.run(), } } diff --git a/core/src/data/achievement.rs b/core/src/data/achievement.rs new file mode 100644 index 0000000..b2b399f --- /dev/null +++ b/core/src/data/achievement.rs @@ -0,0 +1,10 @@ +use super::id::*; + +pub struct Achievement +where T: MayId, +U: MayId, +{ + id: T, + lavel: U, + count: i8, +} \ No newline at end of file diff --git a/core/src/data/id.rs b/core/src/data/id.rs new file mode 100644 index 0000000..b64cd99 --- /dev/null +++ b/core/src/data/id.rs @@ -0,0 +1,55 @@ + +#[derive(Debug)] +pub struct IdNumber(usize); +#[derive(Debug)] +pub struct IdString(String); +#[derive(Debug)] +pub struct NoId(); + +#[derive(Debug, PartialEq)] +pub enum IdValue { + Number(usize), + String(String) +} + +pub trait MayId { + fn is_id() -> bool; + fn get_value(&self) -> Option; +} + +impl MayId for IdNumber { + fn is_id() -> bool { + true + } + fn get_value(&self) -> Option { + Some(IdValue::Number(self.0)) + } +} +impl MayId for IdString { + fn is_id() -> bool { + true + } + fn get_value(&self) -> Option { + Some(IdValue::String(self.0.clone())) + } +} +impl MayId for NoId { + fn is_id() -> bool { + false + } + fn get_value(&self) -> Option { + None + } +} + + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn parse_values() { + assert_eq!(Some(IdValue::Number(1)), IdNumber(1).get_value()); + assert_eq!(Some(IdValue::String("Test".to_string())), IdString("Test".to_string()).get_value()); + assert_eq!(None, NoId().get_value()); + } +} \ No newline at end of file diff --git a/core/src/label.rs b/core/src/data/label.rs similarity index 100% rename from core/src/label.rs rename to core/src/data/label.rs diff --git a/core/src/data/mod.rs b/core/src/data/mod.rs new file mode 100644 index 0000000..93b493f --- /dev/null +++ b/core/src/data/mod.rs @@ -0,0 +1,9 @@ +mod id; +mod label; +mod record; +mod achievement; + +pub use id::*; +pub use label::*; +pub use record::*; +pub use achievement::*; \ No newline at end of file diff --git a/core/src/record.rs b/core/src/data/record.rs similarity index 50% rename from core/src/record.rs rename to core/src/data/record.rs index 4a4ced2..13beb87 100644 --- a/core/src/record.rs +++ b/core/src/data/record.rs @@ -1,10 +1,9 @@ -use crate::label::Label; use chrono::prelude::*; +use std::collections::HashMap; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Record { - pub label: String, pub comment: String, - pub count: u8, pub date: DateTime, + pub achievements: HashMap, } diff --git a/core/src/lib.rs b/core/src/lib.rs index 008973a..baa9cdf 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,7 +1,6 @@ -pub mod label; -pub mod record; -pub use self::label::Label; -pub use self::record::Record; +pub mod data; +pub use self::data::Label; +pub use self::data::Record; pub fn add(left: u64, right: u64) -> u64 { left + right diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..ba03def --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "achievement-counter-server" +version = "0.1.0" +edition = "2024" + +[dependencies] +achievement-counter-core = { path = "../core" } +anyhow = {workspace = true} +chrono = {workspace = true} +clap = {version = "4.5.37", features=["derive"]} +thiserror = {workspace = true} \ No newline at end of file diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}