// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Shared body for `Int::until`, `Int64::until`, and `Double::until`.
/// `Default::default()` is taken to be the additive identity (zero) of
/// `T`, which is true for the built-in numeric types this is used with.
fn[T : Add + Compare + Default] until_impl(
  start : T,
  end : T,
  step : T,
  inclusive : Bool,
) -> Iter[T] {
  let zero = Default::default()
  if step == zero {
    return Iter::empty()
  }
  let mut i = start
  let mut done = false
  Iter::new(() => {
    guard !done else { None }
    guard (step > zero && i < end) ||
      (step < zero && i > end) ||
      (inclusive && i == end) else {
      None
    }
    let value = i
    let next = i + step
    if (step > zero && next >= i) || (step < zero && next <= i) {
      i = next
    } else {
      done = true
    }
    Some(value)
  })
}