Similar to how x.clamp(min, max) will put x into the range min..=max by clamping it within bounds, there should be an x.wrap(min, max) to put x into the range min..=max by wrapping it within bounds:
x.wrap(min, max) == (x - min).rem_euclid(max - min) + min
This operation comes up a lot, and currently requires an inlined implementation each time -- often incorrectly using % instead of rem_euclid, which fails to put x into the range when x < min.
As someone with domain experience here â this is a frustratingly complicated application. Game simulation mostly deals in small, incremental changes and is highly performance sensitive, so it can often times be desirable to replace the division (modulo) with incremental summation in a loop to bring the value back into range (especially if you know it'll only ever exceed the bounds in one of the directions) since the loop will be taken usually zero times, occasionally once, and exceedingly rarely more than once.
clamp only has the (approximately[1]) one implementation. wrap having multiple valid implementation approaches (and having users that care about that choice) makes it harder to provide a universal implementation. The inability to satisfy conflicting constraints is a key reason why lerp was removed from nightly, and that's a significantly more commonly desired operation than wrap ime (biased as it likely is).
If you're using a math crate, it likely provides an extension trait for method syntax lerp. If you have that, the same library can easily provide wrap as well if it is a commonly used routine.
Different spellings do have slightly different behavior w.r.t. NaN propagation. But here the performance difference between them is small enough to rationalize using the most mathematically correct spelling, and it's not like all FPUs even agree on what the "optimal" NaN propagation behavior is. âŠī¸
Sure, it doesn't require an inlined implementation, but it often ends up as one anyways. You don't necessarily want to go and implement wrap as a re-usable function for every primitive just to replace a one-liner in the moment; and if you're contributing to someone else's project, there may not be an obvious good place to put it.
If it comes up many times within a single project then sure, you should write a function.