@@ -8,6 +8,8 @@ use core::{
88
99use super :: { pair_and_then, TryFromTimeError } ;
1010
11+ const NANOS_PER_SEC : u32 = 1_000_000_000 ;
12+
1113/// A `Duration` type to represent a span of time, typically used for system
1214/// timeouts.
1315///
@@ -28,7 +30,6 @@ pub struct Duration(pub(crate) Option<time::Duration>);
2830impl Duration {
2931 // TODO: duration_constants https://github.com/rust-lang/rust/issues/57391
3032 // TODO: duration_zero https://github.com/rust-lang/rust/issues/73544
31- // TODO: duration_float https://github.com/rust-lang/rust/issues/54361
3233 // TODO: div_duration https://github.com/rust-lang/rust/issues/63139
3334
3435 /// Creates a new `Duration` from the specified number of whole seconds and
@@ -39,7 +40,7 @@ impl Duration {
3940 #[ inline]
4041 pub fn new ( secs : u64 , nanos : u32 ) -> Self {
4142 let secs = time:: Duration :: from_secs ( secs) ;
42- let nanos = time:: Duration :: from_nanos ( u64 :: from ( nanos) ) ;
43+ let nanos = time:: Duration :: from_nanos ( nanos as u64 ) ;
4344 Self ( secs. checked_add ( nanos) )
4445 }
4546
@@ -154,6 +155,174 @@ impl Duration {
154155 }
155156 }
156157
158+ /// Returns the number of seconds contained by this `Duration` as `f64`.
159+ ///
160+ /// The returned value does include the fractional (nanosecond) part of the duration.
161+ ///
162+ /// # Examples
163+ ///
164+ /// ```
165+ /// use easytime::Duration;
166+ ///
167+ /// let dur = Duration::new(2, 700_000_000);
168+ /// assert_eq!(dur.as_secs_f64(), Some(2.7));
169+ /// ```
170+ #[ inline]
171+ pub fn as_secs_f64 ( & self ) -> Option < f64 > {
172+ // TODO: replace with `self.0.as_ref().map(time::Duration::as_secs_f64)` on Rust 1.38+.
173+ self . 0 . map ( |this| {
174+ ( this. as_secs ( ) as f64 ) + ( this. subsec_nanos ( ) as f64 ) / ( NANOS_PER_SEC as f64 )
175+ } )
176+ }
177+
178+ /// Returns the number of seconds contained by this `Duration` as `f32`.
179+ ///
180+ /// The returned value does include the fractional (nanosecond) part of the duration.
181+ ///
182+ /// # Examples
183+ ///
184+ /// ```
185+ /// use easytime::Duration;
186+ ///
187+ /// let dur = Duration::new(2, 700_000_000);
188+ /// assert_eq!(dur.as_secs_f32(), Some(2.7));
189+ /// ```
190+ #[ inline]
191+ pub fn as_secs_f32 ( & self ) -> Option < f32 > {
192+ // TODO: replace with `self.0.as_ref().map(time::Duration::as_secs_f32)` on Rust 1.38+.
193+ self . 0 . map ( |this| {
194+ ( this. as_secs ( ) as f32 ) + ( this. subsec_nanos ( ) as f32 ) / ( NANOS_PER_SEC as f32 )
195+ } )
196+ }
197+
198+ /// Creates a new `Duration` from the specified number of seconds represented
199+ /// as `f64`.
200+ ///
201+ /// # Examples
202+ ///
203+ /// ```
204+ /// use easytime::Duration;
205+ ///
206+ /// let dur = Duration::from_secs_f64(2.7);
207+ /// assert_eq!(dur, Duration::new(2, 700_000_000));
208+ /// ```
209+ #[ inline]
210+ pub fn from_secs_f64 ( secs : f64 ) -> Self {
211+ const MAX_NANOS_F64 : f64 =
212+ ( ( u64:: max_value ( ) as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f64 ;
213+ let nanos = secs * ( NANOS_PER_SEC as f64 ) ;
214+ if !nanos. is_finite ( ) || nanos >= MAX_NANOS_F64 || nanos < 0.0 {
215+ return Self ( None ) ;
216+ }
217+ let nanos = nanos as u128 ;
218+ Self :: new (
219+ ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
220+ ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
221+ )
222+ }
223+
224+ /// Creates a new `Duration` from the specified number of seconds represented
225+ /// as `f32`.
226+ ///
227+ /// # Examples
228+ ///
229+ /// ```
230+ /// use easytime::Duration;
231+ ///
232+ /// let dur = Duration::from_secs_f32(2.7);
233+ /// assert_eq!(dur, Duration::new(2, 700_000_000));
234+ /// ```
235+ #[ inline]
236+ pub fn from_secs_f32 ( secs : f32 ) -> Duration {
237+ const MAX_NANOS_F32 : f32 =
238+ ( ( u64:: max_value ( ) as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f32 ;
239+ let nanos = secs * ( NANOS_PER_SEC as f32 ) ;
240+ if !nanos. is_finite ( ) || nanos >= MAX_NANOS_F32 || nanos < 0.0 {
241+ return Self ( None ) ;
242+ }
243+ let nanos = nanos as u128 ;
244+ Self :: new (
245+ ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
246+ ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
247+ )
248+ }
249+
250+ /// Multiplies `Duration` by `f64`.
251+ ///
252+ /// # Examples
253+ ///
254+ /// ```
255+ /// use easytime::Duration;
256+ ///
257+ /// let dur = Duration::new(2, 700_000_000);
258+ /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000));
259+ /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0));
260+ /// ```
261+ #[ inline]
262+ pub fn mul_f64 ( self , rhs : f64 ) -> Duration {
263+ self . as_secs_f64 ( )
264+ . map ( |secs| Duration :: from_secs_f64 ( rhs * secs) )
265+ . unwrap_or_else ( || Self ( None ) )
266+ }
267+
268+ /// Multiplies `Duration` by `f32`.
269+ ///
270+ /// # Examples
271+ ///
272+ /// ```
273+ /// use easytime::Duration;
274+ ///
275+ /// let dur = Duration::new(2, 700_000_000);
276+ /// // note that due to rounding errors result is slightly different
277+ /// // from 8.478 and 847800.0
278+ /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
279+ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
280+ /// ```
281+ #[ inline]
282+ pub fn mul_f32 ( self , rhs : f32 ) -> Duration {
283+ self . as_secs_f32 ( )
284+ . map ( |secs| Duration :: from_secs_f32 ( rhs * secs) )
285+ . unwrap_or_else ( || Self ( None ) )
286+ }
287+
288+ /// Divide `Duration` by `f64`.
289+ ///
290+ /// # Examples
291+ ///
292+ /// ```
293+ /// use easytime::Duration;
294+ ///
295+ /// let dur = Duration::new(2, 700_000_000);
296+ /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611));
297+ /// // note that truncation is used, not rounding
298+ /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598));
299+ /// ```
300+ #[ inline]
301+ pub fn div_f64 ( self , rhs : f64 ) -> Duration {
302+ self . as_secs_f64 ( )
303+ . map ( |secs| Duration :: from_secs_f64 ( secs / rhs) )
304+ . unwrap_or_else ( || Self ( None ) )
305+ }
306+
307+ /// Divide `Duration` by `f32`.
308+ ///
309+ /// # Examples
310+ ///
311+ /// ```
312+ /// use easytime::Duration;
313+ ///
314+ /// let dur = Duration::new(2, 700_000_000);
315+ /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611));
316+ /// // note that truncation is used, not rounding
317+ /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598));
318+ /// ```
319+ #[ inline]
320+ pub fn div_f32 ( self , rhs : f32 ) -> Duration {
321+ self . as_secs_f32 ( )
322+ . map ( |secs| Duration :: from_secs_f32 ( secs / rhs) )
323+ . unwrap_or_else ( || Self ( None ) )
324+ }
325+
157326 // =============================================================================
158327 // Option based method implementations
159328
0 commit comments