Skip to content

Commit 261914a

Browse files
committed
refactor(core): use Range: const Iterator and const_for
[rust-lang/rust#104100][1] has implemented `std::ops::Range: const Iterator`, resolving `[tag:range_const_iterator]`. [1]: rust-lang/rust#104100
1 parent 211cabb commit 261914a

File tree

8 files changed

+100
-135
lines changed

8 files changed

+100
-135
lines changed

doc/toolchain_limitations.md

+18-20
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ type Alias<T> = Struct<{<T as Trait>::N}>;
106106

107107
### `[tag:const_for]` `for` loops are unusable in `const fn`
108108

109-
Technically it's available under the compiler feature `const_for`, but the lack of essential trait implementations (e.g., `[ref:range_const_iterator]`, `[ref:const_slice_iter]`) makes it unusable in many cases.
109+
Technically it's available under the compiler feature `const_for`, but the lack of essential trait implementations (e.g., `[ref:const_slice_iter]`, `[ref:const_rev_iter]`) makes it unusable in many cases.
110110

111111

112112
### `[tag:const_static_item_ref]` `const`s and `const fn`s can't refer to `static`s
@@ -296,6 +296,23 @@ const _: () = { b"".iter(); };
296296
```
297297

298298

299+
### `[tag:const_rev_iter]` `Rev` is not `const Iterator`
300+
301+
```rust
302+
for _ in (0..4).rev() {}
303+
```
304+
305+
```rust,compile_fail,E0277
306+
#![feature(const_intoiterator_identity)]
307+
#![feature(const_trait_impl)]
308+
#![feature(const_mut_refs)]
309+
#![feature(const_for)]
310+
// error[E0277]: the trait bound `Rev<std::ops::Range<i32>>: ~const Iterator`
311+
// is not satisfied
312+
const _: () = for _ in (0..4).rev() {};
313+
```
314+
315+
299316
### `[tag:const_uninit_array]` `MaybeUninit::uninit_array` is unstable
300317

301318
```rust,compile_fail,E0658
@@ -430,25 +447,6 @@ const _: () = assert!(PartialEq::eq(&(A..A), &(A..A)));
430447
```
431448

432449

433-
### `[tag:range_const_iterator]` `Range<T>: !~const Iterator`
434-
435-
The standard library doesn't provide a `const` trait implementation of `Range<T>: Iterator`.
436-
437-
```rust
438-
assert!(matches!((2..4).next(), Some(2)));
439-
```
440-
441-
```rust,compile_fail,E0277
442-
#![feature(const_trait_impl)]
443-
#![feature(const_mut_refs)]
444-
// `assert!` is used here due to [ref:const_assert_eq]
445-
// `matches!` is used here due to [ref:option_const_partial_eq]
446-
// error[E0277]: the trait bound `std::ops::Range<i32>: ~const Iterator` is not
447-
// satisfied
448-
const _: () = assert!(matches!((2..4).next(), Some(2)));
449-
```
450-
451-
452450
### `[tag:const_assert_eq]` `assert_eq!` and similar macros are unusable in `const fn`
453451

454452
```rust,compile_fail,E0015

src/r3_core/src/bind.rs

+7-18
Original file line numberDiff line numberDiff line change
@@ -790,11 +790,8 @@ impl<'pool, const LEN: usize, System, T> const UnzipBind for Bind<'pool, System,
790790
let mut out =
791791
ComptimeVec::new_in(self.bind_registry.borrow().binds.allocator().clone());
792792

793-
// `for` loops are unusable in `const fn` [ref:const_for]
794-
let mut i = 0;
795-
while i < LEN {
793+
for i in 0..LEN {
796794
out.push(divide.slice(hunk.transmute::<BindData<T>>().wrapping_offset(i as isize)));
797-
i += 1;
798795
}
799796

800797
out.to_array()
@@ -988,10 +985,8 @@ impl CfgBindRegistry {
988985
// Because of [ref:bind_finalization_immediate_panic], reaching here
989986
// means the operation was successful
990987

991-
// `for` loops are barely useful in `const fn` at the moment
992-
// [ref:const_for]
993-
let mut i = 0;
994-
while i < callback.bind_init_order.len() {
988+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
989+
for i in 0..callback.bind_init_order.len() {
995990
let bind_i = callback.bind_init_order[i];
996991

997992
if let Some(initializer) = self.binds[bind_i].initializer {
@@ -1000,8 +995,6 @@ impl CfgBindRegistry {
1000995
.priority(INIT_HOOK_PRIORITY)
1001996
.finish(cfg);
1002997
}
1003-
1004-
i += 1;
1005998
}
1006999
}
10071000
}
@@ -1784,11 +1777,9 @@ where
17841777
type Runtime = [Binder::Runtime; LEN];
17851778

17861779
fn register_dependency(&self, ctx: &mut CfgBindCtx<'_>) {
1787-
// `for` loops are unusable in `const fn` [ref:const_for]
1788-
let mut i = 0;
1789-
while i < LEN {
1780+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
1781+
for i in 0..LEN {
17901782
self[i].register_dependency(ctx);
1791-
i += 1;
17921783
}
17931784
}
17941785

@@ -1797,17 +1788,15 @@ where
17971788
// `[T; N]::map` is unusable in `const fn` [ref:const_array_map]
17981789
let mut out = MaybeUninit::uninit_array();
17991790
let this = MaybeUninit::new(self);
1800-
// `for` loops are unusable in `const fn` [ref:const_for]
1801-
let mut i = 0;
1802-
while i < LEN {
1791+
// `[T]::iter_mut` is unusable in `const fn` [ref:const_slice_iter]
1792+
for i in 0..LEN {
18031793
out[i] = MaybeUninit::new(
18041794
this.as_ptr()
18051795
.cast::<Binder>()
18061796
.wrapping_add(i)
18071797
.read()
18081798
.into_runtime_binder(),
18091799
);
1810-
i += 1;
18111800
}
18121801
// Safety: All elements of `out` are initialized
18131802
MaybeUninit::array_assume_init(out)

src/r3_core/src/bind/sorter.rs

+53-62
Original file line numberDiff line numberDiff line change
@@ -160,75 +160,66 @@ pub(super) const fn sort_bindings<Callback, SorterUseInfoList, VertexList>(
160160
assert!(temp_uses.is_empty());
161161
assert!(temp_vertices.is_empty());
162162

163-
{
164-
// `for` loops are unusable in `const fn` [ref:const_for]
165-
let mut bind_i = 0;
166-
while bind_i < num_binds {
167-
let bind_users = cb.bind_users(bind_i);
168-
169-
let mut num_indefinite_shared = 0;
170-
let mut num_indefinite_exclusive = 0;
171-
172-
// `for` loops are unusable in `const fn` [ref:const_for]
173-
let mut i = 0;
174-
while i < bind_users.len() {
175-
// Reject impossible combinations that should be caught earlier
176-
match bind_users[i] {
177-
(BindUsage::Bind(_), BindBorrowType::Borrow)
178-
| (BindUsage::Bind(_), BindBorrowType::BorrowMut)
179-
| (BindUsage::Bind(_), BindBorrowType::Take)
180-
| (BindUsage::Bind(_), BindBorrowType::TakeRef)
181-
| (BindUsage::Bind(_), BindBorrowType::TakeMut)
182-
| (BindUsage::Executable, BindBorrowType::Take)
183-
| (BindUsage::Executable, BindBorrowType::TakeRef)
184-
| (BindUsage::Executable, BindBorrowType::TakeMut) => {}
185-
// [ref:borrow_is_indefinite_for_executable]
186-
(BindUsage::Executable, BindBorrowType::Borrow)
187-
| (BindUsage::Executable, BindBorrowType::BorrowMut) => {
188-
unreachable!()
189-
}
163+
for bind_i in 0..num_binds {
164+
let bind_users = cb.bind_users(bind_i);
165+
166+
let mut num_indefinite_shared = 0;
167+
let mut num_indefinite_exclusive = 0;
168+
169+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
170+
for i in 0..bind_users.len() {
171+
// Reject impossible combinations that should be caught earlier
172+
match bind_users[i] {
173+
(BindUsage::Bind(_), BindBorrowType::Borrow)
174+
| (BindUsage::Bind(_), BindBorrowType::BorrowMut)
175+
| (BindUsage::Bind(_), BindBorrowType::Take)
176+
| (BindUsage::Bind(_), BindBorrowType::TakeRef)
177+
| (BindUsage::Bind(_), BindBorrowType::TakeMut)
178+
| (BindUsage::Executable, BindBorrowType::Take)
179+
| (BindUsage::Executable, BindBorrowType::TakeRef)
180+
| (BindUsage::Executable, BindBorrowType::TakeMut) => {}
181+
// [ref:borrow_is_indefinite_for_executable]
182+
(BindUsage::Executable, BindBorrowType::Borrow)
183+
| (BindUsage::Executable, BindBorrowType::BorrowMut) => {
184+
unreachable!()
190185
}
186+
}
191187

192-
// Count indefinite borrows
193-
match bind_users[i].1 {
194-
BindBorrowType::Borrow | BindBorrowType::BorrowMut => {}
195-
BindBorrowType::TakeRef => {
196-
num_indefinite_shared += 1;
197-
}
198-
BindBorrowType::Take | BindBorrowType::TakeMut => {
199-
num_indefinite_exclusive += 1;
200-
}
188+
// Count indefinite borrows
189+
match bind_users[i].1 {
190+
BindBorrowType::Borrow | BindBorrowType::BorrowMut => {}
191+
BindBorrowType::TakeRef => {
192+
num_indefinite_shared += 1;
201193
}
202-
203-
// Collect dependencies in the reverse direction
204-
if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] {
205-
let use_i = temp_uses.len();
206-
let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i;
207-
temp_uses.push(SorterUseInfo {
208-
bind_i,
209-
borrow_type,
210-
next_use_i: *other_bind_first_use_i,
211-
});
212-
*other_bind_first_use_i = Some(use_i);
194+
BindBorrowType::Take | BindBorrowType::TakeMut => {
195+
num_indefinite_exclusive += 1;
213196
}
214-
215-
i += 1;
216197
}
217198

218-
temp_binds1[bind_i].borrowed_indefinitely =
219-
match (num_indefinite_shared, num_indefinite_exclusive) {
220-
(0, 0) => None,
221-
(_, 0) => Some(false),
222-
(0, 1) => Some(true),
223-
_ => {
224-
// [ref:bind_conflicting_take]
225-
cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i });
226-
Some(false)
227-
}
228-
};
229-
230-
bind_i += 1;
199+
// Collect dependencies in the reverse direction
200+
if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] {
201+
let use_i = temp_uses.len();
202+
let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i;
203+
temp_uses.push(SorterUseInfo {
204+
bind_i,
205+
borrow_type,
206+
next_use_i: *other_bind_first_use_i,
207+
});
208+
*other_bind_first_use_i = Some(use_i);
209+
}
231210
}
211+
212+
temp_binds1[bind_i].borrowed_indefinitely =
213+
match (num_indefinite_shared, num_indefinite_exclusive) {
214+
(0, 0) => None,
215+
(_, 0) => Some(false),
216+
(0, 1) => Some(true),
217+
_ => {
218+
// [ref:bind_conflicting_take]
219+
cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i });
220+
Some(false)
221+
}
222+
};
232223
}
233224

234225
// Helper types needed for topological sorting. `Vertex` is defined outside

src/r3_core/src/kernel/interrupt.rs

+12-22
Original file line numberDiff line numberDiff line change
@@ -433,28 +433,22 @@ pub(super) const fn panic_if_unmanaged_safety_is_violated<System: raw::KernelInt
433433
interrupt_lines: &ComptimeVec<CfgInterruptLineInfo>,
434434
interrupt_handlers: &ComptimeVec<CfgInterruptHandler>,
435435
) {
436-
// `for` is unusable in `const fn` [ref:const_for]
437-
let mut i = 0;
438-
while i < interrupt_handlers.len() {
436+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
437+
for i in 0..interrupt_handlers.len() {
439438
let handler = &interrupt_handlers[i];
440-
i += 1;
441439
if handler.unmanaged {
442440
continue;
443441
}
444442

445-
let is_line_assumed_managed = {
443+
let is_line_assumed_managed = 'a: {
446444
let lines = System::RAW_MANAGED_INTERRUPT_LINES;
447-
let mut i = 0;
448-
loop {
449-
if i < lines.len() {
450-
if lines[i] == handler.line {
451-
break true;
452-
}
453-
i += 1;
454-
} else {
455-
break false;
445+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
446+
for i in 0..lines.len() {
447+
if lines[i] == handler.line {
448+
break 'a true;
456449
}
457450
}
451+
false
458452
};
459453

460454
let managed_line_i = vec_position!(interrupt_lines, |line| line.num == handler.line
@@ -663,12 +657,10 @@ pub const unsafe fn new_interrupt_handler_table<
663657
assert!(NumLines::N == NUM_LINES);
664658
assert!(Handlers::NumHandlers::N == NUM_HANDLERS);
665659

666-
// `for` is unusable in `const fn` [ref:const_for]
667-
let mut i = 0;
668-
while i < NUM_HANDLERS {
660+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
661+
for i in 0..NUM_HANDLERS {
669662
let handler = Handlers::HANDLERS[i];
670663
assert!(handler.line < NUM_LINES);
671-
i += 1;
672664
}
673665

674666
const_array_from_fn! {
@@ -702,14 +694,12 @@ pub const unsafe fn new_interrupt_handler_table<
702694

703695
#[doc(hidden)]
704696
pub const fn num_required_interrupt_line_slots(handlers: &[CfgInterruptHandler]) -> usize {
705-
// `for` is unusable in `const fn` [ref:const_for]
706-
let mut i = 0;
697+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
707698
let mut out = 0;
708-
while i < handlers.len() {
699+
for i in 0..handlers.len() {
709700
if handlers[i].line + 1 > out {
710701
out = handlers[i].line + 1;
711702
}
712-
i += 1;
713703
}
714704
out
715705
}

src/r3_core/src/kernel/raw.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -268,18 +268,16 @@ impl QueueOrder {
268268
QueueOrder::TaskPriority => QueueOrderKind::TaskPriority,
269269
};
270270

271-
// `for` is unusable in `const fn` [ref:const_for]
272-
let mut i = 0;
271+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
273272
let values = System::RAW_SUPPORTED_QUEUE_ORDERS;
274-
while i < values.len() {
273+
for i in 0..values.len() {
275274
// `#[derive(PartialEq)]` doesn't derive `const PartialEq`
276275
// [ref:derive_const_partial_eq]
277276
if let Some(value) = values[i] {
278277
if value as u8 == kind as u8 {
279278
return true;
280279
}
281280
}
282-
i += 1;
283281
}
284282
false
285283
}
@@ -537,18 +535,16 @@ impl MutexProtocol {
537535
MutexProtocol::Ceiling(_) => MutexProtocolKind::Ceiling,
538536
};
539537

540-
// `for` is unusable in `const fn` [ref:const_for]
541-
let mut i = 0;
538+
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
542539
let values = System::RAW_SUPPORTED_MUTEX_PROTOCOLS;
543-
while i < values.len() {
540+
for i in 0..values.len() {
544541
// `#[derive(PartialEq)]` doesn't derive `const PartialEq`
545542
// [ref:derive_const_partial_eq]
546543
if let Some(value) = values[i] {
547544
if value as u8 == kind as u8 {
548545
return true;
549546
}
550547
}
551-
i += 1;
552548
}
553549
false
554550
}

src/r3_core/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![feature(maybe_uninit_array_assume_init)]
88
#![feature(const_maybe_uninit_as_mut_ptr)]
99
#![feature(nonnull_slice_from_raw_parts)]
10+
#![feature(const_intoiterator_identity)]
1011
#![feature(type_changing_struct_update)]
1112
#![feature(maybe_uninit_uninit_array)]
1213
#![feature(const_precise_live_drops)]
@@ -41,9 +42,11 @@
4142
#![feature(cell_update)]
4243
#![feature(const_deref)]
4344
#![feature(const_heap)]
45+
#![feature(const_iter)]
4446
#![feature(const_swap)]
4547
#![feature(decl_macro)]
4648
#![feature(never_type)] // `!`
49+
#![feature(const_for)]
4750
#![feature(const_try)]
4851
#![feature(fn_traits)] // `impl FnOnce`
4952
#![feature(doc_cfg)] // `#[doc(cfg(...))]`

0 commit comments

Comments
 (0)