Skip to content

Commit

Permalink
Implement FromStr for data types (#49)
Browse files Browse the repository at this point in the history
* impl FromStr for types

* Add tests for FromStr impl
  • Loading branch information
TehPers authored Dec 13, 2023
1 parent 4ea725c commit ef53708
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/date.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt;
use std::str::FromStr;

use crate::numbers::int_parse_bytes;
use crate::{get_digit_unchecked, DateTime, ParseError};
Expand Down Expand Up @@ -42,6 +43,17 @@ impl fmt::Display for Date {
}
}

impl FromStr for Date {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
// Delegate to parse_str, which is more permissive - users can call parse_str_rfc3339 directly instead if they
// want to be stricter
Self::parse_str(s)
}
}

// 2e10 if greater than this, the number is in ms, if less than or equal, it's in seconds
// (in seconds this is 11th October 2603, in ms it's 20th August 1970)
const MS_WATERSHED: i64 = 20_000_000_000;
Expand Down
12 changes: 12 additions & 0 deletions src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::TimeConfigBuilder;
use crate::{time::TimeConfig, Date, ParseError, Time};
use std::cmp::Ordering;
use std::fmt;
use std::str::FromStr;
use std::time::SystemTime;

/// A DateTime
Expand Down Expand Up @@ -38,6 +39,17 @@ impl fmt::Display for DateTime {
}
}

impl FromStr for DateTime {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
// Delegate to parse_str, which is more permissive - users can call parse_str_rfc3339 directly instead if they
// want to be stricter
Self::parse_str(s)
}
}

impl PartialOrd for DateTime {
/// Compare two datetimes by inequality.
///
Expand Down
10 changes: 10 additions & 0 deletions src/duration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cmp::Ordering;
use std::fmt;
use std::str::FromStr;

use crate::{time::TimeConfig, ParseError, Time, TimeConfigBuilder};

Expand Down Expand Up @@ -94,6 +95,15 @@ impl fmt::Display for Duration {
}
}

impl FromStr for Duration {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse_str(s)
}
}

impl Duration {
fn to_hms(&self) -> (u32, u32, u32) {
let hours = self.second / 3600;
Expand Down
10 changes: 10 additions & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::cmp::Ordering;
use std::default::Default;
use std::fmt;
use std::str::FromStr;

use crate::{get_digit, get_digit_unchecked, ConfigError, ParseError};

Expand Down Expand Up @@ -74,6 +75,15 @@ impl fmt::Display for Time {
}
}

impl FromStr for Time {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse_str(s)
}
}

impl PartialOrd for Time {
/// Compare two times by inequality.
///
Expand Down
27 changes: 27 additions & 0 deletions tests/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs::File;
use std::io::Read;
use std::str::FromStr;

use chrono::{Datelike, FixedOffset as ChronoFixedOffset, NaiveDate, NaiveDateTime, Timelike, Utc as ChronoUtc};
use strum::EnumMessage;
Expand Down Expand Up @@ -33,11 +34,37 @@ macro_rules! expect_ok_or_error {
};
}

/// macro for comparing a type's `from_str` and `parse_str` methods
macro_rules! expect_fromstr_matches_parse_str {
($type:ty, $name:ident, ok, $_expected:expr, $example:expr) => {
paste::item! {
#[test]
fn [< expect_ $name _fromstr_matches_parse_str_ok >]() {
expect_fromstr_matches_parse_str!(@body $type, $example);
}
}
};
($type:ty, $name:ident, err, $error:expr, $example:expr) => {
paste::item! {
#[test]
fn [< expect_ $name _fromstr_matches_parse_str_ $error:snake _error >]() {
expect_fromstr_matches_parse_str!(@body $type, $example);
}
}
};
(@body $type:ty, $example:expr) => {{
let fromstr = <$type>::from_str($example);
let parse_str = <$type>::parse_str($example);
assert_eq!(fromstr, parse_str, "fromstr: {fromstr:?}, parse_str: {parse_str:?}");
}};
}

/// macro to define many tests for expected values
macro_rules! param_tests {
($type:ty, $($name:ident: $ok_or_err:ident => $input:literal, $expected:expr;)*) => {
$(
expect_ok_or_error!($type, $name, $ok_or_err, $input, $expected);
expect_fromstr_matches_parse_str!($type, $name, $ok_or_err, $expected, $input);
)*
}
}
Expand Down

0 comments on commit ef53708

Please sign in to comment.