brawl_api/
time.rs

1//! Contains the [`TimeLike`] struct, used to indicate strings that contain timestamps which can
2//! be parsed using [`TimeLike.parse`] (if the `chrono` feature is enabled, otherwise the method
3//! is not implemented).
4//!
5//! [`TimeLike`]: time/struct.TimeLike.html
6//! [`TimeLike.parse`]: time/struct.TimeLike.html#method.parse
7
8use serde::{self, Serialize, Deserialize};
9use std::fmt::Display;
10
11/// Represents a timestamp provided by the Brawl API. If the `chrono` feature is enabled (it is
12/// by default), then it is possible to use helper methods to convert it to `chrono` data
13/// structures - see [`TimeLike.parse`] (this is recommended, as it is aware of the correct
14/// format).
15///
16/// [`TimeLike.parse`]: #method.parse
17#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
18pub struct TimeLike(pub(crate) String);
19
20impl Default for TimeLike {
21    /// Returns an initial `TimeLike` instance containing an empty string.
22    ///
23    /// # Examples
24    ///
25    /// ```rust
26    /// use brawl_api::TimeLike;
27    ///
28    /// assert_eq!(
29    ///     TimeLike::default().to_string(),
30    ///     "",
31    /// )
32    /// ```
33    fn default() -> TimeLike {
34        TimeLike(String::from(""))
35    }
36}
37
38impl Display for TimeLike {
39    /// Displays the inner string of the `TimeLike` instance.
40    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
41        write!(f, "{}", self.0)
42    }
43}
44
45impl TimeLike {
46    /// Returns an immutable reference to the inner string.
47    pub fn inner(&self) -> &String {
48        &self.0
49    }
50
51    /// Returns a mutable reference to the inner string.
52    pub fn inner_mut(&mut self) -> &mut String {
53        &mut self.0
54    }
55}
56
57#[cfg(feature = "chrono")]
58pub mod _impls {  // public so its implementations can be accessed
59    use crate::time::TimeLike;
60    use crate::error::{Result, Error};
61    use chrono::prelude::*;
62    use crate::constants::TIMELIKE_FORMAT;
63
64    impl TimeLike {
65        /// Parses this timestamp into a [`chrono::DateTime<chrono::Utc>`], using the API's
66        /// format (see [`constants::TIMELIKE_FORMAT`]).
67        ///
68        /// # Errors
69        ///
70        /// If the string is invalid, an [`Error::ParseTimeLike`] is returned.
71        /// Generally, when requesting from the API, this shouldn't ever happen.
72        ///
73        /// # Examples
74        ///
75        /// ```rust
76        /// use brawl_api::prelude::*;
77        /// use brawl_api::{TimeLike, Battle};
78        /// use chrono::{DateTime, Utc};
79        ///
80        ///
81        /// // after obtaining a fetched battlelog's battle
82        /// let battle: Battle;
83        /// # battle = Battle::default();
84        ///
85        /// let mut the_time: TimeLike = battle.battle_time;
86        /// # let mut _the_str = the_time.inner_mut();
87        /// # *_the_str = String::from("20200129T042143.000Z");
88        /// let parsed_time: DateTime<Utc> = the_time.parse()?;
89        /// // the parsed time of the battle is now available for use.
90        ///
91        /// # Ok::<(), Box<dyn ::std::error::Error>>(())
92        /// ```
93        ///
94        /// [`chrono::DateTime<chrono::Utc>`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html
95        /// [`chrono::ParseError`]: https://docs.rs/chrono/*/chrono/format/struct.ParseError.html
96        /// [`Error::ParseTimeLike`]: ../error/enum.Error.html#variant.ParseTimeLike
97        /// [`constants::TIMELIKE_FORMAT`]: ../constants/constant.TIMELIKE_FORMAT.html
98        pub fn parse(&self) -> Result<DateTime<Utc>> {
99            Utc.datetime_from_str(
100                &self.0, TIMELIKE_FORMAT
101            ).map_err(|e| {
102                Error::ParseTimeLike {
103                    reason: e.to_string(),
104                    offender: Some(self.0.clone()),
105                    original_err: Some(e)
106                }
107            })
108        }
109    }
110}
111
112#[cfg(feature = "datetime")]
113pub use _impls::*;
114
115///////////////////////////////////   tests   ///////////////////////////////////
116
117#[cfg(test)]
118mod tests {
119    use super::TimeLike;
120
121    /// Tests TimeLike to DateTime<Utc> conversion.
122    #[test]
123    #[cfg(feature = "chrono")]
124    fn timelike_to_datetime_convert() -> Result<(), Box<dyn ::std::error::Error>> {
125        use chrono::prelude::*;
126        let time_str = "20200129T042143.000Z";
127        let time = TimeLike(String::from(time_str));
128
129        let dt: DateTime<Utc> = Utc
130            .ymd(2020, 01, 29).and_hms(04, 21, 43);
131
132        assert_eq!(time.parse()?, dt);
133
134        Ok(())
135    }
136}