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.