strings: implement push and push_truncating for CappedString
This patch implements the `CappedString::push` and `CappedString::push_truncating` methods, which are like `CappedString::push_str` and friends but take a single character rather than a string slice.
This commit is contained in:
1 parent
2d5343681a
commit
0d88775366
1 file changed
+48
-6
+48
-6
@@ -104,10 +104,23 @@ impl<const N: usize> CappedString<N> {
|
|||||||
unsafe { Self::from_raw_parts(buf, len) }
|
unsafe { Self::from_raw_parts(buf, len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// `self.len` must be less than `N`, so that there is space in the buffer to append the byte.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn append_byte(&mut self, byte: u8) {
|
||||||
|
// SAFETY:
|
||||||
|
// The caller is responsible for ensuring that `self.len < N`.
|
||||||
|
let dst = unsafe { self.buf.get_unchecked_mut(usize::from(self.len)) };
|
||||||
|
|
||||||
|
*dst = MaybeUninit::new(byte);
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// `src` must point to `len` bytes of valid UTF-8 string data. `len` must be less than or equal
|
/// `src` must point to `len` bytes of valid UTF-8 string data. `len` must be less than or equal
|
||||||
/// to `N - self.len`.
|
/// to `N - self.len`.
|
||||||
unsafe fn append_to_buf(&mut self, src: *const u8, len: u8) {
|
#[inline]
|
||||||
|
unsafe fn append_bytes(&mut self, src: *const u8, len: u8) {
|
||||||
// `u8` has the same memory layout as `MaybeUninit<u8>`, so this cast is valid.
|
// `u8` has the same memory layout as `MaybeUninit<u8>`, so this cast is valid.
|
||||||
let src = src as *const MaybeUninit<u8>;
|
let src = src as *const MaybeUninit<u8>;
|
||||||
|
|
||||||
@@ -117,7 +130,12 @@ impl<const N: usize> CappedString<N> {
|
|||||||
let dst = unsafe { self.buf.get_unchecked_mut(usize::from(self.len)..) };
|
let dst = unsafe { self.buf.get_unchecked_mut(usize::from(self.len)..) };
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
//
|
// The caller is responsible for ensuring that `src` points to a valid string, which means
|
||||||
|
// that it cannot overlap with the new local variable `buf`. The caller is responsible for
|
||||||
|
// ensuring that `src` is valid for reads of `len` bytes. The caller is responsible for
|
||||||
|
// ensuring that `len <= N - self.len`, so the destination `dst = self.buf[self.len..]` is
|
||||||
|
// valid for writes of `len` bytes. `src` and `dst` are both trivially properly aligned,
|
||||||
|
// since they both have an alignment of 1.
|
||||||
unsafe { ptr::copy_nonoverlapping(src, dst.as_mut_ptr(), usize::from(len)); }
|
unsafe { ptr::copy_nonoverlapping(src, dst.as_mut_ptr(), usize::from(len)); }
|
||||||
|
|
||||||
self.len += len;
|
self.len += len;
|
||||||
@@ -202,22 +220,45 @@ impl<const N: usize> CappedString<N> {
|
|||||||
/// is insufficient capacity remaining to do so.
|
/// is insufficient capacity remaining to do so.
|
||||||
///
|
///
|
||||||
/// If you do not care whether or not the append succeeds, see [`Self::push_truncating`].
|
/// If you do not care whether or not the append succeeds, see [`Self::push_truncating`].
|
||||||
|
#[inline]
|
||||||
pub fn push(&mut self, c: char) -> Result<(), CapacityError> {
|
pub fn push(&mut self, c: char) -> Result<(), CapacityError> {
|
||||||
todo!()
|
let mut char_buf = [0u8; 4];
|
||||||
|
let encoded = c.encode_utf8(&mut char_buf);
|
||||||
|
|
||||||
|
match encoded.len() {
|
||||||
|
1 => {
|
||||||
|
if self.len == Self::MAX_LEN {
|
||||||
|
return Err(CapacityError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
//
|
||||||
|
unsafe { self.append_byte(encoded.as_bytes()[0]) }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => self.push_str(encoded),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given character to the end of this `CappedString`, failing silently if there is
|
/// Appends the given character to the end of this `CappedString`, failing silently if there is
|
||||||
/// insufficient capacity remaining to do so.
|
/// insufficient capacity remaining to do so.
|
||||||
///
|
///
|
||||||
/// If you would like to know whether or not the append succeeds, see [`Self::push`].
|
/// If you would like to know whether or not the append succeeds, see [`Self::push`].
|
||||||
|
#[inline]
|
||||||
pub fn push_truncating(&mut self, c: char) {
|
pub fn push_truncating(&mut self, c: char) {
|
||||||
todo!()
|
// Unlike `Self::push_str_truncating`, we can just use `Self::push` and swallow the error
|
||||||
|
// because a single character will never be partially pushed; it is either pushed or it
|
||||||
|
// isn't.
|
||||||
|
self.push(c).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the given string slice to the end of this `CappedString`, returning an error if
|
/// Appends the given string slice to the end of this `CappedString`, returning an error if
|
||||||
/// there is insufficient capacity remaining to do so.
|
/// there is insufficient capacity remaining to do so.
|
||||||
///
|
///
|
||||||
/// If you would like a version which cannot fail, see [`Self::push_str_truncating`].
|
/// If you would like a version which cannot fail, see [`Self::push_str_truncating`].
|
||||||
|
#[inline]
|
||||||
pub fn push_str<S>(&mut self, src: &S) -> Result<(), CapacityError>
|
pub fn push_str<S>(&mut self, src: &S) -> Result<(), CapacityError>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + ?Sized,
|
S: AsRef<str> + ?Sized,
|
||||||
@@ -231,7 +272,7 @@ impl<const N: usize> CappedString<N> {
|
|||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
//
|
//
|
||||||
unsafe { self.append_to_buf(src.as_ptr(), len); }
|
unsafe { self.append_bytes(src.as_ptr(), len); }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -241,6 +282,7 @@ impl<const N: usize> CappedString<N> {
|
|||||||
///
|
///
|
||||||
/// If you would like a version which returns an error if there is not enough capacity remaining
|
/// If you would like a version which returns an error if there is not enough capacity remaining
|
||||||
/// to append the entire string slice, see [`Self::push_str`].
|
/// to append the entire string slice, see [`Self::push_str`].
|
||||||
|
#[inline]
|
||||||
pub fn push_str_truncating<S>(&mut self, src: &S)
|
pub fn push_str_truncating<S>(&mut self, src: &S)
|
||||||
where
|
where
|
||||||
S: AsRef<str> + ?Sized,
|
S: AsRef<str> + ?Sized,
|
||||||
@@ -257,7 +299,7 @@ impl<const N: usize> CappedString<N> {
|
|||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
//
|
//
|
||||||
unsafe { self.append_to_buf(src, len); }
|
unsafe { self.append_bytes(src, len); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string slice pointing to the underlying string data.
|
/// Returns a string slice pointing to the underlying string data.
|
||||||
|
|||||||
Reference in new issue
Block a user