1use std::time::Duration;
13
14use vasi::VirtualAddressSpaceIndependent;
15
16use super::emulated_time;
17
18#[derive(
19 Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash, VirtualAddressSpaceIndependent,
20)]
21#[repr(C)]
22pub struct SimulationTime(CSimulationTime);
23
24pub type CSimulationTime = u64;
26
27impl SimulationTime {
28 pub const MAX: SimulationTime = SimulationTime(SIMTIME_MAX);
32 pub const ZERO: SimulationTime = SimulationTime(0);
33 pub const SECOND: SimulationTime = SimulationTime(SIMTIME_ONE_SECOND);
34 pub const MILLISECOND: SimulationTime = SimulationTime(SIMTIME_ONE_MILLISECOND);
35 pub const MICROSECOND: SimulationTime = SimulationTime(SIMTIME_ONE_MICROSECOND);
36 pub const NANOSECOND: SimulationTime = SimulationTime(SIMTIME_ONE_NANOSECOND);
37
38 pub fn from_c_simtime(val: CSimulationTime) -> Option<Self> {
39 if val == SIMTIME_INVALID {
40 return None;
41 }
42
43 if val > SIMTIME_MAX {
44 return None;
45 }
46
47 Some(Self(val / SIMTIME_ONE_NANOSECOND))
48 }
49
50 pub fn to_c_simtime(val: Option<Self>) -> CSimulationTime {
51 val.map_or(SIMTIME_INVALID, |val| val.0)
52 }
53
54 pub const fn from_duration(val: std::time::Duration) -> Self {
57 if SIMTIME_ONE_NANOSECOND != 1 {
58 unreachable!();
59 }
60
61 let val = val.as_nanos();
62 if val > SIMTIME_MAX as u128 {
63 panic!("Duration is larger than SIMTIME_MAX");
64 }
65
66 Self(val as u64)
67 }
68
69 pub fn is_zero(&self) -> bool {
70 self.0 == 0
71 }
72
73 pub fn is_positive(&self) -> bool {
74 self.0 > 0
75 }
76
77 pub fn as_secs(&self) -> u64 {
78 self.0 / SIMTIME_ONE_SECOND
79 }
80
81 pub fn as_millis(&self) -> u64 {
82 self.0 / SIMTIME_ONE_MILLISECOND
83 }
84
85 pub fn as_micros(&self) -> u64 {
86 self.0 / SIMTIME_ONE_MICROSECOND
87 }
88
89 pub fn as_nanos(&self) -> u128 {
90 (self.0 / SIMTIME_ONE_NANOSECOND).into()
91 }
92
93 pub fn as_nanos_f64(&self) -> f64 {
94 self.as_nanos() as f64
95 }
96
97 pub fn checked_add(self, other: Self) -> Option<Self> {
98 match self.0.checked_add(other.0) {
99 Some(sum) => SimulationTime::from_c_simtime(sum),
100 None => None,
101 }
102 }
103
104 pub fn checked_sub(self, other: Self) -> Option<Self> {
105 match self.0.checked_sub(other.0) {
106 Some(difference) => SimulationTime::from_c_simtime(difference),
107 None => None,
108 }
109 }
110
111 pub fn checked_mul(self, other: u64) -> Option<Self> {
112 match self.0.checked_mul(other) {
113 Some(product) => SimulationTime::from_c_simtime(product),
114 None => None,
115 }
116 }
117
118 pub fn checked_div(self, other: u64) -> Option<Self> {
119 match self.0.checked_div(other) {
120 Some(quotient) => SimulationTime::from_c_simtime(quotient),
121 None => None,
122 }
123 }
124
125 pub fn checked_rem(self, other: Self) -> Option<Self> {
126 match self.0.checked_rem(other.0) {
127 Some(rem) => SimulationTime::from_c_simtime(rem),
128 None => None,
129 }
130 }
131
132 pub fn saturating_add(self, other: Self) -> Self {
133 let sum = self.0.checked_add(other.0).unwrap_or(SIMTIME_MAX);
134 SimulationTime::from_c_simtime(sum).unwrap()
135 }
136
137 pub fn saturating_sub(self, other: Self) -> Self {
138 let difference = self.0.checked_sub(other.0).unwrap_or(SIMTIME_MIN);
139 SimulationTime::from_c_simtime(difference).unwrap()
140 }
141
142 pub fn saturating_mul(self, other: u64) -> Self {
143 let product = self.0.checked_mul(other).unwrap_or(SIMTIME_MAX);
144 SimulationTime::from_c_simtime(product).unwrap()
145 }
146
147 pub fn try_from_secs(s: u64) -> Option<Self> {
148 Self::SECOND.checked_mul(s)
149 }
150
151 pub fn from_secs(s: u64) -> Self {
152 Self::try_from_secs(s).unwrap()
153 }
154
155 pub fn try_from_millis(s: u64) -> Option<Self> {
156 Self::MILLISECOND.checked_mul(s)
157 }
158
159 pub fn from_millis(s: u64) -> Self {
160 Self::try_from_millis(s).unwrap()
161 }
162
163 pub fn try_from_micros(s: u64) -> Option<Self> {
164 Self::MICROSECOND.checked_mul(s)
165 }
166
167 pub fn from_micros(s: u64) -> Self {
168 Self::try_from_micros(s).unwrap()
169 }
170
171 pub fn try_from_nanos(s: u64) -> Option<Self> {
172 Self::NANOSECOND.checked_mul(s)
173 }
174
175 pub fn from_nanos(s: u64) -> Self {
176 Self::try_from_nanos(s).unwrap()
177 }
178
179 pub fn subsec_millis(&self) -> u32 {
180 (self.as_millis() % 1_000).try_into().unwrap()
181 }
182
183 pub fn subsec_micros(&self) -> u32 {
184 (self.as_micros() % 1_000_000).try_into().unwrap()
185 }
186
187 pub fn subsec_nanos(&self) -> u32 {
188 (self.as_nanos() % 1_000_000_000).try_into().unwrap()
189 }
190}
191
192impl std::ops::Add<SimulationTime> for SimulationTime {
193 type Output = SimulationTime;
194
195 fn add(self, other: Self) -> Self::Output {
196 self.checked_add(other).unwrap()
197 }
198}
199
200impl std::ops::AddAssign<SimulationTime> for SimulationTime {
201 fn add_assign(&mut self, rhs: SimulationTime) {
202 *self = *self + rhs;
203 }
204}
205
206impl std::ops::Sub<SimulationTime> for SimulationTime {
207 type Output = SimulationTime;
208
209 fn sub(self, other: Self) -> Self::Output {
210 self.checked_sub(other).unwrap()
211 }
212}
213
214impl std::ops::SubAssign<SimulationTime> for SimulationTime {
215 fn sub_assign(&mut self, rhs: SimulationTime) {
216 *self = *self - rhs;
217 }
218}
219
220impl std::ops::Mul<u32> for SimulationTime {
221 type Output = SimulationTime;
222
223 fn mul(self, other: u32) -> Self::Output {
224 self.checked_mul(other.into()).unwrap()
225 }
226}
227
228impl std::ops::MulAssign<u32> for SimulationTime {
229 fn mul_assign(&mut self, rhs: u32) {
230 *self = self.checked_mul(rhs.into()).unwrap();
231 }
232}
233
234impl std::ops::Div<u32> for SimulationTime {
235 type Output = SimulationTime;
236
237 fn div(self, other: u32) -> Self::Output {
238 self.checked_div(other.into()).unwrap()
239 }
240}
241
242impl std::ops::DivAssign<u32> for SimulationTime {
243 fn div_assign(&mut self, rhs: u32) {
244 *self = self.checked_div(rhs.into()).unwrap();
245 }
246}
247
248impl std::ops::Rem<SimulationTime> for SimulationTime {
249 type Output = SimulationTime;
250
251 fn rem(self, other: SimulationTime) -> Self::Output {
252 self.checked_rem(other).unwrap()
253 }
254}
255
256impl std::convert::TryFrom<std::time::Duration> for SimulationTime {
257 type Error = ();
258
259 fn try_from(val: std::time::Duration) -> Result<Self, Self::Error> {
260 debug_assert_eq!(SIMTIME_ONE_NANOSECOND, 1);
261 let val = val.as_nanos();
262 if val > SIMTIME_MAX.into() {
263 Err(())
264 } else {
265 Ok(Self(val.try_into().unwrap()))
266 }
267 }
268}
269
270impl std::convert::From<SimulationTime> for std::time::Duration {
271 fn from(val: SimulationTime) -> std::time::Duration {
272 debug_assert_eq!(SIMTIME_ONE_NANOSECOND, 1);
273 Duration::from_nanos(val.0)
274 }
275}
276
277impl std::convert::From<SimulationTime> for CSimulationTime {
278 fn from(val: SimulationTime) -> CSimulationTime {
279 val.0
280 }
281}
282
283impl std::convert::TryFrom<libc::timespec> for SimulationTime {
284 type Error = ();
285
286 fn try_from(value: libc::timespec) -> Result<Self, Self::Error> {
287 if value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec > 999_999_999 {
288 return Err(());
289 }
290 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
291 let nanos = Duration::from_nanos(value.tv_nsec.try_into().unwrap());
292 Self::try_from(secs + nanos)
293 }
294}
295
296impl std::convert::TryFrom<SimulationTime> for libc::timespec {
297 type Error = ();
298
299 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
300 let value = Duration::from(value);
301 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
302 let tv_nsec = value.subsec_nanos().into();
303 Ok(libc::timespec { tv_sec, tv_nsec })
304 }
305}
306
307impl std::convert::TryFrom<linux_api::time::timespec> for SimulationTime {
308 type Error = ();
309
310 fn try_from(value: linux_api::time::timespec) -> Result<Self, Self::Error> {
311 if value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec > 999_999_999 {
312 return Err(());
313 }
314 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
315 let nanos = Duration::from_nanos(value.tv_nsec.try_into().unwrap());
316 Self::try_from(secs + nanos)
317 }
318}
319
320impl std::convert::TryFrom<SimulationTime> for linux_api::time::timespec {
321 type Error = ();
322
323 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
324 let value = Duration::from(value);
325 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
326 let tv_nsec = value.subsec_nanos().into();
327 Ok(linux_api::time::timespec { tv_sec, tv_nsec })
328 }
329}
330
331impl std::convert::TryFrom<libc::timeval> for SimulationTime {
332 type Error = ();
333
334 fn try_from(value: libc::timeval) -> Result<Self, Self::Error> {
335 if value.tv_sec < 0 || value.tv_usec < 0 || value.tv_usec > 999_999 {
336 return Err(());
337 }
338 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
339 let micros = Duration::from_micros(value.tv_usec.try_into().unwrap());
340 Self::try_from(secs + micros)
341 }
342}
343
344impl std::convert::TryFrom<SimulationTime> for libc::timeval {
345 type Error = ();
346
347 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
348 let value = Duration::from(value);
349 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
350 let tv_usec = value.subsec_micros().into();
351 Ok(libc::timeval { tv_sec, tv_usec })
352 }
353}
354
355impl std::convert::TryFrom<linux_api::time::timeval> for SimulationTime {
356 type Error = ();
357
358 fn try_from(value: linux_api::time::timeval) -> Result<Self, Self::Error> {
359 if value.tv_sec < 0 || value.tv_usec < 0 || value.tv_usec > 999_999 {
360 return Err(());
361 }
362 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
363 let micros = Duration::from_micros(value.tv_usec.try_into().unwrap());
364 Self::try_from(secs + micros)
365 }
366}
367
368impl std::convert::TryFrom<linux_api::time::kernel_old_timeval> for SimulationTime {
369 type Error = ();
370
371 fn try_from(value: linux_api::time::kernel_old_timeval) -> Result<Self, Self::Error> {
372 if value.tv_sec < 0 || value.tv_usec < 0 || value.tv_usec > 999_999 {
373 return Err(());
374 }
375 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
376 let micros = Duration::from_micros(value.tv_usec.try_into().unwrap());
377 Self::try_from(secs + micros)
378 }
379}
380
381impl std::convert::TryFrom<SimulationTime> for linux_api::time::timeval {
382 type Error = ();
383
384 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
385 let value = Duration::from(value);
386 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
387 let tv_usec = value.subsec_micros().into();
388 Ok(linux_api::time::timeval { tv_sec, tv_usec })
389 }
390}
391
392impl std::convert::TryFrom<SimulationTime> for linux_api::time::kernel_old_timeval {
393 type Error = ();
394
395 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
396 let value = Duration::from(value);
397 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
398 let tv_usec = value.subsec_micros().into();
399 Ok(linux_api::time::kernel_old_timeval { tv_sec, tv_usec })
400 }
401}
402
403impl tcp::util::time::Duration for SimulationTime {
404 const MAX: Self = Self::MAX;
405 const NANOSECOND: Self = Self::NANOSECOND;
406 const MICROSECOND: Self = Self::MICROSECOND;
407 const MILLISECOND: Self = Self::MILLISECOND;
408 const SECOND: Self = Self::SECOND;
409 const ZERO: Self = Self::ZERO;
410
411 #[inline]
412 fn as_micros(&self) -> u128 {
413 self.as_micros().into()
414 }
415
416 #[inline]
417 fn as_millis(&self) -> u128 {
418 self.as_millis().into()
419 }
420
421 #[inline]
422 fn as_nanos(&self) -> u128 {
423 self.as_nanos()
424 }
425
426 #[inline]
427 fn as_secs(&self) -> u64 {
428 self.as_secs()
429 }
430
431 #[inline]
432 fn checked_add(self, rhs: Self) -> Option<Self> {
433 self.checked_add(rhs)
434 }
435
436 #[inline]
437 fn checked_div(self, rhs: u32) -> Option<Self> {
438 self.checked_div(rhs.into())
439 }
440
441 #[inline]
442 fn checked_mul(self, rhs: u32) -> Option<Self> {
443 self.checked_mul(rhs.into())
444 }
445
446 #[inline]
447 fn checked_sub(self, rhs: Self) -> Option<Self> {
448 self.checked_sub(rhs)
449 }
450
451 #[inline]
452 fn from_micros(micros: u64) -> Self {
453 Self::from_micros(micros)
454 }
455
456 #[inline]
457 fn from_millis(millis: u64) -> Self {
458 Self::from_millis(millis)
459 }
460
461 #[inline]
462 fn from_nanos(nanos: u64) -> Self {
463 Self::from_nanos(nanos)
464 }
465
466 #[inline]
467 fn from_secs(secs: u64) -> Self {
468 Self::from_secs(secs)
469 }
470
471 #[inline]
472 fn is_zero(&self) -> bool {
473 self.is_zero()
474 }
475
476 #[inline]
477 fn saturating_add(self, rhs: Self) -> Self {
478 self.saturating_add(rhs)
479 }
480
481 #[inline]
482 fn saturating_mul(self, rhs: u32) -> Self {
483 self.saturating_mul(rhs.into())
484 }
485
486 #[inline]
487 fn saturating_sub(self, rhs: Self) -> Self {
488 self.saturating_sub(rhs)
489 }
490
491 #[inline]
492 fn subsec_micros(&self) -> u32 {
493 self.subsec_micros()
494 }
495
496 #[inline]
497 fn subsec_millis(&self) -> u32 {
498 self.subsec_millis()
499 }
500
501 #[inline]
502 fn subsec_nanos(&self) -> u32 {
503 self.subsec_nanos()
504 }
505}
506
507pub const SIMTIME_INVALID: CSimulationTime = u64::MAX;
509
510pub const SIMTIME_MAX: CSimulationTime = 17500059273709551614u64;
515const _: () =
516 assert!(SIMTIME_MAX == emulated_time::EMUTIME_MAX - emulated_time::EMUTIME_SIMULATION_START);
517
518pub const SIMTIME_MIN: CSimulationTime = 0u64;
519
520pub const SIMTIME_ONE_NANOSECOND: CSimulationTime = 1u64;
522
523pub const SIMTIME_ONE_MICROSECOND: CSimulationTime = 1000u64;
525
526pub const SIMTIME_ONE_MILLISECOND: CSimulationTime = 1000000u64;
528
529pub const SIMTIME_ONE_SECOND: CSimulationTime = 1000000000u64;
531
532pub const SIMTIME_ONE_MINUTE: CSimulationTime = 60000000000u64;
534
535pub const SIMTIME_ONE_HOUR: CSimulationTime = 3600000000000u64;
537
538pub mod export {
539 use super::*;
540 use crate::notnull::*;
541
542 #[unsafe(no_mangle)]
543 pub extern "C-unwind" fn simtime_from_timeval(val: libc::timeval) -> CSimulationTime {
544 SimulationTime::to_c_simtime(SimulationTime::try_from(val).ok())
545 }
546
547 #[unsafe(no_mangle)]
548 pub extern "C-unwind" fn simtime_from_timespec(val: libc::timespec) -> CSimulationTime {
549 SimulationTime::to_c_simtime(SimulationTime::try_from(val).ok())
550 }
551
552 #[must_use]
556 #[unsafe(no_mangle)]
557 pub unsafe extern "C-unwind" fn simtime_to_timeval(
558 val: CSimulationTime,
559 out: *mut libc::timeval,
560 ) -> bool {
561 let Some(simtime) = SimulationTime::from_c_simtime(val) else {
562 return false;
563 };
564 let Ok(tv) = libc::timeval::try_from(simtime) else {
565 return false;
566 };
567 unsafe { std::ptr::write(notnull_mut(out), tv) };
568 true
569 }
570
571 #[must_use]
575 #[unsafe(no_mangle)]
576 pub unsafe extern "C-unwind" fn simtime_to_timespec(
577 val: CSimulationTime,
578 out: *mut libc::timespec,
579 ) -> bool {
580 let Some(simtime) = SimulationTime::from_c_simtime(val) else {
581 return false;
582 };
583 let Ok(ts) = libc::timespec::try_from(simtime) else {
584 return false;
585 };
586 unsafe { std::ptr::write(out, ts) };
587 true
588 }
589}
590
591#[cfg(test)]
592mod tests {
593 use super::*;
594
595 #[test]
596 fn test_from_csimtime() {
597 let sim_time = 5 * SIMTIME_ONE_MINUTE + 7 * SIMTIME_ONE_MILLISECOND;
598 let rust_time = SimulationTime::from_c_simtime(sim_time).unwrap();
599
600 assert_eq!(Duration::from(rust_time).as_secs(), 5 * 60);
601 assert_eq!(Duration::from(rust_time).as_millis(), 5 * 60 * 1_000 + 7);
602
603 assert_eq!(
604 SimulationTime::from_c_simtime(SIMTIME_MAX).unwrap(),
605 SimulationTime::try_from(Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND))
606 .unwrap()
607 );
608 assert_eq!(SimulationTime::from_c_simtime(SIMTIME_MAX + 1), None);
609 }
610
611 #[test]
612 fn test_to_csimtime() {
613 let rust_time = SimulationTime::from_secs(5 * 60) + SimulationTime::from_millis(7);
614 let sim_time = 5 * SIMTIME_ONE_MINUTE + 7 * SIMTIME_ONE_MILLISECOND;
615
616 assert_eq!(SimulationTime::to_c_simtime(Some(rust_time)), sim_time);
617 assert_eq!(SimulationTime::to_c_simtime(None), SIMTIME_INVALID);
618 assert_eq!(
619 SimulationTime::to_c_simtime(Some(SimulationTime::MAX)),
620 SIMTIME_MAX
621 );
622 }
623
624 #[test]
625 fn test_from_timeval() {
626 use libc::timeval;
627
628 assert_eq!(
629 SimulationTime::try_from(timeval {
630 tv_sec: 0,
631 tv_usec: 0
632 }),
633 Ok(SimulationTime::ZERO)
634 );
635 assert_eq!(
636 SimulationTime::try_from(timeval {
637 tv_sec: 1,
638 tv_usec: 2
639 }),
640 Ok(
641 SimulationTime::try_from(Duration::from_secs(1) + Duration::from_micros(2))
642 .unwrap()
643 )
644 );
645 assert_eq!(
646 SimulationTime::try_from(timeval {
647 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
648 tv_usec: SimulationTime::MAX.subsec_micros().into(),
649 }),
650 Ok(SimulationTime::from_micros(SimulationTime::MAX.as_micros()))
651 );
652
653 assert_eq!(
655 SimulationTime::try_from(timeval {
656 tv_sec: libc::time_t::MAX,
657 tv_usec: 999_999
658 }),
659 Err(())
660 );
661
662 assert_eq!(
663 SimulationTime::try_from(timeval {
664 tv_sec: 0,
665 tv_usec: 1_000_000
666 }),
667 Err(())
668 );
669 assert_eq!(
670 SimulationTime::try_from(timeval {
671 tv_sec: 0,
672 tv_usec: -1
673 }),
674 Err(())
675 );
676 assert_eq!(
677 SimulationTime::try_from(timeval {
678 tv_sec: -1,
679 tv_usec: 0
680 }),
681 Err(())
682 );
683 assert_eq!(
684 SimulationTime::try_from(timeval {
685 tv_sec: -1,
686 tv_usec: -1
687 }),
688 Err(())
689 );
690 }
691
692 #[test]
693 fn test_c_from_timeval() {
694 use export::simtime_from_timeval;
695 use libc::timeval;
696
697 assert_eq!(
698 simtime_from_timeval(timeval {
699 tv_sec: 0,
700 tv_usec: 0,
701 }),
702 0
703 );
704 assert_eq!(
705 simtime_from_timeval(timeval {
706 tv_sec: 1,
707 tv_usec: 2,
708 }),
709 SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_MICROSECOND
710 );
711
712 assert_eq!(
714 simtime_from_timeval(timeval {
715 tv_sec: libc::time_t::MAX,
716 tv_usec: 999_999,
717 }),
718 SIMTIME_INVALID
719 );
720
721 assert_eq!(
722 simtime_from_timeval(timeval {
723 tv_sec: 0,
724 tv_usec: 1_000_000,
725 }),
726 SIMTIME_INVALID
727 );
728 assert_eq!(
729 simtime_from_timeval(timeval {
730 tv_sec: 0,
731 tv_usec: -1,
732 }),
733 SIMTIME_INVALID
734 );
735 assert_eq!(
736 simtime_from_timeval(timeval {
737 tv_sec: -1,
738 tv_usec: 0,
739 }),
740 SIMTIME_INVALID
741 );
742 assert_eq!(
743 simtime_from_timeval(timeval {
744 tv_sec: -1,
745 tv_usec: -1,
746 }),
747 SIMTIME_INVALID
748 );
749 }
750
751 #[test]
752 fn test_to_timeval() {
753 use libc::timeval;
754
755 assert_eq!(
756 timeval::try_from(SimulationTime::ZERO),
757 Ok(timeval {
758 tv_sec: 0,
759 tv_usec: 0
760 })
761 );
762 assert_eq!(
763 timeval::try_from(
764 SimulationTime::try_from(Duration::from_secs(1) + Duration::from_micros(2))
765 .unwrap()
766 ),
767 Ok(timeval {
768 tv_sec: 1,
769 tv_usec: 2
770 })
771 );
772 assert_eq!(
773 timeval::try_from(SimulationTime::MAX),
774 Ok(timeval {
775 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
776 tv_usec: SimulationTime::MAX.subsec_micros().into(),
777 })
778 );
779 }
780
781 #[test]
782 fn test_c_to_timeval() {
783 use export::simtime_to_timeval;
784 use libc::timeval;
785
786 let mut tv = unsafe { std::mem::zeroed() };
787
788 assert!(unsafe { simtime_to_timeval(0, &mut tv) });
789 assert_eq!(
790 tv,
791 timeval {
792 tv_sec: 0,
793 tv_usec: 0
794 }
795 );
796
797 assert!(unsafe {
798 simtime_to_timeval(SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_MICROSECOND, &mut tv)
799 });
800 assert_eq!(
801 tv,
802 timeval {
803 tv_sec: 1,
804 tv_usec: 2
805 }
806 );
807
808 {
809 assert!(unsafe { simtime_to_timeval(SIMTIME_MAX, &mut tv) });
810 let d = Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND);
811 assert_eq!(
812 tv,
813 timeval {
814 tv_sec: d.as_secs().try_into().unwrap(),
815 tv_usec: d.subsec_micros().into(),
816 }
817 );
818 }
819 }
820
821 #[test]
822 fn test_from_timespec() {
823 use libc::timespec;
824
825 assert_eq!(
826 SimulationTime::try_from(timespec {
827 tv_sec: 0,
828 tv_nsec: 0
829 }),
830 Ok(SimulationTime::ZERO)
831 );
832 assert_eq!(
833 SimulationTime::try_from(timespec {
834 tv_sec: 1,
835 tv_nsec: 2
836 }),
837 Ok(SimulationTime::try_from(Duration::from_secs(1) + Duration::from_nanos(2)).unwrap())
838 );
839 assert_eq!(
840 SimulationTime::try_from(timespec {
841 tv_sec: (SIMTIME_MAX / SIMTIME_ONE_SECOND).try_into().unwrap(),
842 tv_nsec: 0,
843 }),
844 Ok(
845 SimulationTime::try_from(Duration::from_secs(SIMTIME_MAX / SIMTIME_ONE_SECOND))
846 .unwrap()
847 )
848 );
849
850 assert_eq!(
853 SimulationTime::try_from(timespec {
854 tv_sec: libc::time_t::MAX,
855 tv_nsec: 999_999_999
856 }),
857 Err(())
858 );
859
860 assert_eq!(
861 SimulationTime::try_from(timespec {
862 tv_sec: 0,
863 tv_nsec: 1_000_000_000
864 }),
865 Err(())
866 );
867 assert_eq!(
868 SimulationTime::try_from(timespec {
869 tv_sec: 0,
870 tv_nsec: -1
871 }),
872 Err(())
873 );
874 assert_eq!(
875 SimulationTime::try_from(timespec {
876 tv_sec: -1,
877 tv_nsec: 0
878 }),
879 Err(())
880 );
881 assert_eq!(
882 SimulationTime::try_from(timespec {
883 tv_sec: -1,
884 tv_nsec: -1
885 }),
886 Err(())
887 );
888 }
889
890 #[test]
891 fn test_c_from_timespec() {
892 use export::simtime_from_timespec;
893 use libc::timespec;
894
895 assert_eq!(
896 simtime_from_timespec(timespec {
897 tv_sec: 0,
898 tv_nsec: 0,
899 }),
900 0
901 );
902 assert_eq!(
903 simtime_from_timespec(timespec {
904 tv_sec: 1,
905 tv_nsec: 2,
906 }),
907 SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_NANOSECOND
908 );
909
910 assert_eq!(
912 simtime_from_timespec(timespec {
913 tv_sec: libc::time_t::MAX,
914 tv_nsec: 999_999_999,
915 }),
916 SIMTIME_INVALID
917 );
918
919 assert_eq!(
920 simtime_from_timespec(timespec {
921 tv_sec: 0,
922 tv_nsec: 1_000_000_000,
923 }),
924 SIMTIME_INVALID
925 );
926 assert_eq!(
927 simtime_from_timespec(timespec {
928 tv_sec: 0,
929 tv_nsec: -1,
930 }),
931 SIMTIME_INVALID
932 );
933 assert_eq!(
934 simtime_from_timespec(timespec {
935 tv_sec: -1,
936 tv_nsec: 0,
937 }),
938 SIMTIME_INVALID
939 );
940 assert_eq!(
941 simtime_from_timespec(timespec {
942 tv_sec: -1,
943 tv_nsec: -1,
944 }),
945 SIMTIME_INVALID
946 );
947 }
948
949 #[test]
950 fn test_to_timespec() {
951 use libc::timespec;
952
953 assert_eq!(
954 timespec::try_from(SimulationTime::ZERO),
955 Ok(timespec {
956 tv_sec: 0,
957 tv_nsec: 0
958 })
959 );
960 assert_eq!(
961 timespec::try_from(SimulationTime::from_secs(1) + SimulationTime::from_nanos(2)),
962 Ok(timespec {
963 tv_sec: 1,
964 tv_nsec: 2
965 })
966 );
967
968 assert_eq!(
969 timespec::try_from(SimulationTime::MAX),
970 Ok(timespec {
971 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
972 tv_nsec: SimulationTime::MAX.subsec_nanos().into(),
973 })
974 );
975 }
976
977 #[test]
978 fn test_c_to_timespec() {
979 use export::simtime_to_timespec;
980 use libc::timespec;
981
982 let mut ts = unsafe { std::mem::zeroed() };
983
984 assert!(unsafe { simtime_to_timespec(0, &mut ts) });
985 assert_eq!(
986 ts,
987 timespec {
988 tv_sec: 0,
989 tv_nsec: 0
990 }
991 );
992
993 assert!(unsafe {
994 simtime_to_timespec(SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_NANOSECOND, &mut ts)
995 });
996 assert_eq!(
997 ts,
998 timespec {
999 tv_sec: 1,
1000 tv_nsec: 2
1001 }
1002 );
1003
1004 {
1005 assert!(unsafe { simtime_to_timespec(SIMTIME_MAX, &mut ts) });
1006 let d = Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND);
1007 assert_eq!(
1008 ts,
1009 timespec {
1010 tv_sec: d.as_secs().try_into().unwrap(),
1011 tv_nsec: d.subsec_nanos().into(),
1012 }
1013 );
1014 }
1015 }
1016}