1extern crate alloc;
6extern crate core;
7
8#[cfg(not(feature = "std"))]
9use alloc::boxed::Box;
10#[cfg(not(feature = "std"))]
11use alloc::vec::Vec;
12use core::fmt;
13use core::fmt::Write;
14use core::mem;
15use core::ops;
16use core::ptr;
17
18#[must_use]
31pub(crate) unsafe fn strlen(buf: usize, len: usize) -> usize {
32 let buf_ptr = buf as *const u8;
33 for i in 0..len {
34 let chr: u8 = unsafe { *buf_ptr.wrapping_add(i) };
35 if chr == 0 {
36 return i;
37 }
38 }
39 len
40}
41
42pub struct CString {
43 inner: Box<[u8]>,
44}
45
46pub struct CStr {
47 inner: [u8],
48}
49
50impl CString {
51 pub fn new<T: Into<Vec<u8>>>(t: T) -> Self {
52 let mut v = t.into();
53 v.reserve_exact(1);
54 v.push(0);
55 Self {
56 inner: v.into_boxed_slice(),
57 }
58 }
59
60 #[must_use]
61 pub fn with_capacity(cap: usize) -> Self {
62 let mut v: Vec<u8> = vec![0; cap];
63 v.reserve_exact(1);
64 v.push(0);
65 Self {
66 inner: v.into_boxed_slice(),
67 }
68 }
69
70 #[must_use]
71 pub fn into_bytes_with_nul(self) -> Vec<u8> {
72 self.into_inner().into_vec()
73 }
74
75 #[must_use]
76 #[inline]
77 pub fn as_bytes(&self) -> &[u8] {
78 &self.inner[..self.inner.len() - 1]
79 }
80
81 #[must_use]
82 #[inline]
83 pub const fn as_bytes_with_nul(&self) -> &[u8] {
84 &self.inner
85 }
86
87 #[must_use]
88 #[inline]
89 #[allow(clippy::borrow_deref_ref)]
90 pub fn as_c_str(&self) -> &CStr {
91 &*self
92 }
93
94 #[must_use]
95 pub fn into_boxed_c_str(self) -> Box<CStr> {
96 unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
97 }
98
99 #[must_use]
100 fn into_inner(self) -> Box<[u8]> {
101 let this = mem::ManuallyDrop::new(self);
102 unsafe { ptr::read(&this.inner) }
103 }
104
105 #[must_use]
106 #[inline]
107 pub const fn len(&self) -> usize {
108 self.as_bytes_with_nul().len() - 1
109 }
110
111 #[must_use]
112 #[inline]
113 pub const fn is_empty(&self) -> bool {
114 self.as_bytes_with_nul().len() == 0
116 }
117
118 #[must_use]
119 pub fn strim_into_bytes(self) -> Vec<u8> {
120 let mut vec = self.into_inner().into_vec();
121 let mut nul_idx = 0;
122 for v in &vec {
123 if v == &0 {
124 break;
125 }
126 nul_idx += 1;
127 }
128 vec.resize(nul_idx, 0);
129 vec
130 }
131
132 #[must_use]
133 pub fn into_bytes(self) -> Vec<u8> {
134 let mut vec = self.into_inner().into_vec();
135 let _nul = vec.pop();
136 vec
137 }
138}
139
140impl CStr {
141 #[must_use]
142 pub const fn as_ptr(&self) -> *const u8 {
143 self.inner.as_ptr()
144 }
145
146 #[inline]
147 #[allow(clippy::missing_const_for_fn)]
148 unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
149 &*(bytes as *const [u8] as *const Self)
150 }
151
152 #[must_use]
153 pub fn to_bytes(&self) -> &[u8] {
154 let bytes = self.to_bytes_with_nul();
155 &bytes[..bytes.len() - 1]
156 }
157
158 #[must_use]
159 #[allow(clippy::borrow_as_ptr)]
160 #[allow(clippy::missing_const_for_fn)]
161 pub fn to_bytes_with_nul(&self) -> &[u8] {
163 unsafe { &*(&self.inner as *const [u8]) }
164 }
165}
166
167impl ops::Deref for CString {
168 type Target = CStr;
169
170 #[inline]
171 fn deref(&self) -> &CStr {
172 unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
173 }
174}
175
176impl Drop for CString {
177 #[inline]
178 fn drop(&mut self) {
179 unsafe {
180 *self.inner.get_unchecked_mut(0) = 0;
181 }
182 }
183}
184
185impl fmt::Debug for CString {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 fmt::Debug::fmt(&**self, f)
188 }
189}
190
191impl fmt::Debug for CStr {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 write!(f, "\"")?;
194 for byte in self.to_bytes() {
195 f.write_char(*byte as char)?;
196 }
197 write!(f, "\"")
198 }
199}
200
201impl From<CString> for Vec<u8> {
202 #[inline]
203 fn from(s: CString) -> Self {
204 s.into_bytes()
205 }
206}