diff --git a/src/ascii_str_arr.rs b/src/ascii_str_arr.rs index daeb485..6203d1a 100644 --- a/src/ascii_str_arr.rs +++ b/src/ascii_str_arr.rs @@ -2,6 +2,7 @@ // Modules pub mod error; +pub mod slice; mod visitor; // Exports @@ -19,6 +20,8 @@ pub struct AsciiStrArr { chars: [AsciiChar; N], /// Size + /// + /// Invariant: Must be `< N` len: usize, } @@ -38,12 +41,14 @@ impl AsciiStrArr { /// Converts this string to a `&[AsciiStr]` #[must_use] pub fn as_ascii_str(&self) -> &AsciiStr { + // Note: Cannot panic due to our invariant <&AsciiStr>::from(&self.chars[..self.len]) } /// Converts this string to a `&mut [AsciiStr]` #[must_use] pub fn as_ascii_str_mut(&mut self) -> &mut AsciiStr { + // Note: Cannot panic due to our invariant <&mut AsciiStr>::from(&mut self.chars[..self.len]) } @@ -58,18 +63,6 @@ impl AsciiStrArr { pub fn as_str(&self) -> &str { self.as_ascii_str().as_str() } - - /// Returns the `n`th character - #[must_use] - pub fn get(&self, n: usize) -> Option<&AsciiChar> { - self.chars.get(n) - } - - /// Returns the `n`th character mutably - #[must_use] - pub fn get_mut(&mut self, n: usize) -> Option<&mut AsciiChar> { - self.chars.get_mut(n) - } } impl AsRef for AsciiStrArr { @@ -84,20 +77,6 @@ impl AsMut for AsciiStrArr { } } -impl std::ops::Index for AsciiStrArr { - type Output = AsciiChar; - - fn index(&self, idx: usize) -> &Self::Output { - self.get(idx).expect("Invalid index access") - } -} - -impl std::ops::IndexMut for AsciiStrArr { - fn index_mut(&mut self, idx: usize) -> &mut Self::Output { - self.get_mut(idx).expect("Invalid index access") - } -} - impl PartialEq for AsciiStrArr { fn eq(&self, other: &Self) -> bool { AsciiStr::eq(self.as_ascii_str(), other.as_ascii_str()) @@ -210,3 +189,13 @@ impl TryFrom<&[u8]> for AsciiStrArr { Self::try_from(ascii_str).map_err(FromByteStringError::TooLong) } } + +impl TryFrom<&str> for AsciiStrArr { + type Error = FromByteStringError; + + fn try_from(string: &str) -> Result { + let ascii_str = AsciiStr::from_ascii(string).map_err(FromByteStringError::NotAscii)?; + + Self::try_from(ascii_str).map_err(FromByteStringError::TooLong) + } +} diff --git a/src/ascii_str_arr/slice.rs b/src/ascii_str_arr/slice.rs new file mode 100644 index 0000000..4bd0d13 --- /dev/null +++ b/src/ascii_str_arr/slice.rs @@ -0,0 +1,57 @@ +//! Slicing operations for [`AsciiStrArr`] + +// Imports +use super::AsciiStrArr; +use ascii::AsciiChar; +use std::ops::{Index, IndexMut}; + +/// Helper trait for slicing a [`AsciiStrArr`] +// Note: Adapted from `std::slice::SliceIndex` +pub trait SliceIndex +where + I: ?Sized, +{ + /// Output type for this slicing + type Output: ?Sized; + + /// Tries to get the `idx`th element + fn get(&self, idx: I) -> Option<&Self::Output>; + + /// Tries to get the `idx`th element mutably + fn get_mut(&mut self, idx: I) -> Option<&mut Self::Output>; +} + +impl SliceIndex for AsciiStrArr +where + I: std::slice::SliceIndex<[AsciiChar]>, +{ + type Output = >::Output; + + fn get(&self, idx: I) -> Option<&Self::Output> { + self.as_ascii_str().as_slice().get(idx) + } + + fn get_mut(&mut self, idx: I) -> Option<&mut Self::Output> { + self.as_ascii_str_mut().as_mut_slice().get_mut(idx) + } +} + +impl Index for AsciiStrArr +where + Self: SliceIndex, +{ + type Output = >::Output; + + fn index(&self, idx: I) -> &Self::Output { + self.get(idx).expect("Invalid index access") + } +} + +impl IndexMut for AsciiStrArr +where + Self: SliceIndex, +{ + fn index_mut(&mut self, idx: I) -> &mut Self::Output { + self.get_mut(idx).expect("Invalid index access") + } +} diff --git a/src/lib.rs b/src/lib.rs index 0104735..83d0dae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,8 @@ #![allow(clippy::integer_arithmetic, clippy::integer_division)] // We prefer using match ergonomic where possible #![allow(clippy::pattern_type_mismatch)] +// Sometimes the blocks make it easier to invert their order +#![allow(clippy::if_not_else)] // False positives: // TODO: Remove them in the future once they are no longer triggered. // We only slice arrays, which are verified at compile time. This