1use core::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: core::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 core::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 core::ops::AddAssign<SimulationTime> for SimulationTime {
201 fn add_assign(&mut self, rhs: SimulationTime) {
202 *self = *self + rhs;
203 }
204}
205
206impl core::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 core::ops::SubAssign<SimulationTime> for SimulationTime {
215 fn sub_assign(&mut self, rhs: SimulationTime) {
216 *self = *self - rhs;
217 }
218}
219
220impl core::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 core::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 core::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 core::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 core::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 core::convert::TryFrom<core::time::Duration> for SimulationTime {
257 type Error = ();
258
259 fn try_from(val: core::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 core::convert::From<SimulationTime> for core::time::Duration {
271 fn from(val: SimulationTime) -> core::time::Duration {
272 debug_assert_eq!(SIMTIME_ONE_NANOSECOND, 1);
273 Duration::from_nanos(val.0)
274 }
275}
276
277impl core::convert::From<SimulationTime> for CSimulationTime {
278 fn from(val: SimulationTime) -> CSimulationTime {
279 val.0
280 }
281}
282
283impl core::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 core::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 core::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 core::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 core::convert::TryFrom<linux_api::time::kernel_timespec> for SimulationTime {
332 type Error = ();
333
334 fn try_from(value: linux_api::time::kernel_timespec) -> Result<Self, Self::Error> {
335 if value.tv_sec < 0 || value.tv_nsec < 0 || value.tv_nsec > 999_999_999 {
336 return Err(());
337 }
338 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
339 let nanos = Duration::from_nanos(value.tv_nsec.try_into().unwrap());
340 Self::try_from(secs + nanos)
341 }
342}
343
344impl core::convert::TryFrom<SimulationTime> for linux_api::time::kernel_timespec {
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_nsec = value.subsec_nanos().into();
351 Ok(linux_api::time::kernel_timespec { tv_sec, tv_nsec })
352 }
353}
354
355impl core::convert::TryFrom<libc::timeval> for SimulationTime {
356 type Error = ();
357
358 fn try_from(value: libc::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 core::convert::TryFrom<SimulationTime> for libc::timeval {
369 type Error = ();
370
371 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
372 let value = Duration::from(value);
373 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
374 let tv_usec = value.subsec_micros().into();
375 Ok(libc::timeval { tv_sec, tv_usec })
376 }
377}
378
379impl core::convert::TryFrom<linux_api::time::timeval> for SimulationTime {
380 type Error = ();
381
382 fn try_from(value: linux_api::time::timeval) -> Result<Self, Self::Error> {
383 if value.tv_sec < 0 || value.tv_usec < 0 || value.tv_usec > 999_999 {
384 return Err(());
385 }
386 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
387 let micros = Duration::from_micros(value.tv_usec.try_into().unwrap());
388 Self::try_from(secs + micros)
389 }
390}
391
392impl core::convert::TryFrom<linux_api::time::kernel_old_timeval> for SimulationTime {
393 type Error = ();
394
395 fn try_from(value: linux_api::time::kernel_old_timeval) -> Result<Self, Self::Error> {
396 if value.tv_sec < 0 || value.tv_usec < 0 || value.tv_usec > 999_999 {
397 return Err(());
398 }
399 let secs = Duration::from_secs(value.tv_sec.try_into().unwrap());
400 let micros = Duration::from_micros(value.tv_usec.try_into().unwrap());
401 Self::try_from(secs + micros)
402 }
403}
404
405impl core::convert::TryFrom<SimulationTime> for linux_api::time::timeval {
406 type Error = ();
407
408 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
409 let value = Duration::from(value);
410 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
411 let tv_usec = value.subsec_micros().into();
412 Ok(linux_api::time::timeval { tv_sec, tv_usec })
413 }
414}
415
416impl core::convert::TryFrom<SimulationTime> for linux_api::time::kernel_old_timeval {
417 type Error = ();
418
419 fn try_from(value: SimulationTime) -> Result<Self, Self::Error> {
420 let value = Duration::from(value);
421 let tv_sec = value.as_secs().try_into().map_err(|_| ())?;
422 let tv_usec = value.subsec_micros().into();
423 Ok(linux_api::time::kernel_old_timeval { tv_sec, tv_usec })
424 }
425}
426
427impl tcp::util::time::Duration for SimulationTime {
428 const MAX: Self = Self::MAX;
429 const NANOSECOND: Self = Self::NANOSECOND;
430 const MICROSECOND: Self = Self::MICROSECOND;
431 const MILLISECOND: Self = Self::MILLISECOND;
432 const SECOND: Self = Self::SECOND;
433 const ZERO: Self = Self::ZERO;
434
435 #[inline]
436 fn as_micros(&self) -> u128 {
437 self.as_micros().into()
438 }
439
440 #[inline]
441 fn as_millis(&self) -> u128 {
442 self.as_millis().into()
443 }
444
445 #[inline]
446 fn as_nanos(&self) -> u128 {
447 self.as_nanos()
448 }
449
450 #[inline]
451 fn as_secs(&self) -> u64 {
452 self.as_secs()
453 }
454
455 #[inline]
456 fn checked_add(self, rhs: Self) -> Option<Self> {
457 self.checked_add(rhs)
458 }
459
460 #[inline]
461 fn checked_div(self, rhs: u32) -> Option<Self> {
462 self.checked_div(rhs.into())
463 }
464
465 #[inline]
466 fn checked_mul(self, rhs: u32) -> Option<Self> {
467 self.checked_mul(rhs.into())
468 }
469
470 #[inline]
471 fn checked_sub(self, rhs: Self) -> Option<Self> {
472 self.checked_sub(rhs)
473 }
474
475 #[inline]
476 fn from_micros(micros: u64) -> Self {
477 Self::from_micros(micros)
478 }
479
480 #[inline]
481 fn from_millis(millis: u64) -> Self {
482 Self::from_millis(millis)
483 }
484
485 #[inline]
486 fn from_nanos(nanos: u64) -> Self {
487 Self::from_nanos(nanos)
488 }
489
490 #[inline]
491 fn from_secs(secs: u64) -> Self {
492 Self::from_secs(secs)
493 }
494
495 #[inline]
496 fn is_zero(&self) -> bool {
497 self.is_zero()
498 }
499
500 #[inline]
501 fn saturating_add(self, rhs: Self) -> Self {
502 self.saturating_add(rhs)
503 }
504
505 #[inline]
506 fn saturating_mul(self, rhs: u32) -> Self {
507 self.saturating_mul(rhs.into())
508 }
509
510 #[inline]
511 fn saturating_sub(self, rhs: Self) -> Self {
512 self.saturating_sub(rhs)
513 }
514
515 #[inline]
516 fn subsec_micros(&self) -> u32 {
517 self.subsec_micros()
518 }
519
520 #[inline]
521 fn subsec_millis(&self) -> u32 {
522 self.subsec_millis()
523 }
524
525 #[inline]
526 fn subsec_nanos(&self) -> u32 {
527 self.subsec_nanos()
528 }
529}
530
531pub const SIMTIME_INVALID: CSimulationTime = u64::MAX;
533
534pub const SIMTIME_MAX: CSimulationTime = 17500059273709551614u64;
539const _: () =
540 assert!(SIMTIME_MAX == emulated_time::EMUTIME_MAX - emulated_time::EMUTIME_SIMULATION_START);
541
542pub const SIMTIME_MIN: CSimulationTime = 0u64;
543
544pub const SIMTIME_ONE_NANOSECOND: CSimulationTime = 1u64;
546
547pub const SIMTIME_ONE_MICROSECOND: CSimulationTime = 1000u64;
549
550pub const SIMTIME_ONE_MILLISECOND: CSimulationTime = 1000000u64;
552
553pub const SIMTIME_ONE_SECOND: CSimulationTime = 1000000000u64;
555
556pub const SIMTIME_ONE_MINUTE: CSimulationTime = 60000000000u64;
558
559pub const SIMTIME_ONE_HOUR: CSimulationTime = 3600000000000u64;
561
562pub mod export {
563 use super::*;
564 use crate::notnull::*;
565
566 #[unsafe(no_mangle)]
567 pub extern "C-unwind" fn simtime_from_timeval(val: libc::timeval) -> CSimulationTime {
568 SimulationTime::to_c_simtime(SimulationTime::try_from(val).ok())
569 }
570
571 #[unsafe(no_mangle)]
572 pub extern "C-unwind" fn simtime_from_timespec(val: libc::timespec) -> CSimulationTime {
573 SimulationTime::to_c_simtime(SimulationTime::try_from(val).ok())
574 }
575
576 #[must_use]
580 #[unsafe(no_mangle)]
581 pub unsafe extern "C-unwind" fn simtime_to_timeval(
582 val: CSimulationTime,
583 out: *mut libc::timeval,
584 ) -> bool {
585 let Some(simtime) = SimulationTime::from_c_simtime(val) else {
586 return false;
587 };
588 let Ok(tv) = libc::timeval::try_from(simtime) else {
589 return false;
590 };
591 unsafe { core::ptr::write(notnull_mut(out), tv) };
592 true
593 }
594
595 #[must_use]
599 #[unsafe(no_mangle)]
600 pub unsafe extern "C-unwind" fn simtime_to_timespec(
601 val: CSimulationTime,
602 out: *mut libc::timespec,
603 ) -> bool {
604 let Some(simtime) = SimulationTime::from_c_simtime(val) else {
605 return false;
606 };
607 let Ok(ts) = libc::timespec::try_from(simtime) else {
608 return false;
609 };
610 unsafe { core::ptr::write(out, ts) };
611 true
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 #[test]
620 fn test_from_csimtime() {
621 let sim_time = 5 * SIMTIME_ONE_MINUTE + 7 * SIMTIME_ONE_MILLISECOND;
622 let rust_time = SimulationTime::from_c_simtime(sim_time).unwrap();
623
624 assert_eq!(Duration::from(rust_time).as_secs(), 5 * 60);
625 assert_eq!(Duration::from(rust_time).as_millis(), 5 * 60 * 1_000 + 7);
626
627 assert_eq!(
628 SimulationTime::from_c_simtime(SIMTIME_MAX).unwrap(),
629 SimulationTime::try_from(Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND))
630 .unwrap()
631 );
632 assert_eq!(SimulationTime::from_c_simtime(SIMTIME_MAX + 1), None);
633 }
634
635 #[test]
636 fn test_to_csimtime() {
637 let rust_time = SimulationTime::from_secs(5 * 60) + SimulationTime::from_millis(7);
638 let sim_time = 5 * SIMTIME_ONE_MINUTE + 7 * SIMTIME_ONE_MILLISECOND;
639
640 assert_eq!(SimulationTime::to_c_simtime(Some(rust_time)), sim_time);
641 assert_eq!(SimulationTime::to_c_simtime(None), SIMTIME_INVALID);
642 assert_eq!(
643 SimulationTime::to_c_simtime(Some(SimulationTime::MAX)),
644 SIMTIME_MAX
645 );
646 }
647
648 #[test]
649 fn test_from_timeval() {
650 use libc::timeval;
651
652 assert_eq!(
653 SimulationTime::try_from(timeval {
654 tv_sec: 0,
655 tv_usec: 0
656 }),
657 Ok(SimulationTime::ZERO)
658 );
659 assert_eq!(
660 SimulationTime::try_from(timeval {
661 tv_sec: 1,
662 tv_usec: 2
663 }),
664 Ok(
665 SimulationTime::try_from(Duration::from_secs(1) + Duration::from_micros(2))
666 .unwrap()
667 )
668 );
669 assert_eq!(
670 SimulationTime::try_from(timeval {
671 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
672 tv_usec: SimulationTime::MAX.subsec_micros().into(),
673 }),
674 Ok(SimulationTime::from_micros(SimulationTime::MAX.as_micros()))
675 );
676
677 assert_eq!(
679 SimulationTime::try_from(timeval {
680 tv_sec: libc::time_t::MAX,
681 tv_usec: 999_999
682 }),
683 Err(())
684 );
685
686 assert_eq!(
687 SimulationTime::try_from(timeval {
688 tv_sec: 0,
689 tv_usec: 1_000_000
690 }),
691 Err(())
692 );
693 assert_eq!(
694 SimulationTime::try_from(timeval {
695 tv_sec: 0,
696 tv_usec: -1
697 }),
698 Err(())
699 );
700 assert_eq!(
701 SimulationTime::try_from(timeval {
702 tv_sec: -1,
703 tv_usec: 0
704 }),
705 Err(())
706 );
707 assert_eq!(
708 SimulationTime::try_from(timeval {
709 tv_sec: -1,
710 tv_usec: -1
711 }),
712 Err(())
713 );
714 }
715
716 #[test]
717 fn test_c_from_timeval() {
718 use export::simtime_from_timeval;
719 use libc::timeval;
720
721 assert_eq!(
722 simtime_from_timeval(timeval {
723 tv_sec: 0,
724 tv_usec: 0,
725 }),
726 0
727 );
728 assert_eq!(
729 simtime_from_timeval(timeval {
730 tv_sec: 1,
731 tv_usec: 2,
732 }),
733 SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_MICROSECOND
734 );
735
736 assert_eq!(
738 simtime_from_timeval(timeval {
739 tv_sec: libc::time_t::MAX,
740 tv_usec: 999_999,
741 }),
742 SIMTIME_INVALID
743 );
744
745 assert_eq!(
746 simtime_from_timeval(timeval {
747 tv_sec: 0,
748 tv_usec: 1_000_000,
749 }),
750 SIMTIME_INVALID
751 );
752 assert_eq!(
753 simtime_from_timeval(timeval {
754 tv_sec: 0,
755 tv_usec: -1,
756 }),
757 SIMTIME_INVALID
758 );
759 assert_eq!(
760 simtime_from_timeval(timeval {
761 tv_sec: -1,
762 tv_usec: 0,
763 }),
764 SIMTIME_INVALID
765 );
766 assert_eq!(
767 simtime_from_timeval(timeval {
768 tv_sec: -1,
769 tv_usec: -1,
770 }),
771 SIMTIME_INVALID
772 );
773 }
774
775 #[test]
776 fn test_to_timeval() {
777 use libc::timeval;
778
779 assert_eq!(
780 timeval::try_from(SimulationTime::ZERO),
781 Ok(timeval {
782 tv_sec: 0,
783 tv_usec: 0
784 })
785 );
786 assert_eq!(
787 timeval::try_from(
788 SimulationTime::try_from(Duration::from_secs(1) + Duration::from_micros(2))
789 .unwrap()
790 ),
791 Ok(timeval {
792 tv_sec: 1,
793 tv_usec: 2
794 })
795 );
796 assert_eq!(
797 timeval::try_from(SimulationTime::MAX),
798 Ok(timeval {
799 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
800 tv_usec: SimulationTime::MAX.subsec_micros().into(),
801 })
802 );
803 }
804
805 #[test]
806 fn test_c_to_timeval() {
807 use export::simtime_to_timeval;
808 use libc::timeval;
809
810 let mut tv = unsafe { std::mem::zeroed() };
811
812 assert!(unsafe { simtime_to_timeval(0, &mut tv) });
813 assert_eq!(
814 tv,
815 timeval {
816 tv_sec: 0,
817 tv_usec: 0
818 }
819 );
820
821 assert!(unsafe {
822 simtime_to_timeval(SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_MICROSECOND, &mut tv)
823 });
824 assert_eq!(
825 tv,
826 timeval {
827 tv_sec: 1,
828 tv_usec: 2
829 }
830 );
831
832 {
833 assert!(unsafe { simtime_to_timeval(SIMTIME_MAX, &mut tv) });
834 let d = Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND);
835 assert_eq!(
836 tv,
837 timeval {
838 tv_sec: d.as_secs().try_into().unwrap(),
839 tv_usec: d.subsec_micros().into(),
840 }
841 );
842 }
843 }
844
845 #[test]
846 fn test_from_timespec() {
847 use libc::timespec;
848
849 assert_eq!(
850 SimulationTime::try_from(timespec {
851 tv_sec: 0,
852 tv_nsec: 0
853 }),
854 Ok(SimulationTime::ZERO)
855 );
856 assert_eq!(
857 SimulationTime::try_from(timespec {
858 tv_sec: 1,
859 tv_nsec: 2
860 }),
861 Ok(SimulationTime::try_from(Duration::from_secs(1) + Duration::from_nanos(2)).unwrap())
862 );
863 assert_eq!(
864 SimulationTime::try_from(timespec {
865 tv_sec: (SIMTIME_MAX / SIMTIME_ONE_SECOND).try_into().unwrap(),
866 tv_nsec: 0,
867 }),
868 Ok(
869 SimulationTime::try_from(Duration::from_secs(SIMTIME_MAX / SIMTIME_ONE_SECOND))
870 .unwrap()
871 )
872 );
873
874 assert_eq!(
877 SimulationTime::try_from(timespec {
878 tv_sec: libc::time_t::MAX,
879 tv_nsec: 999_999_999
880 }),
881 Err(())
882 );
883
884 assert_eq!(
885 SimulationTime::try_from(timespec {
886 tv_sec: 0,
887 tv_nsec: 1_000_000_000
888 }),
889 Err(())
890 );
891 assert_eq!(
892 SimulationTime::try_from(timespec {
893 tv_sec: 0,
894 tv_nsec: -1
895 }),
896 Err(())
897 );
898 assert_eq!(
899 SimulationTime::try_from(timespec {
900 tv_sec: -1,
901 tv_nsec: 0
902 }),
903 Err(())
904 );
905 assert_eq!(
906 SimulationTime::try_from(timespec {
907 tv_sec: -1,
908 tv_nsec: -1
909 }),
910 Err(())
911 );
912 }
913
914 #[test]
915 fn test_c_from_timespec() {
916 use export::simtime_from_timespec;
917 use libc::timespec;
918
919 assert_eq!(
920 simtime_from_timespec(timespec {
921 tv_sec: 0,
922 tv_nsec: 0,
923 }),
924 0
925 );
926 assert_eq!(
927 simtime_from_timespec(timespec {
928 tv_sec: 1,
929 tv_nsec: 2,
930 }),
931 SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_NANOSECOND
932 );
933
934 assert_eq!(
936 simtime_from_timespec(timespec {
937 tv_sec: libc::time_t::MAX,
938 tv_nsec: 999_999_999,
939 }),
940 SIMTIME_INVALID
941 );
942
943 assert_eq!(
944 simtime_from_timespec(timespec {
945 tv_sec: 0,
946 tv_nsec: 1_000_000_000,
947 }),
948 SIMTIME_INVALID
949 );
950 assert_eq!(
951 simtime_from_timespec(timespec {
952 tv_sec: 0,
953 tv_nsec: -1,
954 }),
955 SIMTIME_INVALID
956 );
957 assert_eq!(
958 simtime_from_timespec(timespec {
959 tv_sec: -1,
960 tv_nsec: 0,
961 }),
962 SIMTIME_INVALID
963 );
964 assert_eq!(
965 simtime_from_timespec(timespec {
966 tv_sec: -1,
967 tv_nsec: -1,
968 }),
969 SIMTIME_INVALID
970 );
971 }
972
973 #[test]
974 fn test_to_timespec() {
975 use libc::timespec;
976
977 assert_eq!(
978 timespec::try_from(SimulationTime::ZERO),
979 Ok(timespec {
980 tv_sec: 0,
981 tv_nsec: 0
982 })
983 );
984 assert_eq!(
985 timespec::try_from(SimulationTime::from_secs(1) + SimulationTime::from_nanos(2)),
986 Ok(timespec {
987 tv_sec: 1,
988 tv_nsec: 2
989 })
990 );
991
992 assert_eq!(
993 timespec::try_from(SimulationTime::MAX),
994 Ok(timespec {
995 tv_sec: SimulationTime::MAX.as_secs().try_into().unwrap(),
996 tv_nsec: SimulationTime::MAX.subsec_nanos().into(),
997 })
998 );
999 }
1000
1001 #[test]
1002 fn test_c_to_timespec() {
1003 use export::simtime_to_timespec;
1004 use libc::timespec;
1005
1006 let mut ts = unsafe { std::mem::zeroed() };
1007
1008 assert!(unsafe { simtime_to_timespec(0, &mut ts) });
1009 assert_eq!(
1010 ts,
1011 timespec {
1012 tv_sec: 0,
1013 tv_nsec: 0
1014 }
1015 );
1016
1017 assert!(unsafe {
1018 simtime_to_timespec(SIMTIME_ONE_SECOND + 2 * SIMTIME_ONE_NANOSECOND, &mut ts)
1019 });
1020 assert_eq!(
1021 ts,
1022 timespec {
1023 tv_sec: 1,
1024 tv_nsec: 2
1025 }
1026 );
1027
1028 {
1029 assert!(unsafe { simtime_to_timespec(SIMTIME_MAX, &mut ts) });
1030 let d = Duration::from_nanos(SIMTIME_MAX / SIMTIME_ONE_NANOSECOND);
1031 assert_eq!(
1032 ts,
1033 timespec {
1034 tv_sec: d.as_secs().try_into().unwrap(),
1035 tv_nsec: d.subsec_nanos().into(),
1036 }
1037 );
1038 }
1039 }
1040}