1use std::borrow::Cow;
4use std::ffi::CStr;
5use std::str;
6
7pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
16 assert!(!s.is_null());
17
18 unsafe { str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes()) }
19}
20
21pub unsafe fn opt_utf8_cstr<'a>(s: *const libc::c_char) -> Option<&'a str> {
27 if s.is_null() {
28 None
29 } else {
30 unsafe { Some(utf8_cstr(s)) }
31 }
32}
33
34pub unsafe fn utf8_cstr_bounds<'a>(
39 start: *const libc::c_char,
40 end: *const libc::c_char,
41) -> &'a str {
42 unsafe {
43 let len = end.offset_from(start);
44 assert!(len >= 0);
45
46 utf8_cstr_len(start, len as usize)
47 }
48}
49
50pub unsafe fn utf8_cstr_len<'a>(start: *const libc::c_char, len: usize) -> &'a str {
55 unsafe {
56 #[allow(trivial_casts)]
61 let start = start as *const u8;
62 let value_slice = std::slice::from_raw_parts(start, len);
63
64 str::from_utf8_unchecked(value_slice)
65 }
66}
67
68pub unsafe fn cstr<'a>(s: *const libc::c_char) -> Cow<'a, str> {
70 if s.is_null() {
71 return Cow::Borrowed("(null)");
72 }
73 unsafe { CStr::from_ptr(s).to_string_lossy() }
74}
75
76pub fn clamp<T: PartialOrd>(val: T, low: T, high: T) -> T {
77 if val < low {
78 low
79 } else if val > high {
80 high
81 } else {
82 val
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[allow(trivial_casts)]
91 #[test]
92 fn utf8_cstr_works() {
93 unsafe {
94 let hello = b"hello\0".as_ptr() as *const libc::c_char;
95
96 assert_eq!(utf8_cstr(hello), "hello");
97 }
98 }
99
100 #[allow(trivial_casts)]
101 #[test]
102 fn opt_utf8_cstr_works() {
103 unsafe {
104 let hello = b"hello\0".as_ptr() as *const libc::c_char;
105
106 assert_eq!(opt_utf8_cstr(hello), Some("hello"));
107 assert_eq!(opt_utf8_cstr(std::ptr::null()), None);
108 }
109 }
110
111 #[allow(trivial_casts)]
112 #[test]
113 fn utf8_cstr_bounds_works() {
114 unsafe {
115 let hello: *const libc::c_char = b"hello\0" as *const _ as *const _;
116
117 assert_eq!(utf8_cstr_bounds(hello, hello.offset(5)), "hello");
118 assert_eq!(utf8_cstr_bounds(hello, hello), "");
119 }
120 }
121
122 #[allow(trivial_casts)]
123 #[test]
124 fn utf8_cstr_len_works() {
125 unsafe {
126 let hello: *const libc::c_char = b"hello\0" as *const _ as *const _;
127
128 assert_eq!(utf8_cstr_len(hello, 5), "hello");
129 }
130 }
131
132 #[allow(trivial_casts)]
133 #[test]
134 fn cstr_works() {
135 unsafe {
136 let hello: *const libc::c_char = b"hello\0" as *const _ as *const _;
137 let invalid_utf8: *const libc::c_char = b"hello\xff\0" as *const _ as *const _;
138
139 assert_eq!(cstr(hello).as_ref(), "hello");
140 assert_eq!(cstr(std::ptr::null()).as_ref(), "(null)");
141 assert_eq!(cstr(invalid_utf8).as_ref(), "hello\u{fffd}");
142 }
143 }
144}