External Publication
Visit Post

Design idea: Modeling lifetimes as rotational phases

Rust Internals [Unofficial] April 7, 2026
Source

Hi Rust internals folk,

I've been staring at borrow checker errors all weekend (classic), and it got me thinking about a different way to model the whole problem. Instead of the usual linear lifetime segments that Polonius tries to track, I started sketching out a model based on rotational phase-syncing.

The idea is to use Typestate and const generics to treat memory access as a phase-angle on a stationary axis. It’s a bit of a shift, but it seems to handle self-referential patterns surprisingly well by treating them as a 360° completion rather than a lifetime violation.

Here’s a rough look at the core logic:

use std::cell::UnsafeCell;
use std::marker::PhantomData;

/// SigmaAxis: The stationary center point (0°).
pub struct SigmaAxis<T> {
    inner: UnsafeCell<T>,
}

/// Phase: Represents a specific angle on the axis.
/// Leverages the 'Non-Copy' property: a phase cannot be duplicated.
pub struct Phase<'a, T, const ANGLE: u16> {
    axis: &'a SigmaAxis<T>,
    _marker: PhantomData<&'a T>,
}

impl<T> SigmaAxis<T> {
    pub const fn new(data: T) -> Self {
        Self { inner: UnsafeCell::new(data) }
    }

    /// Initializes the system from the zero-point.
    pub fn initialize(&self) -> Phase<'_, T, 0> {
        Phase {
            axis: self,
            _marker: PhantomData,
        }
    }
}

impl<'a, T, const ANGLE: u16> Phase<'a, T, ANGLE> {
    /// Executes an operation at the current phase.
    /// Returns itself or allows chaining.
    pub fn execute<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut T) -> R
    {
        // SAFETY: The Typestate model guarantees that only one phase object
        // exists for this axis at any given time.
        unsafe { f(&mut *self.axis.inner.get()) }
    }

    /// Transitions the system to a new angle by consuming (moving) the previous phase.
    /// This prevents Aliasing: the old angle ceases to exist for the compiler.
    pub fn rotate<const NEXT_ANGLE: u16>(self) -> Phase<'a, T, NEXT_ANGLE> {
        Phase {
            axis: self.axis,
            _marker: PhantomData,
        }
    }

    /// 360° Integration: Returns the system to the zero-point.
    pub fn complete_cycle(self) -> Phase<'a, T, 0> {
        Phase {
            axis: self.axis,
            _marker: PhantomData,
        }
    }
}

fn main() {
    let axis = SigmaAxis::new(100);

    // 1. Start from zero-point
    let phase_0 = axis.initialize();

    // 2. Rotate the cycle: 0 -> 90 -> 180 -> 270 -> 0
    // Each .rotate() consumes the previous variable, preventing illegal references.
    let mut phase_90 = phase_0.rotate::<90>();
    phase_90.execute(|d| *d += 10);

    let mut phase_180 = phase_90.rotate::<180>();
    phase_180.execute(|d| *d *= 2);

    let mut phase_270 = phase_180.rotate::<270>();
    phase_270.execute(|d| *d -= 5);

    // 3. Return to zero-point (360 degrees completed)
    let mut final_sync = phase_270.complete_cycle();

    final_sync.execute(|result| {
        println!("Sigma-Rotation complete. Result: {}", result);
        assert_eq!(*result, 215);
    });

    println!("Geometric integrity verified by the compiler.");
}

By using rotate<const NEXT_ANGLE>(self), the state transitions are explicit and the previous phase is consumed. It feels like a way to get solid soundness without the compiler having to do the heavy path-sensitive lifting we see in NLL.

Curious to hear if this approach to "geometric" state tracking has been explored before or if I'm just over-engineering my weekend project.

Discussion in the ATmosphere

Loading comments...