Well; strictly speaking it can become part of the type:
#![feature(optin_builtin_traits)]
mod frozen {
use core::{ops::Deref, cell::UnsafeCell, marker::PhantomData};
pub unsafe auto trait Interiorless {}
impl<T: ?Sized> !Interiorless for UnsafeCell<T> {}
unsafe impl<T: ?Sized> Interiorless for PhantomData<T> {}
unsafe impl<T: ?Sized> Interiorless for *const T {}
unsafe impl<T: ?Sized> Interiorless for *mut T {}
unsafe impl<T: ?Sized> Interiorless for &T {}
unsafe impl<T: ?Sized> Interiorless for &mut T {}
pub struct Frozen<T> {
value: T,
}
impl<T> Frozen<T> {
pub fn new(value: T) -> Self {
Self { value }
}
}
impl<T: Interiorless> Deref for Frozen<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
}
The logic of this is that while you may have let mut x = Frozen::new(1);
, there are no &mut
operations on Frozen<u8>
so it is immutable; furthermore, with T: Interiorless
interior mutability is forbidden so that avenue is closed as well. What remains are Clone
, Copy
, and other such "I can recreate T
from &T
facilities" but that's fine under "immutable".
The usefulness of Frozen
is debatable tho.