Skip to content

Commit

Permalink
release: 0.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
joshstoik1 committed Apr 12, 2022
2 parents 8a9cb26 + a579b0a commit b6ec9e9
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 198 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ jobs:
- name: Build
run: |
cargo build --release --target ${{ matrix.target }}
cargo build --release --no-default-features --target ${{ matrix.target }}
- name: Clippy
run: |
cargo clippy --release --target ${{ matrix.target }}
cargo clippy --release --no-default-features --target ${{ matrix.target }}
- name: Tests
run: |
cargo test --release --target ${{ matrix.target }}
cargo test --release --no-default-features --target ${{ matrix.target }}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [0.1.1](https://github.com/Blobfolio/trimothy/releases/tag/v0.1.1) - 2022-04-11

## Changes

* Minor performance improvements

## Fixed

* Return empty slice when all bytes match trim predicate.
* Markdown (docs) formatting issues.



## [0.1.0](https://github.com/Blobfolio/trimothy/releases/tag/v0.1.0) - 2022-04-11

Initial release!
4 changes: 2 additions & 2 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Project Dependencies
Package: trimothy
Version: 0.1.0
Generated: 2022-04-11 21:07:33 UTC
Version: 0.1.1
Generated: 2022-04-12 05:23:34 UTC

This package has no dependencies.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "trimothy"
version = "0.1.0"
version = "0.1.1"
authors = ["Blobfolio, LLC. <[email protected]>"]
edition = "2021"
rust-version = "1.60"
Expand Down Expand Up @@ -34,3 +34,8 @@ std = []
name = "fn_trim_slice"
harness = false
required-features = [ "std" ]

[[bench]]
name = "fn_trim_mut_vec"
harness = false
required-features = [ "std" ]
33 changes: 33 additions & 0 deletions benches/fn_trim_mut_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*!
# Benchmark: Trim Slice
*/

use brunch::{
Bench,
benches,
};
use trimothy::TrimMut;
use std::time::Duration;



const BYTES: &[u8] = b" \t\nHello World!\n\t ";
const STR: &str = " \t\nHello World!\n\t ";



benches!(
Bench::new("Vec<u8>", "trim_mut()")
.timed(Duration::from_secs(1))
.with_setup(BYTES.to_vec(), |mut v| v.trim_mut()),

Bench::spacer(),

Bench::new("String", "trim_mut()")
.timed(Duration::from_secs(1))
.with_setup(STR.to_owned(), |mut s| s.trim_mut()),

Bench::new("String.trim()", "to_owned()")
.timed(Duration::from_secs(1))
.with_setup(STR.to_owned(), |s| s.trim().to_owned()),
);
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,13 @@ pub use trim_slice::{
TrimSlice,
TrimSliceMatches,
};



#[allow(clippy::trivially_copy_pass_by_ref)] // It's the signature iterator wants.
#[inline]
/// # Not Whitespace.
///
/// This callback is used to find the first or last non-whitespace byte in a
/// slice. It is only split off into its own method to enforce consistency.
pub(crate) const fn not_whitespace(b: &u8) -> bool { ! b.is_ascii_whitespace() }
117 changes: 51 additions & 66 deletions src/trim_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use alloc::{
};

use crate::{
not_whitespace,
TrimSlice,
TrimSliceMatches,
};
Expand All @@ -28,13 +29,14 @@ use core::intrinsics::copy;
/// `Vec<u8>`, and `Box<[u8]>`.
///
/// The trait methods included are:
///
/// | Method | Description |
/// | ------ | ----------- |
/// | `trim_mut` | Trim leading and trailing whitespace (mutably). |
/// | `trim_start_mut` | Trim leading whitespace (mutably). |
/// | `trim_end_mut` | Trim trailing whitespace (mutably). |
///
/// **Note:** these behaviors of these methods are consistent with their immutable
/// **Note:** The behaviors of these methods are consistent with their immutable
/// counterparts, meaning that Strings will trim [`char::is_whitespace`], while
/// slices will only trim [`u8::is_ascii_whitespace`].
///
Expand Down Expand Up @@ -67,15 +69,16 @@ pub trait TrimMut {
/// `String`, `Vec<u8>`, and `Box<[u8]>`.
///
/// The trait methods included are:
///
/// | Method | Description |
/// | ------ | ----------- |
/// | `trim_matches_mut` | Trim arbitrary leading and trailing bytes via callback (mutably). |
/// | `trim_start_matches_mut` | Trim arbitrary leading bytes via callback (mutably). |
/// | `trim_end_matches_mut` | Trim arbitrary trailing bytes via callback (mutably). |
///
/// **Note:** The atom being matched varies by implementation to keep behaviors
/// consistent with their immutable counterparts. In other words, `String` uses
/// `char`, while `Vec<u8>` and `Box<[u8]>` use `u8`.
/// **Note:** To maintain consistency with their immutable counterparts, the
/// `String` implementation expects callbacks that match a `char`, while the
/// `Vec<u8>` and `Box<[u8]>` implementations expect callbacks that match a `u8`.
///
/// Refer to the individual implementations for examples.
pub trait TrimMatchesMut {
Expand Down Expand Up @@ -131,18 +134,18 @@ impl TrimMut for String {
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
if 0 < trimmed_len {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
let v = self.as_mut_vec();
copy(trimmed_ptr, v.as_mut_ptr(), trimmed_len);
v.set_len(trimmed_len);
}
}
else { self.truncate(0); }
}
}

Expand All @@ -164,18 +167,18 @@ impl TrimMut for String {
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
if 0 < trimmed_len {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
let v = self.as_mut_vec();
copy(trimmed_ptr, v.as_mut_ptr(), trimmed_len);
v.set_len(trimmed_len);
}
}
else { self.truncate(0); }
}
}

