// 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.
///|
fn decimal_power_count(bits : Int, signed : Bool) -> UInt {
match (bits, signed) {
(16, _) => 5U
(32, _) => 10U
(64, true) => 19U
(64, false) => 20U
_ => abort("arbitrary integer: unsupported bit width")
}
}
///|
fn canonical_integer_bits(
mask : UInt64,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
guard signed else { rs.next_uint(limit=4U).to_uint64() }
match rs.next_uint(limit=5U) {
0U => 0UL
1U => 1UL
2U => mask
3U => 2UL
_ => mask - 1UL
}
}
///|
fn apply_random_sign(
magnitude : UInt64,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
if signed && rs.next_uint(limit=2U) == 1U {
0UL - magnitude
} else {
magnitude
}
}
///|
fn boundary_delta(base : UInt64, rs : @splitmix.RandomState) -> UInt64 {
match rs.next_uint(limit=3U) {
0U => base - 1UL
1U => base
_ => base + 1UL
}
}
///|
fn binary_boundary_bits(
bits : Int,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
let exponent_count = if signed { bits - 1 } else { bits }
let exponent = rs
.next_uint(limit=exponent_count.reinterpret_as_uint())
.reinterpret_as_int()
let magnitude = boundary_delta(1UL << exponent, rs)
apply_random_sign(magnitude, signed, rs)
}
///|
fn decimal_boundary_bits(
bits : Int,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
let exponent = rs
.next_uint(limit=decimal_power_count(bits, signed))
.reinterpret_as_int()
let magnitude = boundary_delta(
(0 : Int).until(exponent).fold(init=1UL, (power, _) => power * 10UL),
rs,
)
apply_random_sign(magnitude, signed, rs)
}
///|
fn extreme_integer_bits(
bits : Int,
mask : UInt64,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
let choice = rs.next_uint(limit=4U)
if signed {
let sign_bit = 1UL << (bits - 1)
match choice {
0U => sign_bit
1U => sign_bit + 1UL
2U => sign_bit - 2UL
_ => sign_bit - 1UL
}
} else {
match choice {
0U => mask
1U => mask - 1UL
2U => mask - 2UL
_ => 1UL << (bits - 1)
}
}
}
///|
/// 40% full-width, 20% canonical, 20% binary boundaries,
/// 10% decimal boundaries, and 10% type extrema.
fn gen_integer_bits(
bits : Int,
signed : Bool,
rs : @splitmix.RandomState,
) -> UInt64 {
let mask = if bits == 64 {
0xffff_ffff_ffff_ffffUL
} else {
(1UL << bits) - 1UL
}
let value = match rs.next_uint(limit=100U) {
0..<40 => rs.next_uint64()
40..<60 => canonical_integer_bits(mask, signed, rs)
60..<80 => binary_boundary_bits(bits, signed, rs)
80..<90 => decimal_boundary_bits(bits, signed, rs)
_ => extreme_integer_bits(bits, mask, signed, rs)
}
value & mask
}
///|
pub impl Arbitrary for Int16 with fn arbitrary(_, rs) {
Int16::reinterpret_from_uint16(gen_integer_bits(16, true, rs).to_uint16())
}
///|
pub impl Arbitrary for UInt16 with fn arbitrary(_, rs) {
gen_integer_bits(16, false, rs).to_uint16()
}
///|
pub impl Arbitrary for Int with fn arbitrary(_, rs) {
gen_integer_bits(32, true, rs).to_uint().reinterpret_as_int()
}
///|
pub impl Arbitrary for UInt with fn arbitrary(_, rs) {
gen_integer_bits(32, false, rs).to_uint()
}
///|
pub impl Arbitrary for Int64 with fn arbitrary(_, rs) {
gen_integer_bits(64, true, rs).reinterpret_as_int64()
}
///|
pub impl Arbitrary for UInt64 with fn arbitrary(_, rs) {
gen_integer_bits(64, false, rs)
}