diff options
Diffstat (limited to 'src/fixed_string')
-rw-r--r-- | src/fixed_string/mod.rs | 298 | ||||
-rw-r--r-- | src/fixed_string/test.rs | 43 |
2 files changed, 0 insertions, 341 deletions
diff --git a/src/fixed_string/mod.rs b/src/fixed_string/mod.rs deleted file mode 100644 index b0342d3..0000000 --- a/src/fixed_string/mod.rs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2024 Gabriel Bjørnager Jensen. -// -// This file is part of bzipper. -// -// bzipper is free software: you can redistribute -// it and/or modify it under the terms of the GNU -// Lesser General Public License as published by -// the Free Software Foundation, either version 3 -// of the License, or (at your option) any later -// version. -// -// bzipper is distributed in the hope that it will -// be useful, but WITHOUT ANY WARRANTY; without -// even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Less- -// er General Public License along with bzipper. If -// not, see <https://www.gnu.org/licenses/>. - -#[cfg(test)] -mod test; - -use crate::{ - Deserialise, - Dstream, - Error, - FixedStringIter, - Serialise, - Sstream, -}; - -use alloc::string::String; -use core::cmp::Ordering; -use core::fmt::{Debug, Display, Formatter}; -use core::ops::{Index, IndexMut}; -use core::str::FromStr; - -/// Owned string with maximum size. -/// -/// This is in contrast to [String], which has no size limit is practice, and [str], which is unsized. -#[derive(Clone)] -pub struct FixedString<const N: usize> { - buf: [char; N], - len: usize, -} - -impl<const N: usize> FixedString<N> { - /// Constructs a new fixed string. - /// - /// The contents of the provided string are copied into the internal buffer. - /// All residual characters are instanced as U+0000 `NULL`. - /// - /// # Errors - /// - /// If the given string `s` cannot fit into `N` characters, an [`ArrayTooShort`](Error::ArrayTooShort) error is returned. - pub fn new(s: &str) -> Result<Self, Error> { - let mut buf = ['\0'; N]; - let len = s.chars().count(); - - for (i, c) in s.chars().enumerate() { - if i >= N { return Err(Error::ArrayTooShort { req: len, len: N }) } - - buf[i] = c; - } - - Ok(Self { buf, len }) - } - - /// Returns the length of the string. - /// - /// This does not necessarily equal the value of `N`, as the internal buffer is not required to be used fully. - #[inline(always)] - #[must_use] - pub const fn len(&self) -> usize { self.len } - - /// Checks if the string is empty, i.e. `self.len() == 0x0`. - #[inline(always)] - #[must_use] - pub const fn is_empty(&self) -> bool { self.len == 0x0 } - - /// Borrows the character at the specified index. - /// - /// If no element exists at that position, [`None`] is returned instead. - #[inline] - #[must_use] - pub const fn get(&self, index: usize) -> Option<&char> { - if index >= self.len { - None - } else { - Some(&self.buf[index]) - } - } - - /// Mutably borrows the character at the specified index. - /// - /// If no element exists at that position, [`None`] is returned instead. - #[inline] - #[must_use] - pub fn get_mut(&mut self, index: usize) -> Option<&mut char> { - if index >= self.len { - None - } else { - Some(&mut self.buf[index]) - } - } - - /// Returns an iterator to the contained characters. - #[inline(always)] - pub fn iter(&self) -> core::slice::Iter<'_, char> { self.buf[0x0..self.len].iter() } - - /// Returns a mutable iterator to the contained characters. - #[inline(always)] - pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, char> { self.buf[0x0..self.len].iter_mut() } -} - -impl<const N: usize> Debug for FixedString<N> { - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - write!(f, "\"")?; - for c in self { write!(f, "{}", c.escape_debug())? } - write!(f, "\"")?; - - Ok(()) - } -} - -impl<const N: usize> Deserialise for FixedString<N> { - type Error = Error; - - fn deserialise(stream: &mut Dstream) -> Result<Self, Self::Error> { - let len = usize::deserialise(stream)?; - let data = stream.take(len)?; - - let s = core::str::from_utf8(data) - .map_err(|e| Error::BadString { source: e })?; - - let len = s.chars().count(); - - if len > N { - return Err(Error::ArrayTooShort { req: len, len: N }); - } - - let mut buf = ['\0'; N]; - for (i, c) in s.chars().enumerate() { - buf[i] = c; - } - - Ok(Self { buf, len }) - } -} - -impl<const N: usize> Default for FixedString<N> { - #[inline(always)] - fn default() -> Self { Self { - buf: ['\0'; N], - len: 0x0, - } } -} - -impl<const N: usize> Display for FixedString<N> { - fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { - for c in self { write!(f, "{c}")? } - - Ok(()) - } -} - -impl<const N: usize> Eq for FixedString<N> { } - -impl<const N: usize> From<[char; N]> for FixedString<N> { - fn from(value: [char; N]) -> Self { Self { - buf: value, - len: N, - } } -} - -impl<const N: usize> FromStr for FixedString<N> { - type Err = Error; - - fn from_str(s: &str) -> Result<Self, Error> { Self::new(s) } -} - -impl<const N: usize> Index<usize> for FixedString<N> { - type Output = char; - - fn index(&self, index: usize) -> &Self::Output { self.get(index).unwrap() } -} - -impl<const N: usize> IndexMut<usize> for FixedString<N> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { self.get_mut(index).unwrap() } -} - -impl<const N: usize> IntoIterator for FixedString<N> { - type Item = char; - - type IntoIter = FixedStringIter<N>; - - fn into_iter(self) -> Self::IntoIter { - FixedStringIter { - buf: self.buf, - len: self.len, - - pos: Some(0x0), - } - } -} - -impl<'a, const N: usize> IntoIterator for &'a FixedString<N> { - type Item = &'a char; - - type IntoIter = core::slice::Iter<'a, char>; - - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - -impl<'a, const N: usize> IntoIterator for &'a mut FixedString<N> { - type Item = &'a mut char; - - type IntoIter = core::slice::IterMut<'a, char>; - - fn into_iter(self) -> Self::IntoIter { self.iter_mut() } -} - -impl<const N: usize> Ord for FixedString<N> { - fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other).unwrap() } -} - -impl<const N: usize, const M: usize> PartialEq<FixedString<M>> for FixedString<N> { - fn eq(&self, other: &FixedString<M>) -> bool { - if self.len() != other.len() { return false }; - - for i in 0x0..self.len() { - if self.buf[i] != other.buf[i] { return false }; - } - - true - } -} - -impl<const N: usize> PartialEq<&str> for FixedString<N> { - fn eq(&self, other: &&str) -> bool { - for (i, c) in other.chars().enumerate() { - if self.buf.get(i) != Some(&c) { return false }; - } - - true - } -} - -impl<const N: usize, const M: usize> PartialOrd<FixedString<M>> for FixedString<N> { - fn partial_cmp(&self, other: &FixedString<M>) -> Option<Ordering> { - let len = self.len().max(other.len()); - - for i in 0x0..len { - let lc = self.get(i); - let rc = other.get(i); - - match (lc, rc) { - (None, None) => return Some(Ordering::Equal), - (Some(_), None) => return Some(Ordering::Greater), - (None, Some(_)) => return Some(Ordering::Less), - - (Some(lc), Some(rc)) => { - let ordering = lc.cmp(rc); - - if ordering != Ordering::Equal { return Some(ordering) }; - } - } - } - - Some(Ordering::Equal) - } -} - -impl<const N: usize> Serialise for FixedString<N> { - type Error = Error; - - const SERIALISE_LIMIT: usize = N * 0x4; - - fn serialise(&self, stream: &mut Sstream) -> Result<usize, Self::Error> { - let mut count = 0x0; - - let s: String = self.iter().collect(); - - count += s.len().serialise(stream)?; - count += stream.add(&s.into_bytes())?; - - Ok(count) - } -} - -impl<const N: usize> TryFrom<&str> for FixedString<N> { - type Error = Error; - - #[inline(always)] - fn try_from(value: &str) -> Result<Self, Self::Error> { Self::new(value) } -} diff --git a/src/fixed_string/test.rs b/src/fixed_string/test.rs deleted file mode 100644 index 1599efc..0000000 --- a/src/fixed_string/test.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2024 Gabriel Bjørnager Jensen. -// -// This file is part of bzipper. -// -// bzipper is free software: you can redistribute -// it and/or modify it under the terms of the GNU -// Lesser General Public License as published by -// the Free Software Foundation, either version 3 -// of the License, or (at your option) any later -// version. -// -// bzipper is distributed in the hope that it will -// be useful, but WITHOUT ANY WARRANTY; without -// even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Less- -// er General Public License along with bzipper. If -// not, see <https://www.gnu.org/licenses/>. - -use crate::FixedString; - -use core::cmp::Ordering; - -#[test] -fn test_fixed_string() { - let str0 = FixedString::<0xC>::new("Hello there!").unwrap(); - let str1 = FixedString::<0xE>::new("MEIN_GRO\u{1E9E}_GOTT").unwrap(); - let str2 = FixedString::<0x5>::new("Hello").unwrap(); - - assert_eq!(str0.partial_cmp(&str0), Some(Ordering::Equal)); - assert_eq!(str0.partial_cmp(&str1), Some(Ordering::Less)); - assert_eq!(str0.partial_cmp(&str2), Some(Ordering::Greater)); - - assert_eq!(str1.partial_cmp(&str0), Some(Ordering::Greater)); - assert_eq!(str1.partial_cmp(&str1), Some(Ordering::Equal)); - assert_eq!(str1.partial_cmp(&str2), Some(Ordering::Greater)); - - assert_eq!(str2.partial_cmp(&str0), Some(Ordering::Less)); - assert_eq!(str2.partial_cmp(&str1), Some(Ordering::Less)); - assert_eq!(str2.partial_cmp(&str2), Some(Ordering::Equal)); -} |