flacenc/
repeat.rs

1// Copyright 2023-2024 Google LLC
2// Copyright 2025- flacenc-rs developers
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Utility for loop-unrolling.
17
18use std::convert::Infallible;
19use std::error::Error;
20
21use seq_macro::seq;
22
23macro_rules! repeat {
24    ($counter:ident to $upto:expr => $body:block) => {
25        <crate::repeat::Count<$upto> as crate::repeat::Repeat>::repeat(
26            #[inline(always)]
27            |$counter| $body,
28        );
29    };
30    ($counter:ident to $upto:expr ; while $cond:expr => $body:block) => {
31        <crate::repeat::Count<$upto> as crate::repeat::Repeat>::repeat_while(
32            #[inline(always)]
33            |$counter| $cond,
34            #[inline(always)]
35            |$counter| $body,
36        )
37    };
38}
39pub(crate) use repeat;
40
41macro_rules! try_repeat {
42    ($counter:ident to $upto:expr ; while $cond:expr => $body:block) => {
43        <crate::repeat::Count<$upto> as crate::repeat::Repeat>::try_repeat_while(
44            #[inline(always)]
45            |$counter| $cond,
46            #[inline(always)]
47            |$counter| $body,
48        )
49    };
50}
51pub(crate) use try_repeat;
52
53/// Repeat trait.
54pub trait Repeat {
55    #[allow(clippy::inline_always)]
56    #[inline(always)]
57    fn repeat<F: FnMut(usize)>(body_fn: F) {
58        Self::repeat_while(
59            #[inline(always)]
60            |_n| true,
61            body_fn,
62        );
63    }
64    #[allow(clippy::inline_always)]
65    #[inline(always)]
66    fn repeat_while<F: FnMut(usize), C: FnMut(usize) -> bool>(cond_fn: C, mut body_fn: F) {
67        Self::try_repeat_while::<Infallible, _, _>(
68            cond_fn,
69            #[inline(always)]
70            |n| {
71                body_fn(n);
72                Ok(())
73            },
74        )
75        .unwrap();
76    }
77    fn try_repeat_while<E: Error, F: FnMut(usize) -> Result<(), E>, C: FnMut(usize) -> bool>(
78        cond_fn: C,
79        body_fn: F,
80    ) -> Result<(), E>;
81}
82
83pub struct Count<const N: usize>;
84
85seq!(M in 1..=32 {
86
87    impl Repeat for Count<M> {
88        #[allow(clippy::inline_always)]
89        #[inline(always)]
90        fn try_repeat_while<E: Error, F: FnMut(usize) -> Result<(), E>, C: FnMut(usize) -> bool>(mut cond_fn: C, mut body_fn: F) -> Result<(), E> {
91            seq!(T in 0..M {
92                if !cond_fn(T) {
93                    return Ok(())
94                }
95                body_fn(T)?;
96            });
97            Ok(())
98        }
99    }
100
101});