1extern crate memchr;
7
8use std::os::raw::c_char;
9use std::{slice, str, fmt, ascii, ops, ptr, mem};
10use std::borrow::{Cow,Borrow};
11use std::hash::{Hash, Hasher};
12use std::ffi::{CStr, CString};
13use std::cmp::Ordering;
14use std::error::Error;
15
16use memchr::memchr;
17
18#[derive(Clone, PartialEq, Eq, Debug)]
19pub struct IntoStringError {
20 inner: CFixedString,
21 error: str::Utf8Error,
22}
23
24impl IntoStringError {
25 pub fn into_c_fixed_string(self) -> CFixedString {
30 self.inner
31 }
32
33 pub fn utf8_error(&self) -> str::Utf8Error {
35 self.error
36 }
37}
38
39impl Error for IntoStringError {
40 fn description(&self) -> &str {
41 "C fixed string contained non-utf8 bytes"
42 }
43
44 fn cause(&self) -> Option<&Error> {
45 Some(&self.error)
46 }
47}
48
49impl fmt::Display for IntoStringError {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 self.description().fmt(f)
52 }
53}
54
55pub struct CFixedString {
74 inner: Box<[u8]>
75}
76
77impl CFixedString {
78 pub fn new<T: Into<Box<[u8]>>>(t: T) -> CFixedString {
82 CFixedString { inner: t.into() }
83 }
84 pub fn with_limit(limit: usize) -> CFixedString {
87 CFixedString { inner: vec![0; limit].into_boxed_slice() }
88 }
89 pub unsafe fn from_raw_parts(ptr: *mut c_char, limit: usize) -> CFixedString {
97 CFixedString {
98 inner: Box::from_raw(slice::from_raw_parts_mut(ptr as *mut u8, limit))
99 }
100 }
101 pub fn into_string(self) -> Result<String, IntoStringError> {
105 String::from_utf8(self.into_bytes())
106 .map_err(|e| IntoStringError {
107 error: e.utf8_error(),
108 inner: CFixedString::new(e.into_bytes()),
109 })
110 }
111 pub fn into_c_string(self) -> CString {
115 unsafe { CString::from_vec_unchecked(self.into_bytes()) }
116 }
117 pub fn into_bytes(self) -> Vec<u8> {
121 let l = self.len();
122 let mut v = self.into_inner().into_vec();
123 v.truncate(l);
124 v
125 }
126 pub fn into_bytes_full(self) -> Vec<u8> {
130 self.into_inner().into_vec()
131 }
132 pub fn as_c_fixed_str(&self) -> &CFixedStr {
134 &*self
135 }
136 pub fn as_c_fixed_str_mut(&mut self) -> &mut CFixedStr {
138 &mut *self
139 }
140 pub fn into_boxed_c_fixed_str(self) -> Box<CFixedStr> {
142 unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CFixedStr) }
143 }
144 fn into_inner(self) -> Box<[u8]> {
145 unsafe {
146 let result = ptr::read(&self.inner);
147 mem::forget(self);
148 result
149 }
150 }
151}
152
153impl Drop for CFixedString {
154 #[inline]
155 fn drop(&mut self) {
156 if let Some(c) = self.inner.first_mut() {
157 *c = 0
158 }
159 }
160}
161
162impl ops::Deref for CFixedString {
163 type Target = CFixedStr;
164
165 #[inline]
166 fn deref(&self) -> &CFixedStr {
167 CFixedStr::from_bytes(&self.inner)
168 }
169}
170
171impl ops::DerefMut for CFixedString {
172 #[inline]
173 fn deref_mut(&mut self) -> &mut CFixedStr {
174 CFixedStr::from_bytes_mut(&mut self.inner)
175 }
176}
177
178impl fmt::Debug for CFixedString {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 fmt::Debug::fmt(&**self, f)
181 }
182}
183
184impl Clone for CFixedString {
185 fn clone(&self) -> Self {
186 CFixedString::new(self.as_bytes_full())
187 }
188}
189
190impl Hash for CFixedString {
191 fn hash<H: Hasher>(&self, state: &mut H) {
192 (**self).hash(state);
193 }
194}
195
196impl PartialEq for CFixedString {
197 fn eq(&self, other: &CFixedString) -> bool {
198 (**self).eq(other)
199 }
200}
201
202impl Eq for CFixedString {}
203
204impl PartialOrd for CFixedString {
205 fn partial_cmp(&self, other: &CFixedString) -> Option<Ordering> {
206 (**self).partial_cmp(other)
207 }
208}
209
210impl Ord for CFixedString {
211 fn cmp(&self, other: &CFixedString) -> Ordering {
212 (**self).cmp(other)
213 }
214}
215
216impl From<CFixedString> for Vec<u8> {
217 #[inline]
218 fn from(s: CFixedString) -> Vec<u8> {
219 s.into_bytes()
220 }
221}
222
223pub struct CFixedStr {
242 inner: [u8]
243}
244
245impl CFixedStr {
246 pub unsafe fn from_ptr<'a>(ptr: *const c_char, limit: usize) -> &'a CFixedStr {
248 Self::from_bytes(slice::from_raw_parts(ptr as *const u8, limit))
249 }
250 pub unsafe fn from_mut_ptr<'a>(ptr: *mut c_char, limit: usize) -> &'a mut CFixedStr {
252 Self::from_bytes_mut(slice::from_raw_parts_mut(ptr as *mut u8, limit))
253 }
254 pub fn from_str(s: &str) -> &CFixedStr {
256 Self::from_bytes(s.as_bytes())
257 }
258 pub fn from_bytes(bytes: &[u8]) -> &CFixedStr {
260 unsafe { &*(bytes as *const [u8] as *const CFixedStr) }
261 }
262 pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut CFixedStr {
264 unsafe { &mut *(bytes as *mut [u8] as *mut CFixedStr) }
265 }
266 pub fn from_c_str(c_str: &CStr) -> &CFixedStr {
268 Self::from_bytes(c_str.to_bytes_with_nul())
269 }
270 pub fn as_ptr(&self) -> *const c_char {
277 self.inner.as_ptr() as *const c_char
278 }
279 pub fn as_mut_ptr(&mut self) -> *mut c_char {
286 self.inner.as_mut_ptr() as *mut c_char
287 }
288 pub fn limit(&self) -> usize {
291 self.inner.len()
292 }
293 pub fn len(&self) -> usize {
295 memchr(0, &self.inner).unwrap_or(self.limit())
296 }
297 pub fn to_bytes(&self) -> &[u8] {
300 &self.inner[0..self.len()]
301 }
302 pub fn to_bytes_mut(&mut self) -> &mut [u8] {
305 let l = self.len();
306 &mut self.inner[0..l]
307 }
308 pub fn to_bytes_extended(&self) -> &[u8] {
311 if let Some(l) = memchr(0, &self.inner) {
312 &self.inner[0 .. l+1]
313 } else {
314 &self.inner
315 }
316 }
317 pub fn to_bytes_mut_extended(&mut self) -> &mut [u8] {
320 if let Some(l) = memchr(0, &self.inner) {
321 &mut self.inner[0 .. l+1]
322 } else {
323 &mut self.inner
324 }
325 }
326 pub fn as_bytes_full(&self) -> &[u8] {
329 &self.inner
330 }
331 pub fn as_bytes_mut_full(&mut self) -> &mut [u8] {
334 &mut self.inner
335 }
336 pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
341 str::from_utf8(self.to_bytes())
342 }
343 pub fn to_string_lossy(&self) -> Cow<str> {
348 String::from_utf8_lossy(self.to_bytes())
349 }
350 pub fn to_c_str(&self) -> Cow<CStr> {
356 if let Some(l) = memchr(0, &self.inner) {
357 Cow::Borrowed(unsafe { CStr::from_bytes_with_nul_unchecked(&self.inner[0 .. l+1]) })
358 } else {
359 let mut v = Vec::with_capacity(self.inner.len() + 1);
360 v.extend(&self.inner);
361 Cow::Owned(unsafe { CString::from_vec_unchecked(v) })
362 }
363 }
364 pub fn into_c_fixed_string(self: Box<CFixedStr>) -> CFixedString {
366 let raw = Box::into_raw(self) as *mut [u8];
367 CFixedString { inner: unsafe { Box::from_raw(raw) } }
368 }
369}
370
371impl Hash for CFixedStr {
372 fn hash<H: Hasher>(&self, state: &mut H) {
373 self.to_bytes().hash(state);
374 }
375}
376
377impl fmt::Debug for CFixedStr {
378 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
379 write!(f, "\"")?;
380 for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
381 fmt::Write::write_char(f, byte as char)?;
382 }
383 write!(f, "\"")
384 }
385}
386
387impl<'a> Default for &'a CFixedStr {
388 fn default() -> &'a CFixedStr {
389 const SLICE: &'static [u8] = &[0];
390 CFixedStr::from_bytes(SLICE)
391 }
392}
393
394impl Default for CFixedString {
395 fn default() -> CFixedString {
396 CFixedString { inner: Default::default() }
397 }
398}
399
400impl Borrow<CFixedStr> for CFixedString {
401 #[inline]
402 fn borrow(&self) -> &CFixedStr { self }
403}
404
405impl PartialEq for CFixedStr {
406 fn eq(&self, other: &CFixedStr) -> bool {
407 self.to_bytes().eq(other.to_bytes())
408 }
409}
410
411impl Eq for CFixedStr {}
412
413impl PartialOrd for CFixedStr {
414 fn partial_cmp(&self, other: &CFixedStr) -> Option<Ordering> {
415 self.to_bytes().partial_cmp(&other.to_bytes())
416 }
417}
418
419impl Ord for CFixedStr {
420 fn cmp(&self, other: &CFixedStr) -> Ordering {
421 self.to_bytes().cmp(&other.to_bytes())
422 }
423}
424
425impl ToOwned for CFixedStr {
426 type Owned = CFixedString;
427
428 fn to_owned(&self) -> CFixedString {
429 CFixedString { inner: self.to_bytes_extended().into() }
430 }
431}
432
433impl<'a> From<&'a CFixedStr> for CFixedString {
434 fn from(s: &'a CFixedStr) -> CFixedString {
435 s.to_owned()
436 }
437}
438
439impl ops::Index<ops::RangeFull> for CFixedString {
440 type Output = CFixedStr;
441
442 #[inline]
443 fn index(&self, _index: ops::RangeFull) -> &CFixedStr {
444 self
445 }
446}
447
448impl ops::IndexMut<ops::RangeFull> for CFixedString {
449 #[inline]
450 fn index_mut(&mut self, _index: ops::RangeFull) -> &mut CFixedStr {
451 self
452 }
453}
454
455impl AsRef<CFixedStr> for CFixedStr {
456 #[inline]
457 fn as_ref(&self) -> &CFixedStr {
458 self
459 }
460}
461
462impl AsRef<CFixedStr> for CFixedString {
463 #[inline]
464 fn as_ref(&self) -> &CFixedStr {
465 self
466 }
467}
468
469#[cfg(test)]
470mod tests {
471 use super::*;
472 #[test]
473 fn it_works() {
474 assert_eq!(&CFixedString::new(&b"hello,\0world!\0"[..])[..], CFixedStr::from_str("hello,"));
475 }
476}