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}