1#[cfg(feature = "alloc")]
2use crate::inner::inner_alloc::Buf;
3use crate::inner::Slice;
4#[allow(unused_imports)]
5use crate::sys_common::{AsInner, FromInner, IntoInner};
6#[cfg(feature = "alloc")]
7use alloc::borrow::Cow;
8#[cfg(feature = "alloc")]
9use alloc::borrow::ToOwned;
10#[cfg(feature = "alloc")]
11use alloc::boxed::Box;
12#[cfg(feature = "alloc")]
13use alloc::rc::Rc;
14#[cfg(feature = "alloc")]
15use alloc::string::String;
16#[cfg(feature = "alloc")]
17use alloc::sync::Arc;
18#[cfg(feature = "alloc")]
19use core::borrow::Borrow;
20use core::hash::{Hash, Hasher};
21use core::str;
22#[allow(unused_imports)]
23use core::{cmp, fmt, ops};
24
25#[cfg(feature = "alloc")]
87#[derive(Clone)]
88pub struct OsString {
89 inner: Buf,
90}
91
92pub struct OsStr {
107 inner: Slice,
108}
109
110#[cfg(feature = "alloc")]
111impl OsString {
112 pub fn new() -> OsString {
122 OsString {
123 inner: Buf::from_string(String::new()),
124 }
125 }
126
127 pub fn as_os_str(&self) -> &OsStr {
139 self
140 }
141
142 pub fn into_string(self) -> Result<String, OsString> {
156 self.inner
157 .into_string()
158 .map_err(|buf| OsString { inner: buf })
159 }
160
161 pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
175 self.inner.push_slice(&s.as_ref().inner)
176 }
177
178 pub fn with_capacity(capacity: usize) -> OsString {
200 OsString {
201 inner: Buf::with_capacity(capacity),
202 }
203 }
204
205 pub fn clear(&mut self) {
219 self.inner.clear()
220 }
221
222 pub fn capacity(&self) -> usize {
235 self.inner.capacity()
236 }
237
238 pub fn reserve(&mut self, additional: usize) {
253 self.inner.reserve(additional)
254 }
255
256 pub fn reserve_exact(&mut self, additional: usize) {
274 self.inner.reserve_exact(additional)
275 }
276
277 pub fn shrink_to_fit(&mut self) {
293 self.inner.shrink_to_fit()
294 }
295
296 pub fn into_boxed_os_str(self) -> Box<OsStr> {
338 let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr;
339 unsafe { Box::from_raw(rw) }
340 }
341}
342
343#[cfg(feature = "alloc")]
344impl From<String> for OsString {
345 fn from(s: String) -> OsString {
351 OsString {
352 inner: Buf::from_string(s),
353 }
354 }
355}
356
357#[cfg(feature = "alloc")]
358impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
359 fn from(s: &T) -> OsString {
360 s.as_ref().to_os_string()
361 }
362}
363
364#[cfg(feature = "alloc")]
365impl ops::Index<ops::RangeFull> for OsString {
366 type Output = OsStr;
367
368 #[inline]
369 fn index(&self, _index: ops::RangeFull) -> &OsStr {
370 OsStr::from_inner(self.inner.as_slice())
371 }
372}
373
374#[cfg(feature = "alloc")]
375impl ops::Deref for OsString {
376 type Target = OsStr;
377
378 #[inline]
379 fn deref(&self) -> &OsStr {
380 &self[..]
381 }
382}
383
384#[cfg(feature = "alloc")]
385impl Default for OsString {
386 #[inline]
388 fn default() -> OsString {
389 OsString::new()
390 }
391}
392
393#[cfg(feature = "alloc")]
394impl fmt::Debug for OsString {
395 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
396 fmt::Debug::fmt(&**self, formatter)
397 }
398}
399
400#[cfg(feature = "alloc")]
401impl PartialEq for OsString {
402 fn eq(&self, other: &OsString) -> bool {
403 self == other
404 }
405}
406
407#[cfg(feature = "alloc")]
408impl PartialEq<str> for OsString {
409 fn eq(&self, other: &str) -> bool {
410 &**self == other
411 }
412}
413
414#[cfg(feature = "alloc")]
415impl PartialEq<OsString> for str {
416 fn eq(&self, other: &OsString) -> bool {
417 &**other == self
418 }
419}
420
421#[cfg(feature = "alloc")]
422impl PartialEq<&str> for OsString {
423 fn eq(&self, other: &&str) -> bool {
424 **self == **other
425 }
426}
427
428#[cfg(feature = "alloc")]
429impl<'a> PartialEq<OsString> for &'a str {
430 fn eq(&self, other: &OsString) -> bool {
431 **other == **self
432 }
433}
434
435#[cfg(feature = "alloc")]
436impl Eq for OsString {}
437
438#[cfg(feature = "alloc")]
439impl PartialOrd for OsString {
440 #[inline]
441 fn partial_cmp(&self, other: &OsString) -> Option<cmp::Ordering> {
442 (&**self).partial_cmp(&**other)
443 }
444 #[inline]
445 fn lt(&self, other: &OsString) -> bool {
446 self < other
447 }
448 #[inline]
449 fn le(&self, other: &OsString) -> bool {
450 self <= other
451 }
452 #[inline]
453 fn gt(&self, other: &OsString) -> bool {
454 self > other
455 }
456 #[inline]
457 fn ge(&self, other: &OsString) -> bool {
458 self >= other
459 }
460}
461
462#[cfg(feature = "alloc")]
463impl PartialOrd<str> for OsString {
464 #[inline]
465 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
466 (&**self).partial_cmp(other)
467 }
468}
469
470#[cfg(feature = "alloc")]
471impl Ord for OsString {
472 #[inline]
473 fn cmp(&self, other: &OsString) -> cmp::Ordering {
474 (&**self).cmp(&**other)
475 }
476}
477
478#[cfg(feature = "alloc")]
479impl Hash for OsString {
480 #[inline]
481 fn hash<H: Hasher>(&self, state: &mut H) {
482 (&**self).hash(state)
483 }
484}
485
486impl OsStr {
487 pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
497 s.as_ref()
498 }
499
500 fn from_inner(inner: &Slice) -> &OsStr {
501 unsafe { &*(inner as *const Slice as *const OsStr) }
502 }
503
504 pub fn to_str(&self) -> Option<&str> {
519 self.inner.to_str()
520 }
521
522 #[cfg(feature = "alloc")]
568 pub fn to_string_lossy(&self) -> Cow<'_, str> {
569 self.inner.to_string_lossy()
570 }
571
572 #[cfg(feature = "alloc")]
584 pub fn to_os_string(&self) -> OsString {
585 OsString {
586 inner: self.inner.to_owned(),
587 }
588 }
589
590 pub fn is_empty(&self) -> bool {
604 self.inner.inner.is_empty()
605 }
606
607 pub fn len(&self) -> usize {
633 self.inner.inner.len()
634 }
635
636 #[cfg(feature = "alloc")]
638 pub fn into_os_string(self: Box<OsStr>) -> OsString {
639 let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
640 OsString {
641 inner: Buf::from_box(boxed),
642 }
643 }
644
645 fn bytes(&self) -> &[u8] {
650 unsafe { &*(&self.inner as *const _ as *const [u8]) }
651 }
652
653 pub fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
654 fmt::Display::fmt(&self.inner, formatter)
655 }
656}
657
658#[cfg(feature = "alloc")]
659impl From<&OsStr> for Box<OsStr> {
660 fn from(s: &OsStr) -> Box<OsStr> {
661 let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
662 unsafe { Box::from_raw(rw) }
663 }
664}
665
666#[cfg(feature = "alloc")]
667impl From<Box<OsStr>> for OsString {
668 fn from(boxed: Box<OsStr>) -> OsString {
670 boxed.into_os_string()
671 }
672}
673
674#[cfg(feature = "alloc")]
675impl From<OsString> for Box<OsStr> {
676 fn from(s: OsString) -> Box<OsStr> {
678 s.into_boxed_os_str()
679 }
680}
681
682#[cfg(feature = "alloc")]
683impl Clone for Box<OsStr> {
684 #[inline]
685 fn clone(&self) -> Self {
686 self.to_os_string().into_boxed_os_str()
687 }
688}
689
690#[cfg(feature = "alloc")]
691impl From<OsString> for Arc<OsStr> {
692 #[inline]
694 fn from(s: OsString) -> Arc<OsStr> {
695 let arc = s.inner.into_arc();
696 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
697 }
698}
699
700#[cfg(feature = "alloc")]
701impl From<&OsStr> for Arc<OsStr> {
702 #[inline]
703 fn from(s: &OsStr) -> Arc<OsStr> {
704 let arc = s.inner.into_arc();
705 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) }
706 }
707}
708
709#[cfg(feature = "alloc")]
710impl From<OsString> for Rc<OsStr> {
711 #[inline]
713 fn from(s: OsString) -> Rc<OsStr> {
714 let rc = s.inner.into_rc();
715 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
716 }
717}
718
719#[cfg(feature = "alloc")]
720impl From<&OsStr> for Rc<OsStr> {
721 #[inline]
722 fn from(s: &OsStr) -> Rc<OsStr> {
723 let rc = s.inner.into_rc();
724 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) }
725 }
726}
727
728#[cfg(feature = "alloc")]
729impl<'a> From<OsString> for Cow<'a, OsStr> {
730 #[inline]
731 fn from(s: OsString) -> Cow<'a, OsStr> {
732 Cow::Owned(s)
733 }
734}
735
736#[cfg(feature = "alloc")]
737impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
738 #[inline]
739 fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
740 Cow::Borrowed(s)
741 }
742}
743
744#[cfg(feature = "alloc")]
745impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
746 #[inline]
747 fn from(s: &'a OsString) -> Cow<'a, OsStr> {
748 Cow::Borrowed(s.as_os_str())
749 }
750}
751
752#[cfg(feature = "alloc")]
753impl<'a> From<Cow<'a, OsStr>> for OsString {
754 #[inline]
755 fn from(s: Cow<'a, OsStr>) -> Self {
756 s.into_owned()
757 }
758}
759
760#[cfg(feature = "alloc")]
761impl Default for Box<OsStr> {
762 fn default() -> Box<OsStr> {
763 let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr;
764 unsafe { Box::from_raw(rw) }
765 }
766}
767
768impl Default for &OsStr {
769 #[inline]
771 fn default() -> Self {
772 OsStr::new("")
773 }
774}
775
776impl PartialEq for OsStr {
777 fn eq(&self, other: &OsStr) -> bool {
778 self.bytes().eq(other.bytes())
779 }
780}
781
782impl PartialEq<str> for OsStr {
783 fn eq(&self, other: &str) -> bool {
784 *self == *OsStr::new(other)
785 }
786}
787
788impl PartialEq<OsStr> for str {
789 fn eq(&self, other: &OsStr) -> bool {
790 *other == *OsStr::new(self)
791 }
792}
793
794impl Eq for OsStr {}
795
796impl PartialOrd for OsStr {
797 #[inline]
798 fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> {
799 self.bytes().partial_cmp(other.bytes())
800 }
801 #[inline]
802 fn lt(&self, other: &OsStr) -> bool {
803 self.bytes().lt(other.bytes())
804 }
805 #[inline]
806 fn le(&self, other: &OsStr) -> bool {
807 self.bytes().le(other.bytes())
808 }
809 #[inline]
810 fn gt(&self, other: &OsStr) -> bool {
811 self.bytes().gt(other.bytes())
812 }
813 #[inline]
814 fn ge(&self, other: &OsStr) -> bool {
815 self.bytes().ge(other.bytes())
816 }
817}
818
819impl PartialOrd<str> for OsStr {
820 #[inline]
821 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
822 self.partial_cmp(OsStr::new(other))
823 }
824}
825
826impl Ord for OsStr {
830 #[inline]
831 fn cmp(&self, other: &OsStr) -> cmp::Ordering {
832 self.bytes().cmp(other.bytes())
833 }
834}
835
836#[cfg(feature = "alloc")]
837macro_rules! impl_cmp {
838 ($lhs:ty, $rhs: ty) => {
839 impl<'a, 'b> PartialEq<$rhs> for $lhs {
840 #[inline]
841 fn eq(&self, other: &$rhs) -> bool {
842 <OsStr as PartialEq>::eq(self, other)
843 }
844 }
845
846 impl<'a, 'b> PartialEq<$lhs> for $rhs {
847 #[inline]
848 fn eq(&self, other: &$lhs) -> bool {
849 <OsStr as PartialEq>::eq(self, other)
850 }
851 }
852
853 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
854 #[inline]
855 fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
856 <OsStr as PartialOrd>::partial_cmp(self, other)
857 }
858 }
859
860 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
861 #[inline]
862 fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
863 <OsStr as PartialOrd>::partial_cmp(self, other)
864 }
865 }
866 };
867}
868
869#[cfg(feature = "alloc")]
870impl_cmp!(OsString, OsStr);
871#[cfg(feature = "alloc")]
872impl_cmp!(OsString, &'a OsStr);
873#[cfg(feature = "alloc")]
874impl_cmp!(Cow<'a, OsStr>, OsStr);
875#[cfg(feature = "alloc")]
876impl_cmp!(Cow<'a, OsStr>, &'b OsStr);
877#[cfg(feature = "alloc")]
878impl_cmp!(Cow<'a, OsStr>, OsString);
879
880impl Hash for OsStr {
881 #[inline]
882 fn hash<H: Hasher>(&self, state: &mut H) {
883 self.bytes().hash(state)
884 }
885}
886
887impl fmt::Debug for OsStr {
888 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
889 fmt::Debug::fmt(&self.inner, formatter)
890 }
891}
892
893#[cfg(feature = "alloc")]
894impl Borrow<OsStr> for OsString {
895 fn borrow(&self) -> &OsStr {
896 &self[..]
897 }
898}
899
900#[cfg(feature = "alloc")]
901impl ToOwned for OsStr {
902 type Owned = OsString;
903 fn to_owned(&self) -> OsString {
904 self.to_os_string()
905 }
906 }
911
912impl AsRef<OsStr> for OsStr {
913 fn as_ref(&self) -> &OsStr {
914 self
915 }
916}
917
918#[cfg(feature = "alloc")]
919impl AsRef<OsStr> for OsString {
920 fn as_ref(&self) -> &OsStr {
921 self
922 }
923}
924
925impl AsRef<OsStr> for str {
926 fn as_ref(&self) -> &OsStr {
927 OsStr::from_inner(Slice::from_str(self))
928 }
929}
930
931#[cfg(feature = "alloc")]
932impl AsRef<OsStr> for String {
933 fn as_ref(&self) -> &OsStr {
934 (&**self).as_ref()
935 }
936}
937
938#[cfg(feature = "alloc")]
939impl FromInner<Buf> for OsString {
940 fn from_inner(buf: Buf) -> OsString {
941 OsString { inner: buf }
942 }
943}
944
945#[cfg(feature = "alloc")]
946impl IntoInner<Buf> for OsString {
947 fn into_inner(self) -> Buf {
948 self.inner
949 }
950}
951
952impl AsInner<Slice> for OsStr {
953 #[inline]
954 fn as_inner(&self) -> &Slice {
955 &self.inner
956 }
957}
958
959#[cfg(feature = "alloc")]
960#[cfg(test)]
961mod tests {
962 use super::*;
963 use crate::sys_common::{AsInner, IntoInner};
964
965 use alloc::rc::Rc;
966 use alloc::sync::Arc;
967
968 #[test]
969 fn test_os_string_with_capacity() {
970 let os_string = OsString::with_capacity(0);
971 assert_eq!(0, os_string.inner.into_inner().capacity());
972
973 let os_string = OsString::with_capacity(10);
974 assert_eq!(10, os_string.inner.into_inner().capacity());
975
976 let mut os_string = OsString::with_capacity(0);
977 os_string.push("abc");
978 assert!(os_string.inner.into_inner().capacity() >= 3);
979 }
980
981 #[test]
982 fn test_os_string_clear() {
983 let mut os_string = OsString::from("abc");
984 assert_eq!(3, os_string.inner.as_inner().len());
985
986 os_string.clear();
987 assert_eq!(&os_string, "");
988 assert_eq!(0, os_string.inner.as_inner().len());
989 }
990
991 #[test]
992 fn test_os_string_capacity() {
993 let os_string = OsString::with_capacity(0);
994 assert_eq!(0, os_string.capacity());
995
996 let os_string = OsString::with_capacity(10);
997 assert_eq!(10, os_string.capacity());
998
999 let mut os_string = OsString::with_capacity(0);
1000 os_string.push("abc");
1001 assert!(os_string.capacity() >= 3);
1002 }
1003
1004 #[test]
1005 fn test_os_string_reserve() {
1006 let mut os_string = OsString::new();
1007 assert_eq!(os_string.capacity(), 0);
1008
1009 os_string.reserve(2);
1010 assert!(os_string.capacity() >= 2);
1011
1012 for _ in 0..16 {
1013 os_string.push("a");
1014 }
1015
1016 assert!(os_string.capacity() >= 16);
1017 os_string.reserve(16);
1018 assert!(os_string.capacity() >= 32);
1019
1020 os_string.push("a");
1021
1022 os_string.reserve(16);
1023 assert!(os_string.capacity() >= 33)
1024 }
1025
1026 #[test]
1027 fn test_os_string_reserve_exact() {
1028 let mut os_string = OsString::new();
1029 assert_eq!(os_string.capacity(), 0);
1030
1031 os_string.reserve_exact(2);
1032 assert!(os_string.capacity() >= 2);
1033
1034 for _ in 0..16 {
1035 os_string.push("a");
1036 }
1037
1038 assert!(os_string.capacity() >= 16);
1039 os_string.reserve_exact(16);
1040 assert!(os_string.capacity() >= 32);
1041
1042 os_string.push("a");
1043
1044 os_string.reserve_exact(16);
1045 assert!(os_string.capacity() >= 33)
1046 }
1047
1048 #[test]
1049 fn test_os_string_default() {
1050 let os_string: OsString = Default::default();
1051 assert_eq!("", &os_string);
1052 }
1053
1054 #[test]
1055 fn test_os_str_is_empty() {
1056 let mut os_string = OsString::new();
1057 assert!(os_string.is_empty());
1058
1059 os_string.push("abc");
1060 assert!(!os_string.is_empty());
1061
1062 os_string.clear();
1063 assert!(os_string.is_empty());
1064 }
1065
1066 #[test]
1067 fn test_os_str_len() {
1068 let mut os_string = OsString::new();
1069 assert_eq!(0, os_string.len());
1070
1071 os_string.push("abc");
1072 assert_eq!(3, os_string.len());
1073
1074 os_string.clear();
1075 assert_eq!(0, os_string.len());
1076 }
1077
1078 #[test]
1079 fn test_os_str_default() {
1080 let os_str: &OsStr = Default::default();
1081 assert_eq!("", os_str);
1082 }
1083
1084 #[test]
1085 fn into_boxed() {
1086 let orig = "Hello, world!";
1087 let os_str = OsStr::new(orig);
1088 let boxed: Box<OsStr> = Box::from(os_str);
1089 let os_string = os_str.to_owned().into_boxed_os_str().into_os_string();
1090 assert_eq!(os_str, &*boxed);
1091 assert_eq!(&*boxed, &*os_string);
1092 assert_eq!(&*os_string, os_str);
1093 }
1094
1095 #[test]
1096 fn boxed_default() {
1097 let boxed = <Box<OsStr>>::default();
1098 assert!(boxed.is_empty());
1099 }
1100
1101 #[test]
1102 fn into_rc() {
1103 let orig = "Hello, world!";
1104 let os_str = OsStr::new(orig);
1105 let rc: Rc<OsStr> = Rc::from(os_str);
1106 let arc: Arc<OsStr> = Arc::from(os_str);
1107
1108 assert_eq!(&*rc, os_str);
1109 assert_eq!(&*arc, os_str);
1110
1111 let rc2: Rc<OsStr> = Rc::from(os_str.to_owned());
1112 let arc2: Arc<OsStr> = Arc::from(os_str.to_owned());
1113
1114 assert_eq!(&*rc2, os_str);
1115 assert_eq!(&*arc2, os_str);
1116 }
1117}