Closed imbolc closed 1 year ago
You don't need typestate here -- if you statically know that &OnceCell<T>
is initialized, you can use &T
.
By "statically know" you mean static N: Lazy<i32> = Lazy::new(|| 42);
? If so it's almost all of my use cases require runtime initialization (like reading an parsing a file). Then I should match on .get()
s option each time which is inconvenient, or use &T
without compile time guaranties of initialization.
Could you give a small example of your use-case? Basically, what I think should work is to match on .get
once, and then thread the resulting &T
, but it's hard to know if that'll work without a specific example.
The docs example will do: https://docs.rs/once_cell/1.8.0/once_cell/index.html#safe-initialization-of-global-data
A call of Logger::global()
before INSTANCE.set(..)
will panic.
Yeah, if that's a concern, it is possible to remove global
function at all, and pass &'static Logger
to any code which needs a logger. &'static
is Copy and doesn't have lifeitems, so that should be pretty ergonomic.
Do you mean passing the reference as an argument? I thought the whole point of once_cell
is having "globals". With passing through arguments why not just initialize the logger and use a usual reference?
Yeah, I mean passing as an argument. I think with any kind of typestate you'd have to pass an argument though?
I thought of this, but I missed type changing in set()
:) Maybe it can be done somehow, maybe by unsafe, because type essentially stay the same?
use std::marker::PhantomData;
struct Cell<T, S> {
payload: Option<T>,
state: PhantomData<S>,
}
struct Empty;
struct Full;
impl<T, S> Cell<T, S> {
fn new() -> Cell<T, Empty> {
Cell {
payload: None,
state: PhantomData,
}
}
}
impl<T> Cell<T, Empty> {
fn set(&self, payload: T) -> Cell<T, Full> {
// I thought I could somehow mess with self here instead of returning a new instance
Cell {
payload: Some(payload),
state: PhantomData,
}
}
}
impl<T> Cell<T, Full> {
fn get(&self) -> &T {
self.payload.as_ref().unwrap()
}
}
fn main() {
let empty = Cell::<i32, Empty>::new();
let full = empty.set(1);
assert_eq!(full.get(), &1);
}
I think at this point its best to experiment with this kinds of API in a different crate!
Isn't it possible to get rid of
Option
inget()
via typestate pattern (making the method available only for an initialized cell)?