Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CheetahString is a versatile string type that goes beyond the standard library's
- Efficient Arc-based sharing for larger strings

- **🔧 Rich API**
- Type split: `CheetahStr` for immutable clone-cheap keys and `CheetahBuilder` for append-heavy construction
- Query methods: `starts_with`, `ends_with`, `contains`, `find`, `rfind`
- Transformation: `to_uppercase`, `to_lowercase`, `replace`, `trim`
- Iteration: `split`, `lines`, `chars`
Expand Down Expand Up @@ -66,7 +67,7 @@ Available features:
## 🚀 Quick Start

```rust
use cheetah_string::CheetahString;
use cheetah_string::{CheetahBuilder, CheetahStr, CheetahString};

// Create from various sources
let s1 = CheetahString::from("hello"); // From &str
Expand All @@ -90,16 +91,23 @@ let name = CheetahString::from(" Rust");
let message = greeting + name.as_str(); // "Hello Rust"

// Builder pattern for efficient construction
let mut builder = CheetahString::with_capacity(100);
builder.push_str("Hello");
builder.push_str(", ");
builder.push_str("World!");
let mut string_builder = CheetahString::with_capacity(100);
string_builder.push_str("Hello");
string_builder.push_str(", ");
string_builder.push_str("World!");

// Explicit String storage policy
let mut owned = CheetahString::from_string_owned(String::with_capacity(128));
owned.push_str("capacity-preserving");
let shared = CheetahString::from_string_shared("clone-cheap".repeat(16));

// v2 type split
let topic = CheetahStr::from_static_str("orders-created");
let mut route_builder = CheetahBuilder::with_capacity(64);
route_builder.push_str(topic.as_str());
route_builder.push_str(":partition-0");
let route_key = route_builder.finish_str();

// Safe UTF-8 validation
let bytes = b"hello";
let s = CheetahString::try_from_bytes(bytes).unwrap();
Expand Down Expand Up @@ -135,6 +143,16 @@ CheetahString intelligently chooses the most efficient storage:
| Owned | `String` | 1 | Reserved capacity, repeated mutation |
| Bytes | `CheetahBytes` | 1 | Byte-oriented network buffers (with feature) |

For new code, use:

| Type | Role |
|------|------|
| `CheetahStr` | Immutable clone-cheap values such as topics, groups, names, and keys |
| `CheetahString` | Mutable string value with the 1.x compatibility API |
| `CheetahBuilder` | Append-heavy construction followed by `finish_string()` or `finish_str()` |
| `CheetahFinder` | Reusable substring search |
| `CheetahBytes` | Byte semantics without a UTF-8 promise |

## 🔧 API Overview

### Construction
Expand All @@ -145,6 +163,8 @@ CheetahString intelligently chooses the most efficient storage:
- `from_string_owned(s)` - Preserve `String` ownership and spare capacity for mutation
- `from_string_shared(s)` - Convert long owned strings to clone-cheap shared storage
- `try_from_bytes(b)` - Safe construction from bytes with UTF-8 validation
- `CheetahStr` - Immutable clone-cheap string companion
- `CheetahBuilder` - Append-heavy builder companion
- `CheetahBytes` - Byte-oriented companion type available with the `bytes` feature
- `with_capacity(n)` - Pre-allocate capacity

Expand Down
146 changes: 146 additions & 0 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use alloc::string::String;
use core::fmt;

use crate::{CheetahStr, CheetahString};

/// Append-heavy builder for constructing Cheetah string values.
///
/// `CheetahBuilder` keeps mutable construction separate from immutable
/// clone-cheap `CheetahStr` values and stable string values.
#[derive(Clone, Default)]
pub struct CheetahBuilder {
inner: String,
}

impl CheetahBuilder {
/// Creates an empty builder.
#[inline]
pub fn new() -> Self {
Self {
inner: String::new(),
}
}

/// Creates an empty builder with at least `capacity` bytes.
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
inner: String::with_capacity(capacity),
}
}

/// Creates a builder from existing owned storage.
#[inline]
pub fn from_string(value: String) -> Self {
Self { inner: value }
}

/// Appends a string slice.
#[inline]
pub fn push_str(&mut self, value: &str) {
self.inner.push_str(value);
}

/// Appends a character.
#[inline]
pub fn push(&mut self, value: char) {
self.inner.push(value);
}

/// Reserves capacity for at least `additional` more bytes.
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional);
}

/// Clears the current contents while preserving capacity.
#[inline]
pub fn clear(&mut self) {
self.inner.clear();
}

/// Returns the current contents.
#[inline]
pub fn as_str(&self) -> &str {
self.inner.as_str()
}

/// Returns the current length in bytes.
#[inline]
pub fn len(&self) -> usize {
self.inner.len()
}

/// Returns whether the builder is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}

/// Returns the allocated capacity in bytes.
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}

/// Finishes into a mutable string value, preserving spare capacity when it
/// is useful for subsequent mutation.
#[inline]
pub fn finish_string(self) -> CheetahString {
CheetahString::from_string_owned(self.inner)
}

/// Finishes into an immutable clone-cheap string value.
#[inline]
pub fn finish_str(self) -> CheetahStr {
CheetahStr::from_string(self.inner)
}

/// Returns the owned `String` backing this builder.
#[inline]
pub fn into_string(self) -> String {
self.inner
}
}

impl From<String> for CheetahBuilder {
#[inline]
fn from(value: String) -> Self {
Self::from_string(value)
}
}

impl From<&str> for CheetahBuilder {
#[inline]
fn from(value: &str) -> Self {
let mut builder = Self::with_capacity(value.len());
builder.push_str(value);
builder
}
}

impl Extend<char> for CheetahBuilder {
#[inline]
fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
self.inner.extend(iter);
}
}

impl<'a> Extend<&'a str> for CheetahBuilder {
#[inline]
fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
for item in iter {
self.push_str(item);
}
}
}

impl fmt::Debug for CheetahBuilder {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CheetahBuilder")
.field("value", &self.inner)
.field("capacity", &self.inner.capacity())
.finish()
}
}
Loading
Loading