Skip to content

Commit 61d4751

Browse files
Wicparpaulocsanz
authored andcommitted
added no panic check, refactored so there is no panic in push_str and push_str_truncate
1 parent 701879a commit 61d4751

File tree

3 files changed

+39
-27
lines changed

3 files changed

+39
-27
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ criterion = { version = "0.4", features = ["html_reports"] }
2727
env_logger = "0.10"
2828
serde = { version = "1.0", features = ["derive"] }
2929
diesel = { version = "2", features = ["sqlite", "postgres", "mysql"] }
30-
3130
[dependencies]
3231
log = { version = "0.4", optional = true }
3332
serde = { version = "1", optional = true }
3433
diesel = { version = "2", optional = true }
34+
no-panic = "0.1"
3535

3636
[features]
3737
default = ["std"]
@@ -43,3 +43,6 @@ diesel-traits = ["diesel"]
4343
[package.metadata.docs.rs]
4444
rustdoc-args = ["--cfg", "docs_rs_workaraound"]
4545
features = ["logs", "serde-traits", "std", "diesel-traits"]
46+
47+
[profile.dev]
48+
opt-level = 3

src/arraystring.rs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use core::str::from_utf8;
99
use core::{cmp::min, ops::*};
1010
#[cfg(feature = "logs")]
1111
use log::{debug, trace};
12-
use std::usize;
12+
use no_panic::no_panic;
13+
use std::{ptr, usize};
1314

1415
/// String based on a generic array (size defined at compile time through `const generics`)
1516
///
@@ -470,15 +471,21 @@ where
470471
/// # }
471472
/// ```
472473
#[inline]
474+
#[cfg_attr(not(debug_assertions), no_panic)]
473475
pub fn try_push_str(&mut self, string: impl AsRef<str>) -> Result<(), OutOfBounds> {
474476
trace!("Push str: {}", string.as_ref());
475477
let str = string.as_ref().as_bytes();
476478
if str.len() == 0 {
477479
return Ok(());
478480
}
479481
is_inside_boundary(str.len() + self.len(), Self::capacity())?;
480-
let this_len = self.len();
481-
self.array[this_len..this_len + str.len()].copy_from_slice(str);
482+
unsafe {
483+
ptr::copy_nonoverlapping(
484+
str.as_ptr(),
485+
self.array.as_mut_ptr().add(self.len()),
486+
str.len(),
487+
);
488+
}
482489
self.size += str.len() as u8;
483490
return Ok(());
484491
}
@@ -502,17 +509,22 @@ where
502509
/// # }
503510
/// ```
504511
#[inline]
512+
#[cfg_attr(not(debug_assertions), no_panic)]
505513
pub fn push_str_truncate(&mut self, string: impl AsRef<str>) {
506514
trace!("Push str truncate: {}", string.as_ref());
515+
let str = string.as_ref().as_bytes();
507516
let size = Self::capacity() - self.len();
508-
if size == 0 {
517+
if size == 0 || str.len() == 0 {
509518
return;
510519
}
511-
let str = truncate_str(string.as_ref().as_bytes(), size.into());
512-
if str.len() == 0 {
513-
return;
520+
let str = truncate_str(str, size);
521+
unsafe {
522+
ptr::copy_nonoverlapping(
523+
str.as_ptr(),
524+
self.array.as_mut_ptr().add(self.len()),
525+
str.len(),
526+
);
514527
}
515-
self.array[self.size as usize..self.size as usize + str.len()].copy_from_slice(str);
516528
self.size += str.len() as u8;
517529
}
518530

@@ -983,15 +995,6 @@ where
983995
Bound::Excluded(t) => *t,
984996
Bound::Unbounded => self.len(),
985997
};
986-
is_inside_boundary(start, end)?;
987-
is_inside_boundary(end, self.len())?;
988-
is_char_boundary(self, start)?;
989-
is_char_boundary(self, end)?;
990-
let r_len = end - start;
991-
is_inside_boundary(start + str.len() + self.len() - end, Self::capacity())?;
992-
if start == end && with.as_ref().len() == 0 {
993-
return Ok(());
994-
}
995998
debug!(
996999
"Replace range (len: {}) ({}..{}) with (len: {}) {}",
9971000
self.len(),
@@ -1000,13 +1003,21 @@ where
10001003
with.as_ref().len(),
10011004
with.as_ref()
10021005
);
1006+
if start == end && str.len() == 0 {
1007+
return Ok(());
1008+
}
1009+
is_inside_boundary(start, end)?;
1010+
is_inside_boundary(end, self.len())?;
1011+
is_char_boundary(self, start)?;
1012+
is_char_boundary(self, end)?;
1013+
is_inside_boundary(start + str.len() + self.len() - end, Self::capacity())?;
10031014
let dest = start + str.len();
10041015
let this_len = self.len();
10051016
self.array.copy_within(end..this_len, dest);
10061017
if str.len() > 0 {
10071018
self.array[start..start + str.len()].copy_from_slice(str);
10081019
}
1009-
self.size -= r_len as u8;
1020+
self.size -= (end - start) as u8;
10101021
self.size += str.len() as u8;
10111022
Ok(())
10121023
}

src/utils.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,18 @@
33
use crate::{arraystring::sealed::ValidCapacity, prelude::*};
44
#[cfg(feature = "logs")]
55
use log::{debug, trace};
6+
use no_panic::no_panic;
67

78
pub(crate) trait IntoLossy<T>: Sized {
89
fn into_lossy(self) -> T;
910
}
1011

1112
/// Returns error if size is outside of specified boundary
13+
#[cfg_attr(not(debug_assertions), no_panic)]
1214
#[inline]
13-
pub fn is_inside_boundary<S, L>(size: S, limit: L) -> Result<(), OutOfBounds>
14-
where
15-
S: Into<usize>,
16-
L: Into<usize>,
17-
{
18-
let (s, l) = (size.into(), limit.into());
19-
trace!("Out of bounds: ensures {} < {}", s, l);
20-
Some(()).filter(|_| s <= l).ok_or(OutOfBounds)
15+
pub fn is_inside_boundary(size: usize, limit: usize) -> Result<(), OutOfBounds> {
16+
trace!("Out of bounds: ensures {} <= {}", size, limit);
17+
(size <= limit).then_some(()).ok_or(OutOfBounds)
2118
}
2219

2320
/// Returns error if index is not at a valid utf-8 char boundary
@@ -47,6 +44,7 @@ pub unsafe fn is_char_boundary_at(arr: &[u8], index: usize) -> bool {
4744

4845
/// Truncates string to specified size (ignoring last bytes if they form a partial `char`)
4946
#[inline]
47+
#[cfg_attr(not(debug_assertions), no_panic)]
5048
pub(crate) fn truncate_str(slice: &[u8], mut size: usize) -> &[u8] {
5149
trace!(
5250
"Truncate str: {} at {}",

0 commit comments

Comments
 (0)