|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | //! A distribution uniformly generating numbers within a given range.
|
| 12 | +#[cfg(feature = "std")] |
| 13 | +use std::time::Duration; |
12 | 14 |
|
13 | 15 | use Rng;
|
14 | 16 | use distributions::Distribution;
|
@@ -494,6 +496,91 @@ macro_rules! uniform_float_impl {
|
494 | 496 | uniform_float_impl! { f32, 32 - 23, next_u32 }
|
495 | 497 | uniform_float_impl! { f64, 64 - 52, next_u64 }
|
496 | 498 |
|
| 499 | +/// Implementation of `UniformImpl` for `Duration`. |
| 500 | +/// |
| 501 | +/// Unless you are implementing `UniformImpl` for your own types, this type should |
| 502 | +/// not be used directly, use `Uniform` instead. |
| 503 | +#[cfg(feature = "std")] |
| 504 | +#[derive(Clone, Copy, Debug)] |
| 505 | +pub struct UniformDuration { |
| 506 | + offset: Duration, |
| 507 | + mode: UniformDurationMode, |
| 508 | +} |
| 509 | + |
| 510 | +#[cfg(feature = "std")] |
| 511 | +#[derive(Debug, Copy, Clone)] |
| 512 | +enum UniformDurationMode { |
| 513 | + Small { |
| 514 | + nanos: Uniform<u64>, |
| 515 | + }, |
| 516 | + Large { |
| 517 | + size: Duration, |
| 518 | + secs: Uniform<u64>, |
| 519 | + } |
| 520 | +} |
| 521 | + |
| 522 | +#[cfg(feature = "std")] |
| 523 | +impl SampleUniform for Duration { |
| 524 | + type Impl = UniformDuration; |
| 525 | +} |
| 526 | + |
| 527 | +#[cfg(feature = "std")] |
| 528 | +impl UniformImpl for UniformDuration { |
| 529 | + type X = Duration; |
| 530 | + |
| 531 | + #[inline] |
| 532 | + fn new(low: Duration, high: Duration) -> UniformDuration { |
| 533 | + UniformDuration::new_inclusive(low, high - Duration::new(0, 1)) |
| 534 | + } |
| 535 | + |
| 536 | + #[inline] |
| 537 | + fn new_inclusive(low: Duration, high: Duration) -> UniformDuration { |
| 538 | + let size = high - low; |
| 539 | + let nanos = size |
| 540 | + .as_secs() |
| 541 | + .checked_mul(1_000_000_000) |
| 542 | + .and_then(|n| n.checked_add(size.subsec_nanos() as u64)); |
| 543 | + |
| 544 | + let mode = match nanos { |
| 545 | + Some(nanos) => { |
| 546 | + UniformDurationMode::Small { |
| 547 | + nanos: Uniform::new_inclusive(0, nanos), |
| 548 | + } |
| 549 | + } |
| 550 | + None => { |
| 551 | + UniformDurationMode::Large { |
| 552 | + size: size, |
| 553 | + secs: Uniform::new_inclusive(0, size.as_secs()), |
| 554 | + } |
| 555 | + } |
| 556 | + }; |
| 557 | + |
| 558 | + UniformDuration { |
| 559 | + mode, |
| 560 | + offset: low, |
| 561 | + } |
| 562 | + } |
| 563 | + |
| 564 | + #[inline] |
| 565 | + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration { |
| 566 | + let d = match self.mode { |
| 567 | + UniformDurationMode::Small { nanos } => { |
| 568 | + let nanos = nanos.sample(rng); |
| 569 | + Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32) |
| 570 | + } |
| 571 | + UniformDurationMode::Large { size, secs } => { |
| 572 | + loop { |
| 573 | + let d = Duration::new(secs.sample(rng), rng.gen_range(0, 1_000_000_000)); |
| 574 | + if d <= size { |
| 575 | + break d; |
| 576 | + } |
| 577 | + } |
| 578 | + } |
| 579 | + }; |
| 580 | + |
| 581 | + self.offset + d |
| 582 | + } |
| 583 | +} |
497 | 584 |
|
498 | 585 | #[cfg(test)]
|
499 | 586 | mod tests {
|
@@ -601,6 +688,26 @@ mod tests {
|
601 | 688 |
|
602 | 689 | t!(f32, f64)
|
603 | 690 | }
|
| 691 | + |
| 692 | + #[test] |
| 693 | + #[cfg(feature = "std")] |
| 694 | + fn test_durations() { |
| 695 | + use std::time::Duration; |
| 696 | + |
| 697 | + let mut rng = ::test::rng(253); |
| 698 | + |
| 699 | + let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)), |
| 700 | + (Duration::new(0, 100), Duration::new(1, 50)), |
| 701 | + (Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))]; |
| 702 | + for &(low, high) in v.iter() { |
| 703 | + let my_uniform = Uniform::new(low, high); |
| 704 | + for _ in 0..1000 { |
| 705 | + let v = rng.sample(my_uniform); |
| 706 | + assert!(low <= v && v < high); |
| 707 | + } |
| 708 | + } |
| 709 | + } |
| 710 | + |
604 | 711 | #[test]
|
605 | 712 | fn test_custom_uniform() {
|
606 | 713 | #[derive(Clone, Copy, PartialEq, PartialOrd)]
|
|
0 commit comments