pascal_string/
pascal_str.rs

1use ascii::{AsciiChar, AsciiStr};
2use std::ascii::AsciiExt;
3use std::borrow::{Cow, ToOwned};
4use std::cmp::Ordering;
5use std::convert::AsRef;
6use std::error::Error;
7use std::ffi::{CStr, CString};
8use std::iter::{ExactSizeIterator, Iterator};
9use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
10use std::slice::{Iter, IterMut};
11use std::{fmt, isize};
12use ::{PASCAL_STRING_BUF_SIZE, PascalString};
13
14/// A borrowed slice from a `PascalString`. Does not own its data.
15#[derive(Eq, Hash, Ord)]
16pub struct PascalStr {
17    /// The `AsciiStr`, borrowed from the original `PascalString`
18    string: AsciiStr
19}
20
21impl PascalStr {
22    /// Get a pointer to the first byte of the string buffer.
23    #[inline]
24    pub fn as_ptr(&self) -> *const AsciiChar {
25        self.string.as_ptr()
26    }
27
28    /// Get a mutable pointer to the first byte of the string buffer.
29    #[inline]
30    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
31        self.string.as_mut_ptr()
32    }
33
34    /// Get the `PascalStr` as an immutable `&str` reference.
35    #[inline]
36    pub fn as_str(&self) -> &str {
37        self.string.as_str()
38    }
39
40    /// Get this string as a `CStr`.
41    ///
42    /// Returns `Err(InteriorNullError)` if the string contains any interior nulls. If this string is full,
43    /// then a new `CString` will be allocated to hold the trailing null byte.
44    #[inline]
45    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
46        match self.chars().position(|&c| c == AsciiChar::Null) {
47            Some(pos) if pos != (self.len() - 1) => Err(InteriorNullError(pos)),
48            _ if self.is_full() && self.string[PASCAL_STRING_BUF_SIZE - 1] != AsciiChar::Null => {
49                let str_clone = self.to_owned();
50                Ok(Cow::Owned(CString::new(str_clone).unwrap()))
51            }
52            _ => Ok(Cow::Borrowed(CStr::from_bytes_with_nul(self.as_ref()).unwrap()))
53        }
54    }
55
56    /// Returns the number of characters used in the string.
57    #[inline]
58    pub fn len(&self) -> usize {
59        self.string.len()
60    }
61
62    /// Returns true if the string has a length of 0
63    #[inline]
64    pub fn is_empty(&self) -> bool {
65        self.len() == 0
66    }
67
68    /// Returns true if the string has a length of 255.
69    ///
70    /// When this value is true, no more elements can be pushed onto the string.
71    #[inline]
72    pub fn is_full(&self) -> bool {
73        self.len() == PASCAL_STRING_BUF_SIZE
74    }
75
76    /// Get an immutable iterator to the internal character array.
77    #[inline]
78    pub fn chars<'a>(&'a self) -> Chars<'a> {
79        Chars(self.string.as_slice().iter())
80    }
81
82    /// Get a mutable iterator to the internal character array.
83    #[inline]
84    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
85        CharsMut(self.string.as_mut_slice().iter_mut())
86    }
87
88    /// Get an iterator over the lines of the internal character array.
89    #[inline]
90    pub fn lines(&self) -> Lines {
91        Lines {
92            current_index: 0,
93            string: &self
94        }
95    }
96
97    /// Get a character in the string, without checking if the index is within the bounds of `len()`.
98    ///
99    /// This method cannot cause memory unsafety because `index` is bounds checked within the maximum possible
100    /// length of the `PascalStr`, which means that it cannot read uninitialised memory. However, it can give access
101    /// to stale characters if `index` is greater than or equal to `self.len()` or `isize::MAX`, and `self.is_full()`
102    /// is `false`.
103    ///
104    /// # Panics
105    ///
106    /// This method will panic if `index` is larger than `u8::MAX`(255).
107    #[inline]
108    pub fn get_unchecked(&self, index: usize) -> AsciiChar {
109        assert!(index < PASCAL_STRING_BUF_SIZE);
110        let ptr = self.as_ptr();
111        unsafe {
112            *ptr.offset(index as isize)
113        }
114    }
115}
116
117impl<S: AsRef<PascalStr> + ?Sized> PartialEq<S> for PascalStr {
118    fn eq(&self, other: &S) -> bool {
119        let other = other.as_ref();
120        self.string.eq(&other.string)
121    }
122}
123
124impl<S: AsRef<PascalStr> + ?Sized> PartialOrd<S> for PascalStr {
125    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
126        let other = other.as_ref();
127        self.string.partial_cmp(&other.string)
128    }
129}
130
131impl AsciiExt for PascalStr {
132    type Owned = PascalString;
133
134    fn is_ascii(&self) -> bool {
135        true
136    }
137
138    fn to_ascii_uppercase(&self) -> Self::Owned {
139        let bytes: &[u8] = self.as_ref();
140        let mut upper = PascalString::from(bytes).unwrap();
141        upper.make_ascii_uppercase();
142        upper
143    }
144
145    fn to_ascii_lowercase(&self) -> Self::Owned {
146        let bytes: &[u8] = self.as_ref();
147        let mut lower = PascalString::from(bytes).unwrap();
148        lower.make_ascii_lowercase();
149        lower
150    }
151
152    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
153        self.string.eq_ignore_ascii_case(&other.string)
154    }
155
156    fn make_ascii_uppercase(&mut self) {
157        self.string.make_ascii_uppercase()
158    }
159
160    fn make_ascii_lowercase(&mut self) {
161        self.string.make_ascii_lowercase()
162    }
163}
164
165impl fmt::Debug for PascalStr {
166    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
167        fmtr.pad(self.as_ref())
168    }
169}
170
171impl fmt::Display for PascalStr {
172    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
173        fmtr.pad(self.as_ref())
174    }
175}
176
177impl ToOwned for PascalStr {
178    type Owned = PascalString;
179    fn to_owned(&self) -> Self::Owned {
180        PascalString::from(&self.string).unwrap()
181    }
182}
183
184impl AsRef<PascalStr> for PascalStr {
185    fn as_ref(&self) -> &Self {
186        &self
187    }
188}
189
190impl AsRef<str> for PascalStr {
191    fn as_ref(&self) -> &str {
192        self.string.as_ref()
193    }
194}
195
196impl AsRef<[u8]> for PascalStr {
197    fn as_ref(&self) -> &[u8] {
198        self.string.as_ref()
199    }
200}
201
202impl AsRef<AsciiStr> for PascalStr {
203    fn as_ref(&self) -> &AsciiStr {
204        &self.string
205    }
206}
207
208impl AsMut<AsciiStr> for PascalStr {
209    fn as_mut(&mut self) -> &mut AsciiStr {
210        &mut self.string
211    }
212}
213
214impl AsRef<[AsciiChar]> for PascalStr {
215    fn as_ref(&self) -> &[AsciiChar] {
216        self.string.as_ref()
217    }
218}
219
220impl AsMut<[AsciiChar]> for PascalStr {
221    fn as_mut(&mut self) -> &mut [AsciiChar] {
222        self.string.as_mut()
223    }
224}
225
226impl Index<u8> for PascalStr {
227    type Output = AsciiChar;
228    fn index(&self, index: u8) -> &Self::Output {
229        let index = index as usize;
230        assert!(index < self.len());
231        &self.string[index]
232    }
233}
234
235impl IndexMut<u8> for PascalStr {
236    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
237        let index = index as usize;
238        assert!(index < self.len());
239        &mut self.string[index]
240    }
241}
242
243impl Index<usize> for PascalStr {
244    type Output = AsciiChar;
245    fn index(&self, index: usize) -> &Self::Output {
246        assert!(index < self.len());
247        &self.string[index]
248    }
249}
250
251impl IndexMut<usize> for PascalStr {
252    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
253        assert!(index < self.len());
254        &mut self.string[index]
255    }
256}
257
258impl Index<i32> for PascalStr {
259    type Output = AsciiChar;
260    fn index(&self, index: i32) -> &Self::Output {
261        assert!(index >= 0);
262        assert!((index as usize) < self.len());
263        &self.string[index as usize]
264    }
265}
266
267impl IndexMut<i32> for PascalStr {
268    fn index_mut(&mut self, index: i32) -> &mut Self::Output {
269        assert!(index >= 0);
270        assert!((index as usize) < self.len());
271        &mut self.string[index as usize]
272    }
273}
274
275impl Index<RangeFull> for PascalStr {
276    type Output = [AsciiChar];
277    fn index(&self, _: RangeFull) -> &Self::Output {
278        let char_array: &[AsciiChar] = self.string.as_ref();
279        &char_array[..]
280    }
281}
282
283impl IndexMut<RangeFull> for PascalStr {
284    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
285        let char_array: &mut [AsciiChar] = self.string.as_mut();
286        &mut char_array[..]
287    }
288}
289
290impl Index<Range<u8>> for PascalStr {
291    type Output = [AsciiChar];
292    fn index(&self, range: Range<u8>) -> &Self::Output {
293        assert!((range.end as usize) < self.len());
294        let char_array: &[AsciiChar] = self.string.as_ref();
295        &char_array[range.start as usize..range.end as usize]
296    }
297}
298
299impl IndexMut<Range<u8>> for PascalStr {
300    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
301        assert!((range.end as usize) < self.len());
302        let char_array: &mut [AsciiChar] = self.string.as_mut();
303        &mut char_array[range.start as usize..range.end as usize]
304    }
305}
306
307impl Index<Range<usize>> for PascalStr {
308    type Output = [AsciiChar];
309    fn index(&self, range: Range<usize>) -> &Self::Output {
310        assert!(range.end < self.len());
311        let char_array: &[AsciiChar] = self.string.as_ref();
312        &char_array[range.start..range.end]
313    }
314}
315
316impl IndexMut<Range<usize>> for PascalStr {
317    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
318        assert!(range.end < self.len());
319        let char_array: &mut [AsciiChar] = self.string.as_mut();
320        &mut char_array[range.start..range.end]
321    }
322}
323
324impl Index<Range<i32>> for PascalStr {
325    type Output = [AsciiChar];
326    fn index(&self, range: Range<i32>) -> &Self::Output {
327        assert!(range.start >= 0);
328        assert!((range.start as usize) < self.len());
329        assert!(range.end >= 0);
330        assert!((range.end as usize) < self.len());
331        let char_array: &[AsciiChar] = self.string.as_ref();
332        &char_array[range.start as usize..]
333    }
334}
335
336impl IndexMut<Range<i32>> for PascalStr {
337    fn index_mut(&mut self, range: Range<i32>) -> &mut Self::Output {
338        assert!(range.start >= 0);
339        assert!((range.start as usize) < self.len());
340        assert!(range.end >= 0);
341        assert!((range.end as usize) < self.len());
342        let char_array: &mut [AsciiChar] = self.string.as_mut();
343        &mut char_array[range.start as usize..]
344    }
345}
346
347impl Index<RangeFrom<u8>> for PascalStr {
348    type Output = [AsciiChar];
349    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
350        assert!((range.start as usize) < self.len());
351        let char_array: &[AsciiChar] = self.string.as_ref();
352        &char_array[range.start as usize..]
353    }
354}
355
356impl IndexMut<RangeFrom<u8>> for PascalStr {
357    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
358        assert!((range.start as usize) < self.len());
359        let char_array: &mut [AsciiChar] = self.string.as_mut();
360        &mut char_array[range.start as usize..]
361    }
362}
363
364impl Index<RangeFrom<usize>> for PascalStr {
365    type Output = [AsciiChar];
366    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
367        assert!(range.start < self.len());
368        let char_array: &[AsciiChar] = self.string.as_ref();
369        &char_array[range.start..]
370    }
371}
372
373impl IndexMut<RangeFrom<usize>> for PascalStr {
374    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
375        assert!(range.start < self.len());
376        let char_array: &mut [AsciiChar] = self.string.as_mut();
377        &mut char_array[range.start..]
378    }
379}
380
381impl Index<RangeFrom<i32>> for PascalStr {
382    type Output = [AsciiChar];
383    fn index(&self, range: RangeFrom<i32>) -> &Self::Output {
384        assert!(range.start >= 0);
385        assert!((range.start as usize) < self.len());
386        let char_array: &[AsciiChar] = self.string.as_ref();
387        &char_array[range.start as usize..]
388    }
389}
390
391impl IndexMut<RangeFrom<i32>> for PascalStr {
392    fn index_mut(&mut self, range: RangeFrom<i32>) -> &mut Self::Output {
393        assert!(range.start >= 0);
394        assert!((range.start as usize) < self.len());
395        let char_array: &mut [AsciiChar] = self.string.as_mut();
396        &mut char_array[range.start as usize..]
397    }
398}
399
400impl Index<RangeTo<u8>> for PascalStr {
401    type Output = [AsciiChar];
402    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
403        assert!((range.end as usize) < self.len());
404        let char_array: &[AsciiChar] = self.string.as_ref();
405        &char_array[..range.end as usize]
406    }
407}
408
409impl IndexMut<RangeTo<u8>> for PascalStr {
410    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
411        assert!((range.end as usize) < self.len());
412        let char_array: &mut [AsciiChar] = self.string.as_mut();
413        &mut char_array[..range.end as usize]
414    }
415}
416
417impl Index<RangeTo<usize>> for PascalStr {
418    type Output = [AsciiChar];
419    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
420        assert!(range.end < self.len());
421        let char_array: &[AsciiChar] = self.string.as_ref();
422        &char_array[..range.end]
423    }
424}
425
426impl IndexMut<RangeTo<usize>> for PascalStr {
427    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
428        assert!(range.end < self.len());
429        let char_array: &mut [AsciiChar] = self.string.as_mut();
430        &mut char_array[..range.end]
431    }
432}
433
434impl Index<RangeTo<i32>> for PascalStr {
435    type Output = [AsciiChar];
436    fn index(&self, range: RangeTo<i32>) -> &Self::Output {
437        assert!(range.end >= 0);
438        assert!((range.end as usize) < self.len());
439        let char_array: &[AsciiChar] = self.string.as_ref();
440        &char_array[..range.end as usize]
441    }
442}
443
444impl IndexMut<RangeTo<i32>> for PascalStr {
445    fn index_mut(&mut self, range: RangeTo<i32>) -> &mut Self::Output {
446        assert!(range.end >= 0);
447        assert!((range.end as usize) < self.len());
448        let char_array: &mut [AsciiChar] = self.string.as_mut();
449        &mut char_array[..range.end as usize]
450    }
451}
452
453impl<'a> IntoIterator for &'a PascalStr {
454    type Item = &'a AsciiChar;
455    type IntoIter = Chars<'a>;
456    fn into_iter(self) -> Self::IntoIter {
457        self.chars()
458    }
459}
460
461impl<'a> IntoIterator for &'a mut PascalStr {
462    type Item = &'a mut AsciiChar;
463    type IntoIter = CharsMut<'a>;
464    fn into_iter(self) -> Self::IntoIter {
465        self.chars_mut()
466    }
467}
468
469/// An immutable iterator over the buffer of a `PascalStr`.
470#[derive(Debug)]
471pub struct Chars<'a>(Iter<'a, AsciiChar>);
472
473impl<'a> Iterator for Chars<'a> {
474    type Item = &'a AsciiChar;
475
476    #[inline]
477    fn next(&mut self) -> Option<Self::Item> {
478        self.0.next()
479    }
480}
481
482impl<'a> ExactSizeIterator for Chars<'a> {
483    #[inline]
484    fn len(&self) -> usize {
485        self.0.len()
486    }
487}
488
489/// A mutable iterator over the buffer of a `PascalStr`.
490#[derive(Debug)]
491pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);
492
493impl<'a> Iterator for CharsMut<'a> {
494    type Item = &'a mut AsciiChar;
495
496    #[inline]
497    fn next(&mut self) -> Option<Self::Item> {
498        self.0.next()
499    }
500}
501
502impl<'a> ExactSizeIterator for CharsMut<'a> {
503    #[inline]
504    fn len(&self) -> usize {
505        self.0.len()
506    }
507}
508
509/// An iterator over the lines of the internal character array.
510#[derive(Debug)]
511pub struct Lines<'a> {
512    current_index: usize,
513    string: &'a PascalStr
514}
515
516impl<'a> Iterator for Lines<'a> {
517    type Item = &'a AsciiStr;
518
519    fn next(&mut self) -> Option<Self::Item> {
520        let curr_idx = self.current_index;
521        let len = self.string.len();
522        if curr_idx >= len {
523            return None;
524        }
525
526        let mut next_idx = None;
527        for i in curr_idx..len {
528            if self.string[i] == AsciiChar::LineFeed {
529                next_idx = Some(i);
530                break;
531            }
532        }
533        let next_idx = match next_idx {
534            Some(i) => i,
535            None => return None
536        };
537        let line: &AsciiStr = From::from(&self.string[curr_idx..next_idx]);
538
539        self.current_index = next_idx + 1; // skip the linefeed
540        Some(line)
541    }
542}
543
544impl<'a> ExactSizeIterator for Lines<'a> {
545    #[inline]
546    fn len(&self) -> usize {
547        self.string.chars().skip(self.current_index).filter(|&&c| c == AsciiChar::LineFeed).count()
548    }
549}
550
551#[derive(Clone, Debug, Hash)]
552pub struct InteriorNullError(usize);
553
554impl InteriorNullError {
555    #[inline]
556    pub fn interior_null_index(&self) -> usize {
557        self.0
558    }
559}
560
561impl fmt::Display for InteriorNullError {
562    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
563        write!(fmtr, "interior null at {}", self.0)
564    }
565}
566
567impl Error for InteriorNullError {
568    fn description(&self) -> &str {
569        "an interior null was found when creating a CStr from a pascal string"
570    }
571}