Expand Down Expand Up @@ -223,18 +226,18 @@ impl TrimMatchesMut for String {
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
if 0 < trimmed_len {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
let v = self.as_mut_vec();
copy(trimmed_ptr, v.as_mut_ptr(), trimmed_len);
v.set_len(trimmed_len);
}
}
else { self.truncate(0); }
}
}

Expand All @@ -259,18 +262,18 @@ impl TrimMatchesMut for String {
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
if 0 < trimmed_len {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
let v = self.as_mut_vec();
copy(trimmed_ptr, v.as_mut_ptr(), trimmed_len);
v.set_len(trimmed_len);
}
}
else { self.truncate(0); }
}
}

Expand Down Expand Up @@ -442,22 +445,8 @@ impl TrimMut for Vec<u8> {
/// assert_eq!(v, b"Hello World!");
/// ```
fn trim_mut(&mut self) {
let trimmed = self.trim();
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
unsafe {
copy(trimmed_ptr, self.as_mut_ptr(), trimmed_len);
self.set_len(trimmed_len);
}
}
}
self.trim_start_mut();
self.trim_end_mut();
}

/// # Trim Start Mut.
Expand All @@ -474,22 +463,19 @@ impl TrimMut for Vec<u8> {
/// assert_eq!(v, b"Hello World! ");
/// ```
fn trim_start_mut(&mut self) {
let trimmed = self.trim_start();
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
let trimmed_ptr = trimmed.as_ptr();
if let Some(start) = self.iter().position(not_whitespace) {
if 0 < start {
let trimmed_len = self.len() - start;

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
copy(trimmed_ptr, self.as_mut_ptr(), trimmed_len);
copy(self.as_ptr().add(start), self.as_mut_ptr(), trimmed_len);
self.set_len(trimmed_len);
}
}
}
else { self.truncate(0); }
}

/// # Trim End Mut.
Expand All @@ -506,9 +492,10 @@ impl TrimMut for Vec<u8> {
/// assert_eq!(v, b" Hello World!");
/// ```
fn trim_end_mut(&mut self) {
let trimmed = self.trim_end();
let trimmed_len = trimmed.len();
self.truncate(trimmed_len);
if let Some(end) = self.iter().rposition(not_whitespace) {
self.truncate(end + 1);
}
else { self.truncate(0); }
}
}

Expand Down Expand Up @@ -536,17 +523,17 @@ impl TrimMatchesMut for Vec<u8> {
let trimmed_len = trimmed.len();

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
if 0 < trimmed_len {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
copy(trimmed_ptr, self.as_mut_ptr(), trimmed_len);
self.set_len(trimmed_len);
}
}
else { self.truncate(0); }
}
}

Expand All @@ -567,22 +554,19 @@ impl TrimMatchesMut for Vec<u8> {
/// ```
fn trim_start_matches_mut<F>(&mut self, cb: F)
where F: Fn(Self::MatchUnit) -> bool {
let trimmed = self.trim_start_matches(cb);
let trimmed_len = trimmed.len();
if let Some(start) = self.iter().position(|b: &u8| ! cb(*b)) {
if 0 < start {
let trimmed_len = self.len() - start;

if trimmed_len < self.len() {
if trimmed_len == 0 { self.truncate(0); }
else {
let trimmed_ptr = trimmed.as_ptr();

// Safety: we're just moving the trimmed portion to the start. It
// should be A-OK.
// Safety: we're just moving the trimmed portion to the start
// of the buffer and chopping the length to match.
unsafe {
copy(trimmed_ptr, self.as_mut_ptr(), trimmed_len);
copy(self.as_ptr().add(start), self.as_mut_ptr(), trimmed_len);
self.set_len(trimmed_len);
}
}
}
else { self.truncate(0); }
}

/// # Trim End Matches Mut.
Expand All @@ -602,8 +586,9 @@ impl TrimMatchesMut for Vec<u8> {
/// ```
fn trim_end_matches_mut<F>(&mut self, cb: F)
where F: Fn(Self::MatchUnit) -> bool {
let trimmed = self.trim_end_matches(cb);
let trimmed_len = trimmed.len();
self.truncate(trimmed_len);
if let Some(end) = self.iter().rposition(|b: &u8| ! cb(*b)) {
self.truncate(end + 1);
}
else { self.truncate(0); }
}
}
Loading

0 comments on commit b6ec9e9

Please sign in to comment.