I'm trying to use const generics to do compile-time assertion that a value of a type is used at most some usize (e.g. 5, 27, 267) times, let's call it Counter<T, const MAX: usize, const N: usize=0>
.
The type is also a wrapper of another inner type, T
.
To gain guarded access to the inner type, I made another struct as the guard, CounterGuard<T, const N: usize>
.
I have a method count_up(self, value: T)
of Counter
to return a tuple of Counter
and CounterGuard
, Counter
is returned so that another count_up
can be called to get a value of CounterGuard
and CounterGuard
is purely for accessing the value.
The field value
of CounterGuard
is referencing the field value
of the corresponding Counter
value.
Here is the full code:
#![feature(generic_const_exprs)]
struct Counter<T, const MAX: usize, const N: usize=0> {
value: T
}
struct CounterGuard<'a, T, const N: usize> {
value: &'a T
}
impl<T, const MAX: usize> Counter<T, MAX> {
fn new(value: T) -> Counter<T, MAX> {
Counter {
value
}
}
}
impl<T, const MAX: usize, const N: usize> Counter<T, MAX, N> {
const N_MUST_NOT_EXCEED_MAX: () = assert!(N < MAX, "`N` must not exceed `MAX`");
fn count_up<'a>(self, value: T) -> (Counter<T, MAX, { N + 1 }>, CounterGuard<'a, T, { N + 1 }>) {
let _ = Self::N_MUST_NOT_EXCEED_MAX;
let counter = Counter {
value: value
};
let counter_guard = CounterGuard {
value: &counter.value
};
(counter, counter_guard)
}
}
fn main() {
let counter: Counter<i32, 2> = Counter::new(69);
let (counter, counter_guard) = counter.count_up(70);
let (counter, counter_guard) = counter.count_up(71);
let (counter, counter_guard) = counter.count_up(72);
}
I have no problems understanding the errors, which are:
error[E0597]: `counter.value` does not live long enough
--> src/main.rs:27:20
|
23 | let counter = Counter {
| ------- binding `counter` declared here
...
27 | value: &counter.value
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
30 | }
| -- borrow later used here
| |
| `counter.value` dropped here while still borrowed
error[E0505]: cannot move out of `counter` because it is borrowed
--> src/main.rs:29:10
|
23 | let counter = Counter {
| ------- binding `counter` declared here
...
27 | value: &counter.value
| -------------- borrow of `counter.value` occurs here
28 | };
29 | (counter, counter_guard)
| ^^^^^^^ ------------- borrow later used here
| |
| move out of `counter` occurs here
However, my question is, how do I write a tuple of types such that the field of one of the types references to a field of the other types?