Skip to content

Commit

Permalink
refactor(core): use Range: const Iterator and const_for
Browse files Browse the repository at this point in the history
[rust-lang/rust#104100][1] has implemented `std::ops::Range: const
Iterator`, resolving `[tag:range_const_iterator]`.

[1]: rust-lang/rust#104100
  • Loading branch information
yvt committed Mar 21, 2023
1 parent 211cabb commit 261914a
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 135 deletions.
38 changes: 18 additions & 20 deletions doc/toolchain_limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ type Alias<T> = Struct<{<T as Trait>::N}>;

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

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.
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.


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


### `[tag:const_rev_iter]` `Rev` is not `const Iterator`

```rust
for _ in (0..4).rev() {}
```

```rust,compile_fail,E0277
#![feature(const_intoiterator_identity)]
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
#![feature(const_for)]
// error[E0277]: the trait bound `Rev<std::ops::Range<i32>>: ~const Iterator`
// is not satisfied
const _: () = for _ in (0..4).rev() {};
```


### `[tag:const_uninit_array]` `MaybeUninit::uninit_array` is unstable

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


### `[tag:range_const_iterator]` `Range<T>: !~const Iterator`

The standard library doesn't provide a `const` trait implementation of `Range<T>: Iterator`.

```rust
assert!(matches!((2..4).next(), Some(2)));
```

```rust,compile_fail,E0277
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
// `assert!` is used here due to [ref:const_assert_eq]
// `matches!` is used here due to [ref:option_const_partial_eq]
// error[E0277]: the trait bound `std::ops::Range<i32>: ~const Iterator` is not
// satisfied
const _: () = assert!(matches!((2..4).next(), Some(2)));
```


### `[tag:const_assert_eq]` `assert_eq!` and similar macros are unusable in `const fn`

```rust,compile_fail,E0015
Expand Down
25 changes: 7 additions & 18 deletions src/r3_core/src/bind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,11 +790,8 @@ impl<'pool, const LEN: usize, System, T> const UnzipBind for Bind<'pool, System,
let mut out =
ComptimeVec::new_in(self.bind_registry.borrow().binds.allocator().clone());

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

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

// `for` loops are barely useful in `const fn` at the moment
// [ref:const_for]
let mut i = 0;
while i < callback.bind_init_order.len() {
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..callback.bind_init_order.len() {
let bind_i = callback.bind_init_order[i];

if let Some(initializer) = self.binds[bind_i].initializer {
Expand All @@ -1000,8 +995,6 @@ impl CfgBindRegistry {
.priority(INIT_HOOK_PRIORITY)
.finish(cfg);
}

i += 1;
}
}
}
Expand Down Expand Up @@ -1784,11 +1777,9 @@ where
type Runtime = [Binder::Runtime; LEN];

fn register_dependency(&self, ctx: &mut CfgBindCtx<'_>) {
// `for` loops are unusable in `const fn` [ref:const_for]
let mut i = 0;
while i < LEN {
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..LEN {
self[i].register_dependency(ctx);
i += 1;
}
}

Expand All @@ -1797,17 +1788,15 @@ where
// `[T; N]::map` is unusable in `const fn` [ref:const_array_map]
let mut out = MaybeUninit::uninit_array();
let this = MaybeUninit::new(self);
// `for` loops are unusable in `const fn` [ref:const_for]
let mut i = 0;
while i < LEN {
// `[T]::iter_mut` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..LEN {
out[i] = MaybeUninit::new(
this.as_ptr()
.cast::<Binder>()
.wrapping_add(i)
.read()
.into_runtime_binder(),
);
i += 1;
}
// Safety: All elements of `out` are initialized
MaybeUninit::array_assume_init(out)
Expand Down
115 changes: 53 additions & 62 deletions src/r3_core/src/bind/sorter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,75 +160,66 @@ pub(super) const fn sort_bindings<Callback, SorterUseInfoList, VertexList>(
assert!(temp_uses.is_empty());
assert!(temp_vertices.is_empty());

{
// `for` loops are unusable in `const fn` [ref:const_for]
let mut bind_i = 0;
while bind_i < num_binds {
let bind_users = cb.bind_users(bind_i);

let mut num_indefinite_shared = 0;
let mut num_indefinite_exclusive = 0;

// `for` loops are unusable in `const fn` [ref:const_for]
let mut i = 0;
while i < bind_users.len() {
// Reject impossible combinations that should be caught earlier
match bind_users[i] {
(BindUsage::Bind(_), BindBorrowType::Borrow)
| (BindUsage::Bind(_), BindBorrowType::BorrowMut)
| (BindUsage::Bind(_), BindBorrowType::Take)
| (BindUsage::Bind(_), BindBorrowType::TakeRef)
| (BindUsage::Bind(_), BindBorrowType::TakeMut)
| (BindUsage::Executable, BindBorrowType::Take)
| (BindUsage::Executable, BindBorrowType::TakeRef)
| (BindUsage::Executable, BindBorrowType::TakeMut) => {}
// [ref:borrow_is_indefinite_for_executable]
(BindUsage::Executable, BindBorrowType::Borrow)
| (BindUsage::Executable, BindBorrowType::BorrowMut) => {
unreachable!()
}
for bind_i in 0..num_binds {
let bind_users = cb.bind_users(bind_i);

let mut num_indefinite_shared = 0;
let mut num_indefinite_exclusive = 0;

// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..bind_users.len() {
// Reject impossible combinations that should be caught earlier
match bind_users[i] {
(BindUsage::Bind(_), BindBorrowType::Borrow)
| (BindUsage::Bind(_), BindBorrowType::BorrowMut)
| (BindUsage::Bind(_), BindBorrowType::Take)
| (BindUsage::Bind(_), BindBorrowType::TakeRef)
| (BindUsage::Bind(_), BindBorrowType::TakeMut)
| (BindUsage::Executable, BindBorrowType::Take)
| (BindUsage::Executable, BindBorrowType::TakeRef)
| (BindUsage::Executable, BindBorrowType::TakeMut) => {}
// [ref:borrow_is_indefinite_for_executable]
(BindUsage::Executable, BindBorrowType::Borrow)
| (BindUsage::Executable, BindBorrowType::BorrowMut) => {
unreachable!()
}
}

// Count indefinite borrows
match bind_users[i].1 {
BindBorrowType::Borrow | BindBorrowType::BorrowMut => {}
BindBorrowType::TakeRef => {
num_indefinite_shared += 1;
}
BindBorrowType::Take | BindBorrowType::TakeMut => {
num_indefinite_exclusive += 1;
}
// Count indefinite borrows
match bind_users[i].1 {
BindBorrowType::Borrow | BindBorrowType::BorrowMut => {}
BindBorrowType::TakeRef => {
num_indefinite_shared += 1;
}

// Collect dependencies in the reverse direction
if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] {
let use_i = temp_uses.len();
let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i;
temp_uses.push(SorterUseInfo {
bind_i,
borrow_type,
next_use_i: *other_bind_first_use_i,
});
*other_bind_first_use_i = Some(use_i);
BindBorrowType::Take | BindBorrowType::TakeMut => {
num_indefinite_exclusive += 1;
}

i += 1;
}

temp_binds1[bind_i].borrowed_indefinitely =
match (num_indefinite_shared, num_indefinite_exclusive) {
(0, 0) => None,
(_, 0) => Some(false),
(0, 1) => Some(true),
_ => {
// [ref:bind_conflicting_take]
cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i });
Some(false)
}
};

bind_i += 1;
// Collect dependencies in the reverse direction
if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] {
let use_i = temp_uses.len();
let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i;
temp_uses.push(SorterUseInfo {
bind_i,
borrow_type,
next_use_i: *other_bind_first_use_i,
});
*other_bind_first_use_i = Some(use_i);
}
}

temp_binds1[bind_i].borrowed_indefinitely =
match (num_indefinite_shared, num_indefinite_exclusive) {
(0, 0) => None,
(_, 0) => Some(false),
(0, 1) => Some(true),
_ => {
// [ref:bind_conflicting_take]
cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i });
Some(false)
}
};
}

// Helper types needed for topological sorting. `Vertex` is defined outside
Expand Down
34 changes: 12 additions & 22 deletions src/r3_core/src/kernel/interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,28 +433,22 @@ pub(super) const fn panic_if_unmanaged_safety_is_violated<System: raw::KernelInt
interrupt_lines: &ComptimeVec<CfgInterruptLineInfo>,
interrupt_handlers: &ComptimeVec<CfgInterruptHandler>,
) {
// `for` is unusable in `const fn` [ref:const_for]
let mut i = 0;
while i < interrupt_handlers.len() {
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..interrupt_handlers.len() {
let handler = &interrupt_handlers[i];
i += 1;
if handler.unmanaged {
continue;
}

let is_line_assumed_managed = {
let is_line_assumed_managed = 'a: {
let lines = System::RAW_MANAGED_INTERRUPT_LINES;
let mut i = 0;
loop {
if i < lines.len() {
if lines[i] == handler.line {
break true;
}
i += 1;
} else {
break false;
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..lines.len() {
if lines[i] == handler.line {
break 'a true;
}
}
false
};

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

// `for` is unusable in `const fn` [ref:const_for]
let mut i = 0;
while i < NUM_HANDLERS {
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
for i in 0..NUM_HANDLERS {
let handler = Handlers::HANDLERS[i];
assert!(handler.line < NUM_LINES);
i += 1;
}

const_array_from_fn! {
Expand Down Expand Up @@ -702,14 +694,12 @@ pub const unsafe fn new_interrupt_handler_table<

#[doc(hidden)]
pub const fn num_required_interrupt_line_slots(handlers: &[CfgInterruptHandler]) -> usize {
// `for` is unusable in `const fn` [ref:const_for]
let mut i = 0;
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
let mut out = 0;
while i < handlers.len() {
for i in 0..handlers.len() {
if handlers[i].line + 1 > out {
out = handlers[i].line + 1;
}
i += 1;
}
out
}
12 changes: 4 additions & 8 deletions src/r3_core/src/kernel/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,18 +268,16 @@ impl QueueOrder {
QueueOrder::TaskPriority => QueueOrderKind::TaskPriority,
};

// `for` is unusable in `const fn` [ref:const_for]
let mut i = 0;
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
let values = System::RAW_SUPPORTED_QUEUE_ORDERS;
while i < values.len() {
for i in 0..values.len() {
// `#[derive(PartialEq)]` doesn't derive `const PartialEq`
// [ref:derive_const_partial_eq]
if let Some(value) = values[i] {
if value as u8 == kind as u8 {
return true;
}
}
i += 1;
}
false
}
Expand Down Expand Up @@ -537,18 +535,16 @@ impl MutexProtocol {
MutexProtocol::Ceiling(_) => MutexProtocolKind::Ceiling,
};

// `for` is unusable in `const fn` [ref:const_for]
let mut i = 0;
// `[T]::iter` is unusable in `const fn` [ref:const_slice_iter]
let values = System::RAW_SUPPORTED_MUTEX_PROTOCOLS;
while i < values.len() {
for i in 0..values.len() {
// `#[derive(PartialEq)]` doesn't derive `const PartialEq`
// [ref:derive_const_partial_eq]
if let Some(value) = values[i] {
if value as u8 == kind as u8 {
return true;
}
}
i += 1;
}
false
}
Expand Down
3 changes: 3 additions & 0 deletions src/r3_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#![feature(maybe_uninit_array_assume_init)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(const_intoiterator_identity)]
#![feature(type_changing_struct_update)]
#![feature(maybe_uninit_uninit_array)]
#![feature(const_precise_live_drops)]
Expand Down Expand Up @@ -41,9 +42,11 @@
#![feature(cell_update)]
#![feature(const_deref)]
#![feature(const_heap)]
#![feature(const_iter)]
#![feature(const_swap)]
#![feature(decl_macro)]
#![feature(never_type)] // `!`
#![feature(const_for)]
#![feature(const_try)]
#![feature(fn_traits)] // `impl FnOnce`
#![feature(doc_cfg)] // `#[doc(cfg(...))]`
Expand Down
Loading

0 comments on commit 261914a

Please sign in to comment.