1use core::str::FromStr;
8
9use super::FileTime;
10use crate::error::ParseFileTimeError;
11
12impl FileTime {
13 #[inline]
85 pub const fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseFileTimeError> {
86 match u64::from_str_radix(src, radix) {
87 Ok(ft) => Ok(Self::new(ft)),
88 Err(err) => Err(ParseFileTimeError::new(err)),
89 }
90 }
91}
92
93impl FromStr for FileTime {
94 type Err = ParseFileTimeError;
95
96 #[inline]
142 fn from_str(src: &str) -> Result<Self, Self::Err> {
143 Self::from_str_radix(src, 10)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use core::{
150 error::Error,
151 num::{IntErrorKind, ParseIntError},
152 };
153
154 use super::*;
155
156 #[test]
157 fn from_str_radix() {
158 assert_eq!(
159 FileTime::from_str_radix("0", 2).unwrap(),
160 FileTime::NT_TIME_EPOCH
161 );
162 assert_eq!(
163 FileTime::from_str_radix("+0", 2).unwrap(),
164 FileTime::NT_TIME_EPOCH
165 );
166 assert_eq!(
167 FileTime::from_str_radix(
168 "110011101101100011101111011010101001111101000000000000000",
169 2
170 )
171 .unwrap(),
172 FileTime::UNIX_EPOCH
173 );
174 assert_eq!(
175 FileTime::from_str_radix(
176 "+110011101101100011101111011010101001111101000000000000000",
177 2
178 )
179 .unwrap(),
180 FileTime::UNIX_EPOCH
181 );
182 assert_eq!(
183 FileTime::from_str_radix(
184 "111111111111111111111111111111111111111111111111111111111111111",
185 2
186 )
187 .unwrap(),
188 FileTime::SIGNED_MAX
189 );
190 assert_eq!(
191 FileTime::from_str_radix(
192 "+111111111111111111111111111111111111111111111111111111111111111",
193 2
194 )
195 .unwrap(),
196 FileTime::SIGNED_MAX
197 );
198 assert_eq!(
199 FileTime::from_str_radix(
200 "1111111111111111111111111111111111111111111111111111111111111111",
201 2
202 )
203 .unwrap(),
204 FileTime::MAX
205 );
206 assert_eq!(
207 FileTime::from_str_radix(
208 "+1111111111111111111111111111111111111111111111111111111111111111",
209 2
210 )
211 .unwrap(),
212 FileTime::MAX
213 );
214 assert_eq!(
215 FileTime::from_str_radix("0", 8).unwrap(),
216 FileTime::NT_TIME_EPOCH
217 );
218 assert_eq!(
219 FileTime::from_str_radix("+0", 8).unwrap(),
220 FileTime::NT_TIME_EPOCH
221 );
222 assert_eq!(
223 FileTime::from_str_radix("6355435732517500000", 8).unwrap(),
224 FileTime::UNIX_EPOCH
225 );
226 assert_eq!(
227 FileTime::from_str_radix("+6355435732517500000", 8).unwrap(),
228 FileTime::UNIX_EPOCH
229 );
230 assert_eq!(
231 FileTime::from_str_radix("777777777777777777777", 8).unwrap(),
232 FileTime::SIGNED_MAX
233 );
234 assert_eq!(
235 FileTime::from_str_radix("+777777777777777777777", 8).unwrap(),
236 FileTime::SIGNED_MAX
237 );
238 assert_eq!(
239 FileTime::from_str_radix("1777777777777777777777", 8).unwrap(),
240 FileTime::MAX
241 );
242 assert_eq!(
243 FileTime::from_str_radix("+1777777777777777777777", 8).unwrap(),
244 FileTime::MAX
245 );
246 assert_eq!(
247 FileTime::from_str_radix("0", 10).unwrap(),
248 FileTime::NT_TIME_EPOCH
249 );
250 assert_eq!(
251 FileTime::from_str_radix("+0", 10).unwrap(),
252 FileTime::NT_TIME_EPOCH
253 );
254 assert_eq!(
255 FileTime::from_str_radix("116444736000000000", 10).unwrap(),
256 FileTime::UNIX_EPOCH
257 );
258 assert_eq!(
259 FileTime::from_str_radix("+116444736000000000", 10).unwrap(),
260 FileTime::UNIX_EPOCH
261 );
262 assert_eq!(
263 FileTime::from_str_radix("9223372036854775807", 10).unwrap(),
264 FileTime::SIGNED_MAX
265 );
266 assert_eq!(
267 FileTime::from_str_radix("+9223372036854775807", 10).unwrap(),
268 FileTime::SIGNED_MAX
269 );
270 assert_eq!(
271 FileTime::from_str_radix("18446744073709551615", 10).unwrap(),
272 FileTime::MAX
273 );
274 assert_eq!(
275 FileTime::from_str_radix("+18446744073709551615", 10).unwrap(),
276 FileTime::MAX
277 );
278 assert_eq!(
279 FileTime::from_str_radix("0", 16).unwrap(),
280 FileTime::NT_TIME_EPOCH
281 );
282 assert_eq!(
283 FileTime::from_str_radix("+0", 16).unwrap(),
284 FileTime::NT_TIME_EPOCH
285 );
286 assert_eq!(
287 FileTime::from_str_radix("19db1ded53e8000", 16).unwrap(),
288 FileTime::UNIX_EPOCH
289 );
290 assert_eq!(
291 FileTime::from_str_radix("19DB1DED53E8000", 16).unwrap(),
292 FileTime::UNIX_EPOCH
293 );
294 assert_eq!(
295 FileTime::from_str_radix("+19db1ded53e8000", 16).unwrap(),
296 FileTime::UNIX_EPOCH
297 );
298 assert_eq!(
299 FileTime::from_str_radix("+19DB1DED53E8000", 16).unwrap(),
300 FileTime::UNIX_EPOCH
301 );
302 assert_eq!(
303 FileTime::from_str_radix("7fffffffffffffff", 16).unwrap(),
304 FileTime::SIGNED_MAX
305 );
306 assert_eq!(
307 FileTime::from_str_radix("7FFFFFFFFFFFFFFF", 16).unwrap(),
308 FileTime::SIGNED_MAX
309 );
310 assert_eq!(
311 FileTime::from_str_radix("+7fffffffffffffff", 16).unwrap(),
312 FileTime::SIGNED_MAX
313 );
314 assert_eq!(
315 FileTime::from_str_radix("+7FFFFFFFFFFFFFFF", 16).unwrap(),
316 FileTime::SIGNED_MAX
317 );
318 assert_eq!(
319 FileTime::from_str_radix("ffffffffffffffff", 16).unwrap(),
320 FileTime::MAX
321 );
322 assert_eq!(
323 FileTime::from_str_radix("FFFFFFFFFFFFFFFF", 16).unwrap(),
324 FileTime::MAX
325 );
326 assert_eq!(
327 FileTime::from_str_radix("+ffffffffffffffff", 16).unwrap(),
328 FileTime::MAX
329 );
330 assert_eq!(
331 FileTime::from_str_radix("+FFFFFFFFFFFFFFFF", 16).unwrap(),
332 FileTime::MAX
333 );
334 assert_eq!(
335 FileTime::from_str_radix("0", 36).unwrap(),
336 FileTime::NT_TIME_EPOCH
337 );
338 assert_eq!(
339 FileTime::from_str_radix("+0", 36).unwrap(),
340 FileTime::NT_TIME_EPOCH
341 );
342 assert_eq!(
343 FileTime::from_str_radix("vuk7p84etc0", 36).unwrap(),
344 FileTime::UNIX_EPOCH
345 );
346 assert_eq!(
347 FileTime::from_str_radix("VUK7P84ETC0", 36).unwrap(),
348 FileTime::UNIX_EPOCH
349 );
350 assert_eq!(
351 FileTime::from_str_radix("+vuk7p84etc0", 36).unwrap(),
352 FileTime::UNIX_EPOCH
353 );
354 assert_eq!(
355 FileTime::from_str_radix("+VUK7P84ETC0", 36).unwrap(),
356 FileTime::UNIX_EPOCH
357 );
358 assert_eq!(
359 FileTime::from_str_radix("1y2p0ij32e8e7", 36).unwrap(),
360 FileTime::SIGNED_MAX
361 );
362 assert_eq!(
363 FileTime::from_str_radix("1Y2P0IJ32E8E7", 36).unwrap(),
364 FileTime::SIGNED_MAX
365 );
366 assert_eq!(
367 FileTime::from_str_radix("+1y2p0ij32e8e7", 36).unwrap(),
368 FileTime::SIGNED_MAX
369 );
370 assert_eq!(
371 FileTime::from_str_radix("+1Y2P0IJ32E8E7", 36).unwrap(),
372 FileTime::SIGNED_MAX
373 );
374 assert_eq!(
375 FileTime::from_str_radix("3w5e11264sgsf", 36).unwrap(),
376 FileTime::MAX
377 );
378 assert_eq!(
379 FileTime::from_str_radix("3W5E11264SGSF", 36).unwrap(),
380 FileTime::MAX
381 );
382 assert_eq!(
383 FileTime::from_str_radix("+3w5e11264sgsf", 36).unwrap(),
384 FileTime::MAX
385 );
386 assert_eq!(
387 FileTime::from_str_radix("+3W5E11264SGSF", 36).unwrap(),
388 FileTime::MAX
389 );
390 }
391
392 #[test]
393 fn from_str_radix_with_invalid_digit_radix() {
394 assert_eq!(
395 FileTime::from_str_radix("2", 2)
396 .unwrap_err()
397 .source()
398 .unwrap()
399 .downcast_ref::<ParseIntError>()
400 .unwrap()
401 .kind(),
402 &IntErrorKind::InvalidDigit
403 );
404 assert_eq!(
405 FileTime::from_str_radix("8", 8)
406 .unwrap_err()
407 .source()
408 .unwrap()
409 .downcast_ref::<ParseIntError>()
410 .unwrap()
411 .kind(),
412 &IntErrorKind::InvalidDigit
413 );
414 assert_eq!(
415 FileTime::from_str_radix("a", 10)
416 .unwrap_err()
417 .source()
418 .unwrap()
419 .downcast_ref::<ParseIntError>()
420 .unwrap()
421 .kind(),
422 &IntErrorKind::InvalidDigit
423 );
424 assert_eq!(
425 FileTime::from_str_radix("A", 10)
426 .unwrap_err()
427 .source()
428 .unwrap()
429 .downcast_ref::<ParseIntError>()
430 .unwrap()
431 .kind(),
432 &IntErrorKind::InvalidDigit
433 );
434 assert_eq!(
435 FileTime::from_str_radix("g", 16)
436 .unwrap_err()
437 .source()
438 .unwrap()
439 .downcast_ref::<ParseIntError>()
440 .unwrap()
441 .kind(),
442 &IntErrorKind::InvalidDigit
443 );
444 assert_eq!(
445 FileTime::from_str_radix("G", 16)
446 .unwrap_err()
447 .source()
448 .unwrap()
449 .downcast_ref::<ParseIntError>()
450 .unwrap()
451 .kind(),
452 &IntErrorKind::InvalidDigit
453 );
454 }
455
456 #[test]
457 fn from_str_radix_when_empty() {
458 assert_eq!(
459 FileTime::from_str_radix("", 16)
460 .unwrap_err()
461 .source()
462 .unwrap()
463 .downcast_ref::<ParseIntError>()
464 .unwrap()
465 .kind(),
466 &IntErrorKind::Empty
467 );
468 }
469
470 #[test]
471 fn from_str_radix_with_invalid_digit() {
472 assert_eq!(
473 FileTime::from_str_radix("Z", 16)
474 .unwrap_err()
475 .source()
476 .unwrap()
477 .downcast_ref::<ParseIntError>()
478 .unwrap()
479 .kind(),
480 &IntErrorKind::InvalidDigit
481 );
482 assert_eq!(
483 FileTime::from_str_radix("_", 16)
484 .unwrap_err()
485 .source()
486 .unwrap()
487 .downcast_ref::<ParseIntError>()
488 .unwrap()
489 .kind(),
490 &IntErrorKind::InvalidDigit
491 );
492 assert_eq!(
493 FileTime::from_str_radix("-1", 16)
494 .unwrap_err()
495 .source()
496 .unwrap()
497 .downcast_ref::<ParseIntError>()
498 .unwrap()
499 .kind(),
500 &IntErrorKind::InvalidDigit
501 );
502 assert_eq!(
503 FileTime::from_str_radix("+", 16)
504 .unwrap_err()
505 .source()
506 .unwrap()
507 .downcast_ref::<ParseIntError>()
508 .unwrap()
509 .kind(),
510 &IntErrorKind::InvalidDigit
511 );
512 assert_eq!(
513 FileTime::from_str_radix("-", 16)
514 .unwrap_err()
515 .source()
516 .unwrap()
517 .downcast_ref::<ParseIntError>()
518 .unwrap()
519 .kind(),
520 &IntErrorKind::InvalidDigit
521 );
522 assert_eq!(
523 FileTime::from_str_radix(" 0", 16)
524 .unwrap_err()
525 .source()
526 .unwrap()
527 .downcast_ref::<ParseIntError>()
528 .unwrap()
529 .kind(),
530 &IntErrorKind::InvalidDigit
531 );
532 assert_eq!(
533 FileTime::from_str_radix("0 ", 16)
534 .unwrap_err()
535 .source()
536 .unwrap()
537 .downcast_ref::<ParseIntError>()
538 .unwrap()
539 .kind(),
540 &IntErrorKind::InvalidDigit
541 );
542 }
543
544 #[test]
545 fn from_str_radix_when_positive_overflow() {
546 assert_eq!(
547 FileTime::from_str_radix(
548 "10000000000000000000000000000000000000000000000000000000000000000",
549 2
550 )
551 .unwrap_err()
552 .source()
553 .unwrap()
554 .downcast_ref::<ParseIntError>()
555 .unwrap()
556 .kind(),
557 &IntErrorKind::PosOverflow
558 );
559 assert_eq!(
560 FileTime::from_str_radix("2000000000000000000000", 8)
561 .unwrap_err()
562 .source()
563 .unwrap()
564 .downcast_ref::<ParseIntError>()
565 .unwrap()
566 .kind(),
567 &IntErrorKind::PosOverflow
568 );
569 assert_eq!(
570 FileTime::from_str_radix("18446744073709551616", 10)
571 .unwrap_err()
572 .source()
573 .unwrap()
574 .downcast_ref::<ParseIntError>()
575 .unwrap()
576 .kind(),
577 &IntErrorKind::PosOverflow
578 );
579 assert_eq!(
580 FileTime::from_str_radix("10000000000000000", 16)
581 .unwrap_err()
582 .source()
583 .unwrap()
584 .downcast_ref::<ParseIntError>()
585 .unwrap()
586 .kind(),
587 &IntErrorKind::PosOverflow
588 );
589 assert_eq!(
590 FileTime::from_str_radix("3w5e11264sgsg", 36)
591 .unwrap_err()
592 .source()
593 .unwrap()
594 .downcast_ref::<ParseIntError>()
595 .unwrap()
596 .kind(),
597 &IntErrorKind::PosOverflow
598 );
599 assert_eq!(
600 FileTime::from_str_radix("3W5E11264SGSG", 36)
601 .unwrap_err()
602 .source()
603 .unwrap()
604 .downcast_ref::<ParseIntError>()
605 .unwrap()
606 .kind(),
607 &IntErrorKind::PosOverflow
608 );
609 }
610
611 #[test]
612 #[should_panic]
613 fn from_str_radix_when_radix_is_less_than_2() {
614 let _ = FileTime::from_str_radix("0", 1);
615 }
616
617 #[test]
618 #[should_panic]
619 fn from_str_radix_when_radix_is_greater_than_36() {
620 let _ = FileTime::from_str_radix("0", 37);
621 }
622
623 #[test]
624 const fn from_str_radix_is_const_fn() {
625 const _: Result<FileTime, ParseFileTimeError> = FileTime::from_str_radix("0", 2);
626 }
627
628 #[test]
629 fn from_str() {
630 assert_eq!(FileTime::from_str("0").unwrap(), FileTime::NT_TIME_EPOCH);
631 assert_eq!(FileTime::from_str("+0").unwrap(), FileTime::NT_TIME_EPOCH);
632 assert_eq!(
633 FileTime::from_str("116444736000000000").unwrap(),
634 FileTime::UNIX_EPOCH
635 );
636 assert_eq!(
637 FileTime::from_str("+116444736000000000").unwrap(),
638 FileTime::UNIX_EPOCH
639 );
640 assert_eq!(
641 FileTime::from_str("9223372036854775807").unwrap(),
642 FileTime::SIGNED_MAX
643 );
644 assert_eq!(
645 FileTime::from_str("+9223372036854775807").unwrap(),
646 FileTime::SIGNED_MAX
647 );
648 assert_eq!(
649 FileTime::from_str("18446744073709551615").unwrap(),
650 FileTime::MAX
651 );
652 assert_eq!(
653 FileTime::from_str("+18446744073709551615").unwrap(),
654 FileTime::MAX
655 );
656 }
657
658 #[cfg(feature = "std")]
659 #[test_strategy::proptest]
660 fn from_str_roundtrip(#[strategy(r"\+?[0-9]{1,19}")] s: std::string::String) {
661 use proptest::prop_assert_eq;
662
663 let ft = s.parse().unwrap();
664 prop_assert_eq!(FileTime::from_str(&s).unwrap(), FileTime::new(ft));
665 }
666
667 #[test]
668 fn from_str_when_empty() {
669 assert_eq!(
670 FileTime::from_str("")
671 .unwrap_err()
672 .source()
673 .unwrap()
674 .downcast_ref::<ParseIntError>()
675 .unwrap()
676 .kind(),
677 &IntErrorKind::Empty
678 );
679 }
680
681 #[test]
682 fn from_str_with_invalid_digit() {
683 assert_eq!(
684 FileTime::from_str("a")
685 .unwrap_err()
686 .source()
687 .unwrap()
688 .downcast_ref::<ParseIntError>()
689 .unwrap()
690 .kind(),
691 &IntErrorKind::InvalidDigit
692 );
693 assert_eq!(
694 FileTime::from_str("_")
695 .unwrap_err()
696 .source()
697 .unwrap()
698 .downcast_ref::<ParseIntError>()
699 .unwrap()
700 .kind(),
701 &IntErrorKind::InvalidDigit
702 );
703 assert_eq!(
704 FileTime::from_str("-1")
705 .unwrap_err()
706 .source()
707 .unwrap()
708 .downcast_ref::<ParseIntError>()
709 .unwrap()
710 .kind(),
711 &IntErrorKind::InvalidDigit
712 );
713 assert_eq!(
714 FileTime::from_str("+")
715 .unwrap_err()
716 .source()
717 .unwrap()
718 .downcast_ref::<ParseIntError>()
719 .unwrap()
720 .kind(),
721 &IntErrorKind::InvalidDigit
722 );
723 assert_eq!(
724 FileTime::from_str("-")
725 .unwrap_err()
726 .source()
727 .unwrap()
728 .downcast_ref::<ParseIntError>()
729 .unwrap()
730 .kind(),
731 &IntErrorKind::InvalidDigit
732 );
733 assert_eq!(
734 FileTime::from_str(" 0")
735 .unwrap_err()
736 .source()
737 .unwrap()
738 .downcast_ref::<ParseIntError>()
739 .unwrap()
740 .kind(),
741 &IntErrorKind::InvalidDigit
742 );
743 assert_eq!(
744 FileTime::from_str("0 ")
745 .unwrap_err()
746 .source()
747 .unwrap()
748 .downcast_ref::<ParseIntError>()
749 .unwrap()
750 .kind(),
751 &IntErrorKind::InvalidDigit
752 );
753 }
754
755 #[cfg(feature = "std")]
756 #[test_strategy::proptest]
757 fn from_str_with_invalid_digit_roundtrip(
758 #[strategy(r"-[0-9]+|[^0-9]+")] s: std::string::String,
759 ) {
760 use proptest::prop_assert;
761
762 prop_assert!(FileTime::from_str(&s).is_err());
763 }
764
765 #[test]
766 fn from_str_when_positive_overflow() {
767 assert_eq!(
768 FileTime::from_str("18446744073709551616")
769 .unwrap_err()
770 .source()
771 .unwrap()
772 .downcast_ref::<ParseIntError>()
773 .unwrap()
774 .kind(),
775 &IntErrorKind::PosOverflow
776 );
777 }
778}