pistonite_cu/str/
osstring.rs1use std::ffi::{OsStr, OsString};
2use std::path::{Path, PathBuf};
3
4use cu::Context as _;
5
6pub trait OsStrExtension {
10 fn as_utf8(&self) -> cu::Result<&str>;
12}
13pub trait OsStrExtensionOwned {
17 fn into_utf8(self) -> cu::Result<String>;
19}
20
21impl OsStrExtension for OsStr {
22 #[inline(always)]
23 fn as_utf8(&self) -> cu::Result<&str> {
24 cu::check!(self.to_str(), "not utf-8: {self:?}")
28 }
29}
30
31impl OsStrExtension for Path {
32 #[inline(always)]
33 fn as_utf8(&self) -> cu::Result<&str> {
34 self.as_os_str().as_utf8()
35 }
36}
37
38impl OsStrExtensionOwned for OsString {
39 #[inline(always)]
40 fn into_utf8(self) -> cu::Result<String> {
41 match self.into_string() {
42 Ok(s) => Ok(s),
43 Err(e) => cu::bail!("not utf-8: {e:?}"),
44 }
45 }
46}
47impl OsStrExtensionOwned for PathBuf {
48 #[inline(always)]
49 fn into_utf8(self) -> cu::Result<String> {
50 self.into_os_string().into_utf8()
51 }
52}
53
54#[cfg(all(test, unix))]
55mod test {
56 use super::*;
57 use std::os::unix::ffi::OsStrExt as _;
58 #[test]
59 fn test_not_utf8() {
60 let s = OsStr::from_bytes(b"hello\xffworld");
61 let result = s.as_utf8().unwrap_err().to_string();
62 assert_eq!(result, r#"not utf-8: "hello\xFFworld""#);
63 let result = Path::new(s).as_utf8().unwrap_err().to_string();
64 assert_eq!(result, r#"not utf-8: "hello\xFFworld""#);
65
66 let s = s.to_owned();
67 let result = s.clone().into_utf8().unwrap_err().to_string();
68 assert_eq!(result, r#"not utf-8: "hello\xFFworld""#);
69 let result = PathBuf::from(s).into_utf8().unwrap_err().to_string();
70 assert_eq!(result, r#"not utf-8: "hello\xFFworld""#);
71 }
72 #[test]
73 fn test_utf8() {
74 let s = OsStr::from_bytes(b"hello world");
75 assert!(s.as_utf8().is_ok());
76 assert!(Path::new(s).as_utf8().is_ok());
77
78 let s = s.to_owned();
79 assert!(s.clone().into_utf8().is_ok());
80 assert!(PathBuf::from(s).into_utf8().is_ok());
81 }
82}
83
84#[cfg(all(test, windows))]
85mod test {
86 use super::*;
87 use std::os::windows::ffi::OsStringExt as _;
88 #[test]
89 fn test_not_utf8() {
90 let wide: &[u16] = &[
91 0x0068, 0x0065, 0x006C, 0x006C, 0x006F, 0xD800, 0x0077, 0x006F, 0x0072, 0x006C, 0x0064,
92 ];
93 let s = OsString::from_wide(wide);
94 let result = s.as_utf8().unwrap_err().to_string();
95 assert_eq!(result, r#"not utf-8: "hello\u{d800}world""#);
96 let result = Path::new(&s).as_utf8().unwrap_err().to_string();
97 assert_eq!(result, r#"not utf-8: "hello\u{d800}world""#);
98
99 let result = s.clone().into_utf8().unwrap_err().to_string();
100 assert_eq!(result, r#"not utf-8: "hello\u{d800}world""#);
101 let result = PathBuf::from(s).into_utf8().unwrap_err().to_string();
102 assert_eq!(result, r#"not utf-8: "hello\u{d800}world""#);
103 }
104 #[test]
105 fn test_utf8() {
106 let wide: &[u16] = &[
107 0x0068, 0x0065, 0x006C, 0x006C, 0x006F, 0x0020, 0x0077, 0x006F, 0x0072, 0x006C, 0x0064,
108 ];
109 let s = OsString::from_wide(wide);
110 assert!(s.as_utf8().is_ok());
111 assert!(Path::new(&s).as_utf8().is_ok());
112 assert!(s.clone().into_utf8().is_ok());
113 assert!(PathBuf::from(s).into_utf8().is_ok());
114 }
115}