craturn 1.0.0

A Rust interpretation of the 'Saturn Devouring His Son' painting.
Documentation
<img width="698" alt="Image" src="https://github.com/user-attachments/assets/22276cf0-9eb2-4df9-91b8-106c176d0c7e" />

<br/>
<br/>

## 🪐 craturn

**A Rust interpretation of the [“Saturn Devouring His Son”](https://en.wikipedia.org/wiki/Saturn_Devouring_His_Son) painting.**

`craturn` is a joke global allocator that slowly, subtly, and nondeterministically **eats
allocated memory**, resulting in corrupted program state over time, while remaining fully
valid Rust code.

It is inspired by [Francisco Goya’s *Saturn Devouring His Son*](https://en.wikipedia.org/wiki/Saturn_Devouring_His_Son).  
Except Saturn here is **your program**, and the son is **its own heap**.

The allocator behaves normally at first.  
Then it starts to *eat*.
<br/>
Sometimes nothing happens.<br/>
Sometimes bits disappear.<br/>
Sometimes values decay.<br/>
Sometimes the program hangs.<br/>
Sometimes everything is fine ... until it isn’t.<br/>

<br/>

<br/>

## ⚠️ Disclaimer

This crate is **intentionally unsafe**, **intentionally incorrect**, and **intentionally evil**.

- Do **not** use in production.
- Do **not** use in benchmarks you care about.
- Do **not** file bugs saying “it broke my program”.

This crate exists for:
- jokes,
- demos,
- chaos testing,
- explaining why memory safety matters,
- terrifying coworkers.

You have been warned.

<br/>

<br/>

## 🧭 What `craturn` Does

Once awakened, `craturn` installs a custom **global allocator** that:

- Allocates memory exactly like the system allocator.
- Tracks long-lived heap allocations.
- Spawns a single background “eater” thread.
- Occasionally eats bits inside live heap objects.
- Replaces eaten bits with zeros.
- Scales its appetite based on a configurable **hunger level**.

Crucially:
- There are **no panics**.
- There are **no explicit crashes**.
- Everything compiles cleanly.
- The damage appears *later*, *elsewhere*, and *without context*.

In other words:  
**your program is being consumed from the inside.**

<br/>

<br/>

## 🍖 Hunger Levels

Hunger controls **how often** and **how much** memory is eaten.

```rust
pub enum Hunger {
    Full,        // Eats nothing.
    Hungry,      // Rare, tiny bites. First bite after a second. Default value.
    Starving,    // More frequent nibbling.
    Devouring,   // Large chunks disappear.
    Insatiable,  // Loud, fast, obvious consumption.
}
```

Higher hunger:
- Eats memory more frequently.
- Removes more bits per bite.
- Converges faster to visible failure.

Lower hunger:
- May take seconds, minutes, or never.
- Is ideal for subtle, deniable breakage.

<br/>

<br/>

## 🛠️ Usage

Add `craturn` as a dependency, then **awaken it**.

```rust
craturn::awaken!(); // Defaults to `Hungry`.
// or
craturn::awaken!(Starving);  // Explicit hunger.
```

That’s it.
<br/>
No function calls.<br/>
No runtime handles.<br/>
No opt-out.<br/>
<br/>
Once awakened, Craturn starts eating.

<br/>

<br/>

## 🧪 Example

```rust
use std::thread;
use std::time::{Duration, Instant};

craturn::awaken!(Starving);

fn main() {
println!("Craturn sanity test");

    let timeout = Duration::from_secs(15);

    println!("Vec corruption test.");
    let v: Vec<u64> = (0..10_000).collect();
    let expected_sum: u64 = (0..10_000u64).sum();
    let start = Instant::now();

    loop {
        println!(".");
        thread::sleep(Duration::from_millis(50));

        let sum: u64 = v.iter().sum();
        if sum != expected_sum {
            println!(
                "🔥 Vec eaten after {:?}: expected {}, got {}",
                start.elapsed(),
                expected_sum,
                sum
            );
            break;
        }

        if start.elapsed() > timeout {
            println!("No visible eating after {:?} (this run)", timeout);
            break;
        }
    }

    println!("String corruption test.");
    let content = "the quick brown fox ";
    let s_expected = content.repeat(10);
    let s = s_expected.clone();
    let start = Instant::now();

    loop {
        thread::sleep(Duration::from_millis(50));

        if s != s_expected {
            println!("🔥 String eaten after {:?}", start.elapsed());
            println!("{s_expected:?}");
            println!("{s:?}");
            break;
        }

        if start.elapsed() > timeout {
            println!("No visible eating after {:?} (this run)", timeout);
            break;
        }
    }

    println!("End.");
}
```

#### Possible outcomes

- Values slowly change in random places (some digits, chars, len, etc.).
- Collections lose elements.
- Program hangs due to eaten state.
- Everything appears fine, for now.

All outcomes are correct.

<br/>

<br/>

## 🧙 Macro Details

The allocator is installed via a macro to keep activation **non-obvious**:

```rust
##[macro_export]
macro_rules! awaken {
    () => {
        $crate::awaken!(Hungry);
    };
    ($hunger:ident) => {
        #[global_allocator]
        static A: craturn::Allocator = craturn::Allocator {
            hunger: craturn::Hunger::$hunger,
        };
    };
}
```

Once expanded, the allocator is global and permanent for the binary.

There is no “stop eating” macro.

<br/>

<br/>

## 🧠 Design Notes

- No locks in allocation paths.
- No heap allocation inside allocator hooks.
- One background eater thread.
- Dense tracking of live allocations.
- Long-lived memory is eaten preferentially.
- Bites are small and localized by default.

This keeps the behavior:
- delayed,
- nondeterministic,
- extremely difficult to trace.

Just like real memory bugs.

<br/>

<br/>

## 🪐 Philosophy

> Saturn does not crash.
> Saturn does not panic.
> Saturn simply eats his son.

`craturn` does the same.

<br/>

<br/>

## 📜 License

MIT OR Apache-2.0  
Choose whichever lets you sleep at night.