///|
/// Numeric zero, used by `positive` and related checks.
pub(open) trait Zero {
fn zero() -> Self
}
///|
pub impl Zero for Int with fn zero() {
0
}
///|
pub impl Zero for Int64 with fn zero() {
0L
}
///|
pub impl Zero for Double with fn zero() {
0.0
}
///|
/// Numbers that support remainder, used by `multiple_of`.
pub(open) trait Remainder {
fn rem(Self, Self) -> Self
}
///|
pub impl Remainder for Int with fn rem(self, n) {
self % n
}
///|
pub impl Remainder for Int64 with fn rem(self, n) {
self % n
}
///|
pub impl Remainder for Double with fn rem(self, n) {
self % n
}
///|
/// Require `self >= bound`.
pub fn[T : Compare + Show] Typed::min(
self : Typed[T],
bound : T,
) -> Typed[T] raise Invalid {
if self.val >= bound {
self
} else {
err(self.path, "must be at least \{bound}")
}
}
///|
/// Require `self <= bound`.
pub fn[T : Compare + Show] Typed::max(
self : Typed[T],
bound : T,
) -> Typed[T] raise Invalid {
if self.val <= bound {
self
} else {
err(self.path, "must be at most \{bound}")
}
}
///|
/// Require `min <= self <= max`.
pub fn[T : Compare + Show] Typed::range(
self : Typed[T],
min : T,
max : T,
) -> Typed[T] raise Invalid {
if self.val >= min && self.val <= max {
self
} else {
err(self.path, "must be between \{min} and \{max}")
}
}
///|
/// Require `self > bound`.
pub fn[T : Compare + Show] Typed::gt(
self : Typed[T],
bound : T,
) -> Typed[T] raise Invalid {
if self.val > bound {
self
} else {
err(self.path, "must be greater than \{bound}")
}
}
///|
/// Require `self < bound`.
pub fn[T : Compare + Show] Typed::lt(
self : Typed[T],
bound : T,
) -> Typed[T] raise Invalid {
if self.val < bound {
self
} else {
err(self.path, "must be less than \{bound}")
}
}
///|
/// Require `self > 0`.
pub fn[T : Compare + Zero] Typed::positive(
self : Typed[T],
) -> Typed[T] raise Invalid {
expect_positive(self.path, self.val > Zero::zero())
self
}
///|
/// Require `self < 0`.
pub fn[T : Compare + Zero] Typed::negative(
self : Typed[T],
) -> Typed[T] raise Invalid {
expect_negative(self.path, self.val < Zero::zero())
self
}
///|
/// Require `self >= 0`.
pub fn[T : Compare + Zero] Typed::nonnegative(
self : Typed[T],
) -> Typed[T] raise Invalid {
expect_nonnegative(self.path, self.val >= Zero::zero())
self
}
///|
/// Require `self <= 0`.
pub fn[T : Compare + Zero] Typed::nonpositive(
self : Typed[T],
) -> Typed[T] raise Invalid {
expect_nonpositive(self.path, self.val <= Zero::zero())
self
}
///|
/// Require `self` to be a multiple of `n`.
pub fn[T : Remainder + Zero + Eq + Show] Typed::multiple_of(
self : Typed[T],
n : T,
) -> Typed[T] raise Invalid {
let zero = Zero::zero()
expect_multiple_of(
self.path,
n != zero && Remainder::rem(self.val, n) == zero,
n,
)
self
}
///|
fn expect_positive(path : Path, ok : Bool) -> Unit raise Invalid {
if !ok {
err(path, "must be positive")
}
}
///|
fn expect_negative(path : Path, ok : Bool) -> Unit raise Invalid {
if !ok {
err(path, "must be negative")
}
}
///|
fn expect_nonnegative(path : Path, ok : Bool) -> Unit raise Invalid {
if !ok {
err(path, "must be non-negative")
}
}
///|
fn expect_nonpositive(path : Path, ok : Bool) -> Unit raise Invalid {
if !ok {
err(path, "must be non-positive")
}
}
///|
fn[T : Show] expect_multiple_of(
path : Path,
ok : Bool,
n : T,
) -> Unit raise Invalid {
if !ok {
err(path, "must be a multiple of \{n}")
}
}