Skip to content

Commit e23044d

Browse files
committed
finalize_unsafe added, finalize -> Result changed to finalize -> FixedStr, cleanup
1 parent 63dae5d commit e23044d

File tree

6 files changed

+46
-23
lines changed

6 files changed

+46
-23
lines changed

CHANGELOG.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ All notable changes to this project will be documented in this file.
66

77
### Added
88
- **`truncate(len)` method:** Added `truncate()` to `FixedStr` and `FixedStrBuf` for shortening visible string length in-place.
9+
- **`finalize_unsafe()` method:** for cases requiring direct construction without UTF‑8 validation.
910

1011
### Changed
1112
- **Updated crate-level and function-level docs** for clarity, accuracy, and consistency with actual behavior.
12-
- **Corrected misleading note** on `FixedStr::new_const` to reflect that UTF‑8 is now always respected, even at compile time.
13+
- **`FixedStrBuf::finalize()` now returns `FixedStr` directly** (was `Result`), reflecting that `finalize()` only produces valid UTF‑8.
14+
- **Implemented `From<FixedStrBuf<N>> for FixedStr<N>`** for ergonomic conversion from builder to fixed string.
1315
- Improved descriptions for `from_bytes`, `set_lossy`, and other modifiers to better reflect truncation and null-termination behavior.
14-
16+
1517
### Removed
1618
- `FixedStr::as_hex()` and `FixedStr::hex_dump()`: Removed from the core type to avoid side effects and formatting logic in core APIs.
1719

1820
Hex formatting is still available via the `fast_format_hex()` and `dump_as_hex()` helper functions for manual use.
1921

2022
### Fixed
21-
- Corrected docblocks and comments referring to outdated runtime validation behavior.
23+
- **Corrected misleading note** on `FixedStr::new_const` to reflect that UTF‑8 is now always respected, even at compile time.
2224
- Corrected the conversion implementations for `FixedStrBuf` (from `FixedStr` and via `TryFrom<&[u8]>`) so that the effective length (up to the first null byte) is used rather than the full array capacity. This ensures that builder operations such as appending and truncating behave correctly.
25+
- Corrected docblocks and comments referring to outdated runtime validation behavior.
2326

2427

