flexstr 0.11.7

A flexible, simple to use, clone-efficient string type for Rust
Documentation
#![allow(dead_code)]

use core::fmt;
use flexstr::{FlexStr, RefCounted, StringLike};
use flexstr_support::StringToFromBytes;
use inline_flexstr::{INLINE_CAPACITY, InlineFlexStr, TooLongForInlining};

/// Test empty string operations
pub fn test_empty_string<S, R>(empty: &'static S)
where
    S: ?Sized + StringToFromBytes + PartialEq + fmt::Debug,
    R: RefCounted<S> + fmt::Debug,
    FlexStr<'static, S, R>: StringLike<S>,
    Box<S>: From<S::Owned>,
    S::Owned: AsRef<S>,
{
    let flex_str: FlexStr<'_, S, R> = FlexStr::from_borrowed(empty);

    assert!(StringLike::is_empty(&flex_str));
    assert_eq!(StringLike::len(&flex_str), 0);
    assert!(flex_str.is_borrowed());

    // Test empty string can be cloned
    let cloned = flex_str.clone();
    assert_eq!(flex_str, cloned);

    // Test empty string can be converted to owned
    let owned = flex_str.to_owned();
    assert_eq!(owned.as_ref_type(), empty);
    assert!(StringLike::is_empty(&owned));
}

/// Test capacity boundary - string at exact capacity
/// Input must be exactly at INLINE_CAPACITY
pub fn test_capacity_boundary_exact<S, R>(s: &'static S)
where
    S: ?Sized + StringToFromBytes + fmt::Debug + PartialEq,
    R: RefCounted<S>,
{
    let bytes = s.self_as_raw_bytes();
    assert_eq!(
        bytes.len(),
        INLINE_CAPACITY,
        "test input must be exactly at capacity"
    );

    let inline_str =
        InlineFlexStr::try_from_type(s).expect("string at exact capacity should inline");
    let flex_str: FlexStr<'_, S, R> = FlexStr::from_inline(inline_str);
    assert!(flex_str.is_inlined());
    assert_eq!(flex_str.as_ref_type(), s);
}

/// Test capacity boundary - string one byte over capacity
/// Input must be smaller than INLINE_CAPACITY
pub fn test_capacity_boundary_overflow<S>(s: &'static S)
where
    S: ?Sized + StringToFromBytes + fmt::Debug + PartialEq,
{
    let bytes = s.self_as_raw_bytes();
    assert!(
        bytes.len() < INLINE_CAPACITY,
        "test input must be smaller than capacity"
    );

    // Since bytes.len() < INLINE_CAPACITY, bytes.len() <= INLINE_CAPACITY is always true
    // So try_from_type should always succeed
    let _inline_str =
        InlineFlexStr::try_from_type(s).expect("string smaller than capacity should succeed");
}

/// Test TryFrom error cases - too long
// Type parameter intentionally unused - kept for API consistency with other test functions
#[allow(unused)]
pub fn test_try_from_too_long() {
    // Create a string that's definitely too long
    // This is tricky to do generically, so we'll test the error type
    let _long_bytes = [0u8; INLINE_CAPACITY + 1];

    // Try to create from bytes if possible
    // This will depend on the specific string type
    // For now, we'll just verify the error type exists
    let err = TooLongForInlining {
        length: INLINE_CAPACITY + 1,
        inline_capacity: INLINE_CAPACITY,
    };

    assert_eq!(err.length, INLINE_CAPACITY + 1);
    assert_eq!(err.inline_capacity, INLINE_CAPACITY);
}

/// Test various string lengths
pub fn test_various_lengths<S, R>(s: &'static S)
where
    S: ?Sized + StringToFromBytes + PartialEq + fmt::Debug,
    R: RefCounted<S>,
    FlexStr<'static, S, R>: StringLike<S>,
{
    let bytes = s.self_as_bytes();
    let len = bytes.len();

    let flex_str: FlexStr<'_, S, R> = FlexStr::from_borrowed(s);

    // Test length matches
    assert_eq!(StringLike::len(&flex_str), len);

    // Test empty check
    assert_eq!(StringLike::is_empty(&flex_str), len == 0);

    // Test that we can always create a borrowed variant
    assert!(flex_str.is_borrowed());

    // Test that we can convert to owned regardless of length
    let owned = flex_str.to_owned();
    assert_eq!(StringLike::len(&owned), len);
    assert_eq!(owned.as_ref_type(), s);
}

/// Test special content (if applicable)
pub fn test_special_content<S, R>(s: &'static S)
where
    S: ?Sized + StringToFromBytes + PartialEq,
    R: RefCounted<S>,
{
    let flex_str: FlexStr<'_, S, R> = FlexStr::from_borrowed(s);

    // Test that special characters/content are preserved
    let bytes = flex_str.as_bytes();
    assert_eq!(bytes, s.self_as_bytes());

    // Test that raw bytes match
    let raw_bytes = flex_str.as_raw_bytes();
    assert_eq!(raw_bytes, s.self_as_raw_bytes());

    // Test conversion preserves content
    let owned = flex_str.to_owned();
    assert_eq!(owned.as_bytes(), bytes);
    assert_eq!(owned.as_raw_bytes(), raw_bytes);
}

/// Test clone with different variants
pub fn test_clone_variants<S, R>(s: &'static S)
where
    S: ?Sized + StringToFromBytes + PartialEq + fmt::Debug,
    R: RefCounted<S> + fmt::Debug,
    Box<S>: From<S::Owned>,
    S::Owned: AsRef<S>,
{
    // Test clone of borrowed
    let borrowed: FlexStr<'_, S, R> = FlexStr::from_borrowed(s);
    let cloned = borrowed.clone();
    assert_eq!(borrowed, cloned);

    // Test clone of inlined (input should be small enough to inline)
    let inline_str =
        InlineFlexStr::try_from_type(s).expect("test input should be small enough to inline");
    let inlined: FlexStr<'_, S, R> = FlexStr::from_inline(inline_str);
    let cloned = inlined.clone();
    assert_eq!(inlined, cloned);

    // Test clone of ref_counted
    let rc: R = s.into();
    let ref_counted: FlexStr<'_, S, R> = FlexStr::from_ref_counted(rc.clone());
    let cloned = ref_counted.clone();
    assert_eq!(ref_counted, cloned);

    // Test clone of boxed
    let boxed: FlexStr<'_, S, R> = FlexStr::from_boxed(Box::from(s.to_owned()));
    let cloned = boxed.clone();
    assert!(matches!(
        cloned,
        FlexStr::Inlined(_) | FlexStr::RefCounted(_)
    ));
    assert_eq!(boxed, cloned);
}