pascal_string/
pascal_string.rs

1use ascii::{AsAsciiStrError, AsciiChar, AsciiStr, AsciiString, ToAsciiChar, ToAsciiCharError};
2use std::ascii::AsciiExt;
3use std::borrow::{Borrow, BorrowMut};
4use std::cmp::Ordering;
5use std::convert::{AsRef, AsMut, From, Into};
6use std::error::Error;
7use std::hash::{Hash, Hasher};
8use std::iter::{ExactSizeIterator, FromIterator, IntoIterator};
9use std::ops::{Deref, DerefMut};
10use std::str::{self, FromStr};
11use std::{fmt, mem, ptr, slice};
12use ::{PascalStr, PASCAL_STRING_BUF_SIZE};
13
14/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
15/// the first byte storing the length.
16///
17/// This string type uses Ascii encoding.
18#[derive(Eq)]
19pub struct PascalString {
20    /// The length of this string.
21    len: u8,
22    /// The characters of this string, encoded as an ascii array.
23    chars: [AsciiChar; PASCAL_STRING_BUF_SIZE]
24}
25
26impl PascalString {
27    /// Creates a new, empty `PascalString`.
28    #[inline]
29    pub fn new() -> Self {
30        Default::default()
31    }
32
33    /// Create a new `PascalString` from its constituent parts: `string_len` and `char_array`.
34    ///
35    /// Returns an `Err` if `char_array` is not valid Ascii.
36    #[inline]
37    pub fn from_fixed_ascii_array<C>(string_len: u8, char_array: [C; PASCAL_STRING_BUF_SIZE])
38                                     -> Result<Self, PascalStringCreateError>
39        where C: ToAsciiChar + Clone {
40        let mut pstring = PascalString::new();
41        pstring.len = string_len;
42        for i in 0..(pstring.len as usize) {
43            pstring[i] = try!(AsciiChar::from(char_array[i].clone()));
44        }
45        Ok(pstring)
46    }
47
48    /// Create a new `PascalString` using the contents of `bytes`.
49    ///
50    /// Returns an `Err` if `bytes` is longer than 255 characters, or it does not contain
51    /// Ascii encoded characters.
52    #[inline]
53    pub fn from<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PascalStringCreateError> {
54        PascalString::_from(bytes.as_ref())
55    }
56
57    fn _from(bytes: &[u8]) -> Result<Self, PascalStringCreateError>  {
58        let len = bytes.len();
59        if len > PASCAL_STRING_BUF_SIZE {
60            return Err(PascalStringCreateError::InputTooLong);
61        }
62        // Perform ascii check
63        let ascii = try!(AsciiStr::from_ascii(bytes));
64
65        let mut string = PascalString::new();
66        string.len = len as u8;
67        for i in 0..len {
68            string[i] = ascii[i];
69        }
70        Ok(string)
71    }
72
73    /// Push an ascii convertible character onto this string.
74    ///
75    /// # Panics
76    ///
77    /// Panics if the string is full, of if the `character` is not a valid ascii character.
78    #[inline]
79    pub fn push<C: ToAsciiChar>(&mut self, character: C) {
80        self.try_push(character).unwrap();
81    }
82
83    /// Attempt to push an ascii convertible character onto the end of this `PascalString`.
84    ///
85    /// Returns `Err(_)` if the character cannot be pushed because this `PascalString` is full, or if
86    /// `character` is not a valid ascii character.
87    #[inline]
88    pub fn try_push<C: ToAsciiChar>(&mut self, character: C) -> Result<(), PascalStringAppendError> {
89        self._try_push(try!(AsciiChar::from(character)))
90    }
91
92    fn _try_push(&mut self, ch: AsciiChar) -> Result<(), PascalStringAppendError> {
93        if self.is_full() {
94            return Err(PascalStringAppendError::NoRoom)
95        }
96        self.len += 1;
97        let idx = self.len - 1;
98        self[idx] = ch;
99        self.set_trailing_byte_to_null();
100        Ok(())
101    }
102
103    /// Append a given string slice onto the end of this `PascalString`.
104    ///
105    /// # Panics
106    ///
107    /// Panics if the string cannot be pushed to because this `PascalString` is full.
108    #[inline]
109    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
110        self.try_push_str(s).unwrap();
111    }
112
113    /// Attempt to append a given string slice onto the end of this `PascalString`.
114    ///
115    /// Returns `Err(_)` if the string cannot be pushed because this `PascalString` is full.
116    #[inline]
117    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringAppendError> {
118        self._try_push_str(s.as_ref())
119    }
120
121    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
122        let ascii: &[AsciiChar] = try!(AsciiStr::from_ascii(s)).as_ref();
123        let slen = self.len();
124        let alen = ascii.len();
125        if slen + alen > PASCAL_STRING_BUF_SIZE {
126            return Err(PascalStringAppendError::NoRoom);
127        }
128        for i in 0..alen {
129            self.chars[(i + slen)] = ascii[i];
130        }
131        self.len += alen as u8;
132        Ok(())
133    }
134
135    /// Removes the last character from the string buffer and returns it.
136    ///
137    /// Returns `None` if this `PascalString` is empty.
138    pub fn pop(&mut self) -> Option<AsciiChar> {
139        if self.is_empty() {
140            return None;
141        }
142        let c = self.chars[self.len as usize];
143        self.len -= 1;
144        self.set_trailing_byte_to_null();
145        Some(c)
146    }
147
148    /// Remove a character from the `AsciiString` at `index`.
149    ///
150    /// # Panics
151    ///
152    /// Panics if `index` is larger than `self.len()`, or if `self.is_empty()` is `true`.
153    pub fn remove(&mut self, index: u8) -> AsciiChar {
154        assert!(self.len > index);
155        assert!(!self.is_empty());
156        let len = self.len as usize;
157        let index = index as usize;
158        let c = self[index];
159        // Shift everything to the right of the removed character to the left to cover up the hole
160        // left.
161        unsafe {
162            let ptr = self.as_mut_ptr().offset(index as isize);
163            ptr::copy(ptr.offset(1), ptr, len - index - 1);
164        }
165        self.len -= 1;
166        self.set_trailing_byte_to_null();
167        c
168    }
169
170    /// Insert a character into the `AsciiString` at `index`.
171    ///
172    /// # Panics
173    ///
174    /// Panics if `index` is larger than `self.len()`, or if the `PascalString` is full.
175    #[inline]
176    pub fn insert<C: ToAsciiChar>(&mut self, ch: C, index: u8) {
177        self._insert(AsciiChar::from(ch).unwrap(), index)
178    }
179
180    fn _insert(&mut self, ch: AsciiChar, index: u8) {
181        assert!(self.len > index);
182        assert!(!self.is_full());
183        let len = self.len as usize;
184        let index = index as isize;
185        // Shift everything to the right of `index` 1 place to the right to make room for the
186        // new character.
187        unsafe {
188            let ptr = self.as_mut_ptr().offset(index);
189            ptr::copy(ptr, ptr.offset(1), len - index.abs() as usize - 1);
190        }
191        self[len] = ch;
192        self.len += 1;
193        self.set_trailing_byte_to_null();
194    }
195
196    /// Truncates this String, removing all contents.
197    ///
198    /// Does not zero the values of the string.
199    #[inline]
200    pub fn clear(&mut self) {
201        self.len = 0;
202        self.set_trailing_byte_to_null();
203    }
204
205    /// Consumes this `PascalString`, and returns its inner state as a `[u8; 256]`, where the first byte
206    /// is the length.
207    ///
208    /// Note that if the string has been truncated, bytes beyond the end of the string will not have been
209    /// zeroed.
210    #[inline]
211    pub fn to_array(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
212        self.into()
213    }
214
215    /// Sets the byte beyond the end of `len` to `AsciiChar::Null`, if this `PascalString` isn't full.
216    ///
217    /// Used to ensure that `PascalStr::as_cstr()` works correctly.
218    #[inline]
219    fn set_trailing_byte_to_null(&mut self) {
220        if !self.is_full() {
221            self.chars[self.len as usize] = AsciiChar::Null;
222        }
223    }
224}
225
226impl Default for PascalString {
227    #[inline]
228    fn default() -> Self {
229        PascalString {
230            len: 0,
231            chars: [AsciiChar::Null; PASCAL_STRING_BUF_SIZE]
232        }
233    }
234}
235
236impl Clone for PascalString {
237    fn clone(&self) -> Self {
238        let mut clone = PascalString::default();
239        clone.len = self.len;
240        unsafe {
241            ptr::copy_nonoverlapping(&self.chars, &mut clone.chars, PASCAL_STRING_BUF_SIZE);
242        }
243        clone
244    }
245}
246
247impl<S: AsRef<PascalStr> + ?Sized> PartialEq<S> for PascalString {
248    fn eq(&self, other: &S) -> bool {
249        let other = other.as_ref();
250        if self.len() != other.len() {
251            return false;
252        }
253        self.chars().zip(other.chars()).all(|(c0, c1)| c0 == c1)
254    }
255}
256
257impl Ord for PascalString {
258    #[inline]
259    fn cmp(&self, other: &Self) -> Ordering {
260        let ascii0: &[AsciiChar] = &self.chars;
261        let ascii1: &[AsciiChar] = &other.chars;
262        ascii0.cmp(ascii1)
263    }
264}
265
266impl<S: AsRef<PascalStr> + ?Sized> PartialOrd<S> for PascalString {
267    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
268        let other: &AsciiStr = other.as_ref().as_ref();
269        let self_asciistr: &AsciiStr = self.as_ref();
270        self_asciistr.partial_cmp(&other)
271    }
272}
273
274impl Hash for PascalString {
275    #[inline]
276    fn hash<H: Hasher>(&self, state: &mut H) {
277        state.write_u8(self.len);
278        state.write(self.as_ref());
279    }
280}
281
282impl AsciiExt for PascalString {
283    type Owned = Self;
284
285    fn is_ascii(&self) -> bool {
286        true
287    }
288
289    fn to_ascii_uppercase(&self) -> Self::Owned {
290        let mut upper = self.clone();
291        upper.make_ascii_uppercase();
292        upper
293    }
294
295    fn to_ascii_lowercase(&self) -> Self::Owned {
296        let mut lower = self.clone();
297        lower.make_ascii_lowercase();
298        lower
299    }
300
301    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
302        self.chars().zip(other.chars()).all(|(c0, c1)| c0.eq_ignore_ascii_case(&c1))
303    }
304
305    #[inline]
306    fn make_ascii_uppercase(&mut self) {
307        for c in self.chars_mut() {
308            c.make_ascii_uppercase();
309        }
310    }
311
312    #[inline]
313    fn make_ascii_lowercase(&mut self) {
314        for c in self.chars_mut() {
315            c.make_ascii_lowercase();
316        }
317    }
318}
319
320impl fmt::Debug for PascalString {
321    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
322        write!(fmtr, "{}", self)
323    }
324}
325
326impl fmt::Display for PascalString {
327    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
328        fmtr.pad(self.as_ref())
329    }
330}
331
332impl Deref for PascalString {
333    type Target = PascalStr;
334    fn deref(&self) -> &Self::Target {
335        let ascii_str: &[AsciiChar] = self.as_ref();
336        unsafe {
337            mem::transmute(ascii_str)
338        }
339    }
340}
341
342impl DerefMut for PascalString {
343    fn deref_mut(&mut self) -> &mut Self::Target {
344        let ascii_str: &mut [AsciiChar] = self.as_mut();
345        unsafe {
346            mem::transmute(ascii_str)
347        }
348    }
349}
350
351impl AsRef<PascalStr> for PascalString {
352    fn as_ref(&self) -> &PascalStr {
353        self.deref()
354    }
355}
356
357impl AsRef<str> for PascalString {
358    fn as_ref(&self) -> &str {
359        let bytes: &[u8] = self.as_ref();
360        str::from_utf8(bytes).unwrap()
361    }
362}
363
364impl AsRef<[u8]> for PascalString {
365    fn as_ref(&self) -> &[u8] {
366        unsafe {
367            slice::from_raw_parts(self.chars.as_ptr() as *const u8, self.len as usize)
368        }
369    }
370}
371
372impl AsRef<AsciiStr> for PascalString {
373    fn as_ref(&self) -> &AsciiStr {
374        let bytes: &[u8] = self.as_ref();
375        AsciiStr::from_ascii(bytes).unwrap()
376    }
377}
378
379impl AsRef<[AsciiChar]> for PascalString {
380    fn as_ref(&self) -> &[AsciiChar] {
381        unsafe {
382            slice::from_raw_parts(self.chars.as_ptr(), self.len as usize)
383        }
384    }
385}
386
387impl AsMut<[AsciiChar]> for PascalString {
388    fn as_mut(&mut self) -> &mut [AsciiChar] {
389        unsafe {
390            slice::from_raw_parts_mut(self.chars.as_mut_ptr(), self.len as usize)
391        }
392    }
393}
394
395impl Borrow<PascalStr> for PascalString {
396    #[inline]
397    fn borrow(&self) -> &PascalStr {
398        self.deref()
399    }
400}
401
402impl BorrowMut<PascalStr> for PascalString {
403    #[inline]
404    fn borrow_mut(&mut self) -> &mut PascalStr {
405        self.deref_mut()
406    }
407}
408
409impl Borrow<str> for PascalString {
410    #[inline]
411    fn borrow(&self) -> &str {
412        self.as_ref()
413    }
414}
415
416impl Borrow<[u8]> for PascalString {
417    #[inline]
418    fn borrow(&self) -> &[u8] {
419        self.as_ref()
420    }
421}
422
423impl Borrow<AsciiStr> for PascalString {
424    #[inline]
425    fn borrow(&self) -> &AsciiStr {
426        self.as_ref()
427    }
428}
429
430impl Borrow<[AsciiChar]> for PascalString {
431    #[inline]
432    fn borrow(&self) -> &[AsciiChar] {
433        self.as_ref()
434    }
435}
436
437impl BorrowMut<[AsciiChar]> for PascalString {
438    #[inline]
439    fn borrow_mut(&mut self) -> &mut [AsciiChar] {
440        self.as_mut()
441    }
442}
443
444impl Into<[u8; PASCAL_STRING_BUF_SIZE + 1]> for PascalString {
445    fn into(self) -> [u8; PASCAL_STRING_BUF_SIZE + 1] {
446        let mut array = [0u8; PASCAL_STRING_BUF_SIZE + 1];
447        array[0] = self.len;
448        unsafe {
449            let chars_ptr = &self.chars as *const _ as *const [u8; PASCAL_STRING_BUF_SIZE];
450            let array_ptr = (&mut array as *mut _).offset(1) as *mut [u8; PASCAL_STRING_BUF_SIZE];
451            ptr::copy_nonoverlapping(chars_ptr, array_ptr, PASCAL_STRING_BUF_SIZE);
452        }
453        array
454    }
455}
456
457impl Into<String> for PascalString {
458    #[inline]
459    fn into(self) -> String {
460        String::from_utf8_lossy(self.as_ref()).into_owned()
461    }
462}
463
464impl Into<Vec<u8>> for PascalString {
465    fn into(self) -> Vec<u8> {
466        let mut v = Vec::with_capacity(self.len());
467        v.extend_from_slice(self.as_ref());
468        v
469    }
470}
471
472impl Into<Vec<AsciiChar>> for PascalString {
473    fn into(self) -> Vec<AsciiChar> {
474        let mut v = Vec::with_capacity(self.len());
475        v.extend_from_slice(self.as_ref());
476        v
477    }
478}
479
480impl Into<AsciiString> for PascalString {
481    fn into(self) -> AsciiString {
482        AsciiString::from_ascii(self).unwrap()
483    }
484}
485
486impl FromStr for PascalString {
487    type Err = PascalStringCreateError;
488    fn from_str(s: &str) -> Result<Self, Self::Err> {
489        PascalString::from(s)
490    }
491}
492
493impl FromIterator<AsciiChar> for PascalString {
494    fn from_iter<I: IntoIterator<Item = AsciiChar>>(iter: I) -> Self {
495        let mut iter = iter.into_iter();
496        let mut pstring = PascalString::new();
497        while let Some(ch) = iter.next() {
498            // We know that the characters are valid ascii, and it's probably kinder to drop characters
499            // past the 255th index than panic in this method.
500            let _ = pstring.try_push(ch);
501        }
502        pstring
503    }
504}
505
506impl IntoIterator for PascalString {
507    type Item = AsciiChar;
508    type IntoIter = IntoChars;
509    fn into_iter(self) -> Self::IntoIter {
510        IntoChars(self)
511    }
512}
513
514/// An iterator over the buffer of a `PascalString`. Has ownership of the iterated `PascalString`.
515#[derive(Debug)]
516pub struct IntoChars(PascalString);
517
518impl Iterator for IntoChars {
519    type Item = AsciiChar;
520    fn next(&mut self) -> Option<Self::Item> {
521        if !self.0.is_empty() {
522            Some(self.0.remove(0))
523        } else {
524            None
525        }
526    }
527}
528
529impl ExactSizeIterator for IntoChars {
530    fn len(&self) -> usize {
531        self.0.len()
532    }
533}
534
535/// Indicates the range of errors which can occur from creating a new `PascalString`.
536#[derive(Debug, PartialEq)]
537pub enum PascalStringCreateError {
538    /// The data provided to the constructor was larger than the `PascalString` could store.
539    InputTooLong,
540    /// The data provided was not correctly encoded as ascii.
541    NotValidAscii(AsciiError)
542}
543
544impl fmt::Display for PascalStringCreateError {
545    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
546        match *self {
547            PascalStringCreateError::InputTooLong => fmtr.pad(self.description()),
548            PascalStringCreateError::NotValidAscii(ref e) => write!(fmtr, "{}: {}", self.description(), e)
549        }
550    }
551}
552
553impl Error for PascalStringCreateError {
554    fn description(&self) -> &str {
555        match *self {
556            PascalStringCreateError::InputTooLong => "the input data is longer than what a PascalString can store",
557            PascalStringCreateError::NotValidAscii(_) =>"could not convert input data to ascii"
558        }
559    }
560
561    fn cause(&self) -> Option<&Error> {
562        if let PascalStringCreateError::NotValidAscii(ref e) = *self {
563            Some(e)
564        } else {
565            None
566        }
567    }
568}
569
570impl<E: Into<AsciiError>> From<E> for PascalStringCreateError {
571    #[inline]
572    fn from(e: E) -> Self {
573        PascalStringCreateError::NotValidAscii(e.into())
574    }
575}
576
577/// Indicates the range of errors which can occur from appending string data to a `PascalString`.
578#[derive(Debug, PartialEq)]
579pub enum PascalStringAppendError {
580    /// There is no room to store the appended data.
581    NoRoom,
582    /// The data provided was not correctly encoded as ascii.
583    NotValidAscii(AsciiError)
584}
585
586impl fmt::Display for PascalStringAppendError {
587    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
588        match *self {
589            PascalStringAppendError::NoRoom => fmtr.pad(self.description()),
590            PascalStringAppendError::NotValidAscii(ref e) => write!(fmtr, "{}: {}", self.description(), e)
591        }
592    }
593}
594
595impl Error for PascalStringAppendError {
596    fn description(&self) -> &str {
597        match *self {
598            PascalStringAppendError::NoRoom => "there is no space left in the string to append the data",
599            PascalStringAppendError::NotValidAscii(_) =>"could not convert string to ascii"
600        }
601    }
602
603    fn cause(&self) -> Option<&Error> {
604        if let PascalStringAppendError::NotValidAscii(ref e) = *self {
605            Some(e)
606        } else {
607            None
608        }
609    }
610}
611
612impl<E: Into<AsciiError>> From<E> for PascalStringAppendError {
613    #[inline]
614    fn from(e: E) -> Self {
615        PascalStringAppendError::NotValidAscii(e.into())
616    }
617}
618
619/// An error type which abstracts over ascii conversion errors.
620#[derive(Debug, PartialEq)]
621pub enum AsciiError {
622    /// A character was not encoded as ascii.
623    Char(ToAsciiCharError),
624    /// A string was not encoded as ascii.
625    Str(AsAsciiStrError)
626}
627
628impl fmt::Display for AsciiError {
629    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
630        match *self {
631            AsciiError::Char(ref e) => write!(fmtr, "{}: {}", self.description(), e),
632            AsciiError::Str(ref e) => write!(fmtr, "{}: {}", self.description(), e)
633        }
634    }
635}
636
637impl Error for AsciiError {
638    fn description(&self) -> &str {
639        match *self {
640            AsciiError::Char(_) => "could not convert character to ascii: {}",
641            AsciiError::Str(_) =>"could not convert string to ascii: {}"
642        }
643    }
644
645    fn cause(&self) -> Option<&Error> {
646        match *self {
647            AsciiError::Char(ref e) => Some(e),
648            AsciiError::Str(ref e) => Some(e)
649        }
650    }
651}
652
653impl From<ToAsciiCharError> for AsciiError {
654    #[inline]
655    fn from(e: ToAsciiCharError) -> Self {
656        AsciiError::Char(e)
657    }
658}
659
660impl From<AsAsciiStrError> for AsciiError {
661    #[inline]
662    fn from(e: AsAsciiStrError) -> Self {
663        AsciiError::Str(e)
664    }
665}