2528
## [0.9.0] - 2025-03-25

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ fn main() {
9090
- `truncate(len: usize)`: Truncate the visible portion to a specified length.
9191

9292
### Views & Conversions
93-
- `as_str() -> &str`: View the string up to the null terminator.
94-
- `try_as_str() -> Result<&str, FixedStrError>`: UTF‑8 checked view.
93+
- `as_str() -> &str`: View the string up to the null terminator or last valid UTF-8 character.
94+
- `try_as_str() -> Result<&str, FixedStrError>`: UTF‑8 tested view.
9595
- `as_bytes() -> &[u8]`: Raw byte view of the entire buffer.
9696
- `effective_bytes() -> &[u8]`: View of the bytes until the first `\0`.
9797
- `into_string() -> String`: Convert into an owned `String` (requires `std`).

src/fs_buffer.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,22 @@ impl<const N: usize> FixedStrBuf<N> {
103103
/// This method zero‑pads the unused portion of the buffer and creates a `FixedStr`
104104
/// from the internal byte array. If the written content contains a null byte (`\0`),
105105
/// the resulting string will terminate at that null, ignoring any bytes that follow.
106-
pub fn finalize(mut self) -> Result<FixedStr<N>, FixedStrError> {
107-
for i in self.len..N {
108-
self.buffer[i] = 0;
109-
}
110-
Ok(FixedStr::from_bytes(self.buffer))
106+
pub fn finalize(mut self) -> FixedStr<N> {
107+
self.buffer[self.len..N].fill(0);
108+
FixedStr::from_bytes(self.buffer)
109+
}
110+
111+
/// Finalizes the builder into a `FixedStr` without UTF-8 boundary checks.
112+
///
113+
/// # Warning
114+
/// Use with care—this may produce values that may cause conversions to panic or comparisons to fail.
115+
///
116+
/// This method zero‑pads the unused portion of the buffer and creates a `FixedStr`
117+
/// from the internal byte array. If the written content contains a null byte (`\0`),
118+
/// the resulting string will terminate at that null, ignoring any bytes that follow.
119+
pub fn finalize_unsafe(mut self) -> FixedStr<N> {
120+
self.buffer[self.len..N].fill(0);
121+
FixedStr::from_bytes_unsafe(self.buffer)
111122
}
112123

113124
/// Clears the builder, resetting its effective length to zero and zero‑filling the buffer.
@@ -358,15 +369,15 @@ mod buffer_tests {
358369
// Any additional push will result in truncation.
359370
let result = buf.push_str_lossy(", world!");
360371
assert!(!result);
361-
let fixed: FixedStr<5> = buf.finalize().unwrap();
372+
let fixed: FixedStr<5> = buf.finalize();
362373
assert_eq!(fixed.as_str(), "Hello");
363374
}
364375

365376
#[test]
366377
fn test_finalize_trailing_zeros() {
367378
let mut buf = FixedStrBuf::<10>::new();
368379
buf.try_push_str("Hi").unwrap();
369-
let fixed: FixedStr<10> = buf.finalize().unwrap();
380+
let fixed: FixedStr<10> = buf.finalize();
370381
// The effective string is "Hi" and the rest are zeros.
371382
assert_eq!(fixed.len(), 2);
372383
assert_eq!(fixed.as_str(), "Hi");
@@ -422,7 +433,7 @@ mod buffer_tests {
422433
buf.truncate(5);
423434
assert_eq!(buf.len(), 5);
424435
// Finalize the buffer and check that the effective string is "Hello".
425-
let fixed = buf.finalize().unwrap();
436+
let fixed = buf.finalize();
426437
assert_eq!(fixed.as_str(), "Hello");
427438
// Also check that the truncated portion of the buffer is zero.
428439
for &b in &buf.as_ref()[5..] {

src/fs_core.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl<const N: usize> FixedStr<N> {
125125
/// when using `as_str()` or during comparisons.
126126
///
127127
/// # Warning
128-
/// Use with care—this may produce values that cause `as_str()` to panic or comparisons to fail.
128+
/// Use with care—this may produce values that may cause conversions to panic or comparisons to fail.
129129
///
130130
/// # Panics
131131
/// Panics if `N == 0`. Zero‑length strings are not supported.
@@ -155,7 +155,7 @@ impl<const N: usize> FixedStr<N> {
155155
/// The first null byte (`\0`) still acts as a terminator in conversions and comparisons.
156156
///
157157
/// # Warning
158-
/// Use with care—this may produce values that cause `as_str()` to panic or comparisons to fail.
158+
/// Use with care—this may produce values that may cause conversions to panic or comparisons to fail.
159159
///
160160
/// # Panics
161161
/// Panics if `N == 0`. Zero‑length strings are not supported.

src/fs_impl.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
use super::*;
44

5-
/// Implements the Debug trait for FixedStr.
5+
/// Implements the Debug trait for `FixedStr`.
66
///
77
/// If the effective string is valid UTF‑8, it is printed using the Debug format.
8-
/// Otherwise, it prints "<invalid UTF-8>" followed by a hex dump of the underlying data.
8+
/// Otherwise, it prints a hex dump of the underlying data.
99
impl<const N: usize> fmt::Debug for FixedStr<N> {
1010
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1111
match self.try_as_str() {
@@ -19,35 +19,35 @@ impl<const N: usize> fmt::Debug for FixedStr<N> {
1919
}
2020
}
2121

22-
/// Implements the Display trait for FixedStr by displaying its effective string.
22+
/// Implements the Display trait for `FixedStr` by displaying its effective string.
2323
impl<const N: usize> fmt::Display for FixedStr<N> {
2424
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2525
write!(f, "{}", self.as_str())
2626
}
2727
}
2828

29-
/// Allows a FixedStr to be referenced as a byte slice.
29+
/// Allows a `FixedStr` to be referenced as a byte slice.
3030
impl<const N: usize> AsRef<[u8]> for FixedStr<N> {
3131
fn as_ref(&self) -> &[u8] {
3232
&self.data
3333
}
3434
}
3535

36-
/// Allows a FixedStr to be referenced as a str (using its effective string).
36+
/// Allows a `FixedStr` to be referenced as a `str` (using its effective string).
3737
impl<const N: usize> AsRef<str> for FixedStr<N> {
3838
fn as_ref(&self) -> &str {
3939
self.as_str()
4040
}
4141
}
4242

43-
/// Implements Borrow<str> for FixedStr, returning the effective string.
43+
/// Implements `Borrow<str>` for `FixedStr`, returning the effective string.
4444
impl<const N: usize> Borrow<str> for FixedStr<N> {
4545
fn borrow(&self) -> &str {
4646
self.as_str()
4747
}
4848
}
4949

50-
/// Provides a default FixedStr where all bytes are zero.
50+
/// Provides a default `FixedStr` where all bytes are zero.
5151
impl<const N: usize> Default for FixedStr<N> {
5252
fn default() -> Self {
5353
Self { data: [0; N] }
@@ -99,6 +99,15 @@ impl<const N: usize> From<&str> for FixedStr<N> {
9999
}
100100
}
101101

102+
/// Constructs a FixedStr from a &str using the standard constructor.
103+
///
104+
/// **Warning:** If the input contains a null byte or invalid UTF‑8, the string is truncated.
105+
impl<const N: usize> From<FixedStrBuf<N>> for FixedStr<N> {
106+
fn from(buf: FixedStrBuf<N>) -> Self {
107+
buf.finalize()
108+
}
109+
}
110+
102111
/// Hashes the FixedStr based only on its effective bytes (up to the first null).
103112
impl<const N: usize> Hash for FixedStr<N> {
104113
fn hash<H: Hasher>(&self, state: &mut H) {

src/string_helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub fn fast_format_hex<const N: usize>(
273273
buffer[pos..N].fill(0);
274274

275275
// Safe due to controlled construction.
276-
crate::FixedStrBuf { buffer, len: pos }.finalize().unwrap()
276+
crate::FixedStrBuf { buffer, len: pos }.finalize()
277277
}
278278

279279
/// Outputs the full hexadecimal representation of `bytes` by invoking the provided callback

0 commit comments

Comments
 (0)