Initial commit with basic Date type done
This commit is contained in:
commit
c9c479b873
6 changed files with 197 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
target/
|
||||||
82
Cargo.lock
generated
Normal file
82
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.103"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "habitrs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.118"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "habitrs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = { version = "1.0.103", features = ["std"] }
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Simple Rust habit tracker
|
||||||
|
|
||||||
|
Simple Rust habit tracker intended to integrate with the greater RLOS ecosystem.
|
||||||
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod model;
|
||||||
102
src/model.rs
Normal file
102
src/model.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail};
|
||||||
|
|
||||||
|
pub struct Date {
|
||||||
|
pub day: u8,
|
||||||
|
pub month: u8,
|
||||||
|
pub year: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Date {
|
||||||
|
/// Create a day from String. Expects strings in format '06-26-2026'
|
||||||
|
pub fn from_string(val: &str) -> anyhow::Result<Self> {
|
||||||
|
let mut parts = val.split("-");
|
||||||
|
let month = parts
|
||||||
|
.next()
|
||||||
|
.ok_or(anyhow!("Month missing from date string"))?
|
||||||
|
.parse()?;
|
||||||
|
|
||||||
|
if month > 12 || month == 0 {
|
||||||
|
bail!("Month should be > 0 and <= 12")
|
||||||
|
}
|
||||||
|
|
||||||
|
let day = parts
|
||||||
|
.next()
|
||||||
|
.ok_or(anyhow!("Day missing from date string"))?
|
||||||
|
.parse()?;
|
||||||
|
|
||||||
|
if day == 0 {
|
||||||
|
bail!("Day must be > 0")
|
||||||
|
}
|
||||||
|
|
||||||
|
match month {
|
||||||
|
2 => {
|
||||||
|
if day > 29 {
|
||||||
|
bail!("February can have a max of 29 days (on leap years)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 | 6 | 9 | 11 => {
|
||||||
|
if day > 30 {
|
||||||
|
bail!("The provided month only has 30 days")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 | 3 | 5 | 7 | 8 | 10 | 12 => {
|
||||||
|
if day > 31 {
|
||||||
|
bail!("The provided month only has 31 days")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
let year = parts
|
||||||
|
.next()
|
||||||
|
.ok_or(anyhow!("Year missing from date string"))?
|
||||||
|
.parse()?;
|
||||||
|
|
||||||
|
Ok(Date { day, month, year })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Habit {
|
||||||
|
pub name: String,
|
||||||
|
pub days_completed: HashSet<Date>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::model::Date;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn correct_date_gets_parsed() {
|
||||||
|
let date = Date::from_string("06-16-2026").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(date.day, 16);
|
||||||
|
assert_eq!(date.month, 6);
|
||||||
|
assert_eq!(date.year, 2026);
|
||||||
|
|
||||||
|
let date = Date::from_string("6-16-2026").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(date.day, 16);
|
||||||
|
assert_eq!(date.month, 6);
|
||||||
|
assert_eq!(date.year, 2026);
|
||||||
|
|
||||||
|
let date = Date::from_string("6-6-2026").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(date.day, 6);
|
||||||
|
assert_eq!(date.month, 6);
|
||||||
|
assert_eq!(date.year, 2026);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bad_date_doesnt_get_parsed() {
|
||||||
|
let date = Date::from_string("-12-2026");
|
||||||
|
assert!(date.is_err());
|
||||||
|
|
||||||
|
let date = Date::from_string("13-01-2026");
|
||||||
|
assert!(date.is_err());
|
||||||
|
|
||||||
|
let date = Date::from_string("01-32-2026");
|
||||||
|
assert!(date.is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue