Skip to content

Pavez7274/kroos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kroos

A zero-cost abstraction over heap allocation and reference counting for ?Sized types, built for performance-critical systems with manual memory control.

Discord Ask DeepWiki

Why this exists

While developing kodrst, we encountered non-trivial overhead from using Arc<str> in performance-sensitive paths. Even in immutable scenarios, Arc introduces unnecessary synchronization and layout complexity. kroos provides low-level primitives (Flake, Rime) designed to bypass these costs entirely, trading away safety and general-purpose semantics in favor of raw performance.

When to use kroos

  • You want to store unsized data like str or [u8] on the heap with no overhead.
  • You want shared ownership over unsized types, but don't want to pay for Arc or Rc.
  • You need maximum control over memory layout, reference counting, or allocation.
  • You can guarantee safe memory usage manually (e.g., no Drop, aliasing, or race conditions).

When not to use

  • Your types require Drop, or have complex ownership semantics.
  • You want ergonomic or type-safe abstractions.
  • You're not prepared to work at the raw pointer level.

Flake<T: ?Sized>

A Box-like wrapper for unsized types without ownership semantics. It provides heap allocation for types like str, [u8], or any ?Sized data using raw pointers.

Flake::new

Allocates a copy of a referenced ?Sized object to the heap.

let flake = Flake::new("hello");
assert_eq!(&*flake, "hello");

Flake::steal

Moves a Sized value directly into the heap, without duplication.

let flake = Flake::steal(String::from("hi"));
assert_eq!(&*flake, "hi");

Memory layout

A Flake<T> contains a single fat pointer to the heap-allocated value. It does not store length or capacity explicitly — metadata is embedded in the fat pointer.

Safe mutability

While Flake is primarily intended for immutable data, controlled mutation is allowed:

let mut flake = Flake::new(&[1, 2, 3][..]);
unsafe { (*flake.as_mut_ptr())[0] = 42; }
assert_eq!(&*flake, &[42, 2, 3]);

Caution

Use only if you guarantee exclusive access.

Rime<C, T: ?Sized>

A compact, inline, reference-counted pointer to unsized types, using a custom Counter.

Features

  • Fully inline: Rime stores [ Counter | Data ] in one allocation.
  • Works with dynamically sized types (str, [u8], etc.)
  • Counter-agnostic: atomic or non-atomic counters via Rime<AtomicU8, str> or Rime<Cell<u8>, str>.
  • No vtable, no indirection.

Rime::new

Copies a reference to heap and initializes a new refcount.

let rime = Rime::<AtomicU8, str>::new("hello");
let clone = rime.clone();
assert_eq!(&*clone, "hello");

Rime::steal

Takes ownership of a Sized value and moves it into a single block.

let rime = Rime::<u8, String>::steal("hi".to_string());
assert_eq!(&*rime, "hi".to_string());

Safe mutability

If you use a Cell<u8> counter (or similar interior-mutable strategy), you can achieve safe mutability under the following constraints:

  1. Rime must not be cloned (i.e. you must be the only owner).
  2. Use as_mut_ptr to mutate contents in-place.
  3. You are responsible for enforcing Rust’s aliasing rules manually.

Handling growth and capacity

You can store metadata in a header format like:

[ Counter | Metadata | Data ]
            ↑          ↑
         len/cap       T

For example, a fixed-capacity string-like object might store len as a usize, followed by a zero-terminated buffer. On mutation:

  1. Update len manually.
  2. Overwrite data in-place within bounds.

This enables a fixed-capacity "string" stored inline, avoiding reallocation.

Avoiding stack-to-heap moves

Flake::from_raw and Rime::from_raw allow you to construct heap-backed references without the intermediate cost of stack allocation followed by a move. Instead of creating a Box<T> or Vec<T> and extracting its pointer, you can allocate memory and write directly into it.

For example, to create a *mut str without touching the stack:

pub unsafe fn alloc_str_and_write(bytes: &[u8]) -> *mut str {
    let len = bytes.len();
    let ptr = alloc(Layout::array::<u8>(len).unwrap());
    
    // You can handle layouts errors checking ptr.in_null()

    ptr.copy_from_nonoverlapping(bytes.as_ptr(), len);
    ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
}

You can then wrap the result into a Flake:

let raw = unsafe { alloc_str_and_write(b"hola") };
let flake = unsafe { Flake::from_raw(raw) };

This pattern avoids temporary allocations or extra indirection like:

let boxed = Box::new(value);     // Allocates and moves
let flake = Flake::new(&*boxed); // Copies again

Instead, you allocate once and write directly where the value will live.

Note

Box is optimized for sometimes do a placement-in protocol-like.

Comparison Table

Feature Box / Arc Flake / Rime
Works with ?Sized ✅ (Box)
Custom counter
Atomic optional ✅ (Arc) ✅ (via AtomicU*)
Inline allocation
Copy or move control
Drop safety ❌ (must be manual)

Safety Warnings

  • Flake and Rime bypass Drop, Clone, and Rust's ownership model.
  • Do not use with types that manage heap resources or contain non-Copy fields.
  • You are responsible for:
    • Ensuring uniqueness or correct refcounting.
    • Avoiding data races (use Atomic* if needed).
    • Deallocating correctly (done automatically, but only if created via safe constructors).

Contributing & Attribution

This project is licensed under the GNU AGPL v3.

All contributions must retain clear attribution to the original author(s).
If you modify or extend this project, please include appropriate credit in your repository and documentation.

In particular:

  • Keep the original copyright notices.
  • If publishing a fork, mention the original project name and link in your README.
  • If you use this project as a dependency, consider acknowledging it in your LICENSE or README.

I believe in free software and shared credit.

Contributors

Kaffssist

This crate exists to explore precision memory control and support edge-case optimizations in projects like kodrst. It is not intended as a general-purpose utility. If you're using Flake or Rime outside internal systems, you're either very brave — or very desperate...

About

Flexible smart pointer for ?Sized types with customizable reference counting.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages