diff --git a/src/ranged_int/builtin/int128.gleam b/src/ranged_int/builtin/int128.gleam index 44d1943..e265c13 100644 --- a/src/ranged_int/builtin/int128.gleam +++ b/src/ranged_int/builtin/int128.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} pub opaque type Int128 { Int128(data: BigInt) @@ -19,24 +19,44 @@ pub fn to_bigint(uint: Int128) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Int128, b: Int128) { interface.compare(a, b, iface) } -pub fn math_op(a: Int128, b: Int128, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Int128, b: Int128, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Int128, b: Int128, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Int128, b: Int128) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Int128)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Int128)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/int16.gleam b/src/ranged_int/builtin/int16.gleam index 43a1155..a8130dd 100644 --- a/src/ranged_int/builtin/int16.gleam +++ b/src/ranged_int/builtin/int16.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const max_limit = 32_767 @@ -23,24 +23,44 @@ pub fn to_bigint(uint: Int16) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Int16, b: Int16) { interface.compare(a, b, iface) } -pub fn math_op(a: Int16, b: Int16, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Int16, b: Int16, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Int16, b: Int16, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Int16, b: Int16) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Int16)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Int16)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/int32.gleam b/src/ranged_int/builtin/int32.gleam index 868b9e0..4abe491 100644 --- a/src/ranged_int/builtin/int32.gleam +++ b/src/ranged_int/builtin/int32.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const max_limit = 2_147_483_647 @@ -23,24 +23,44 @@ pub fn to_bigint(uint: Int32) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Int32, b: Int32) { interface.compare(a, b, iface) } -pub fn math_op(a: Int32, b: Int32, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Int32, b: Int32, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Int32, b: Int32, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Int32, b: Int32) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Int32)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Int32)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/int64.gleam b/src/ranged_int/builtin/int64.gleam index b2cad09..e74828d 100644 --- a/src/ranged_int/builtin/int64.gleam +++ b/src/ranged_int/builtin/int64.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} pub opaque type Int64 { Int64(data: BigInt) @@ -19,24 +19,44 @@ pub fn to_bigint(uint: Int64) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Int64, b: Int64) { interface.compare(a, b, iface) } -pub fn math_op(a: Int64, b: Int64, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Int64, b: Int64, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Int64, b: Int64, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Int64, b: Int64) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Int64)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Int64)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/int8.gleam b/src/ranged_int/builtin/int8.gleam index 24f49b6..a39c798 100644 --- a/src/ranged_int/builtin/int8.gleam +++ b/src/ranged_int/builtin/int8.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const max_limit = 127 @@ -23,24 +23,44 @@ pub fn to_bigint(uint: Int8) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Int8, b: Int8) { interface.compare(a, b, iface) } -pub fn math_op(a: Int8, b: Int8, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Int8, b: Int8, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Int8, b: Int8, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Int8, b: Int8) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Int8)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Int8)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/uint.gleam b/src/ranged_int/builtin/uint.gleam index 2f2c100..4f33d3c 100644 --- a/src/ranged_int/builtin/uint.gleam +++ b/src/ranged_int/builtin/uint.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const min_limit = 0 @@ -25,12 +25,36 @@ pub fn compare(a: Uint, b: Uint) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint, b: Uint, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_eject(a: Uint, b: Uint, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn subtract(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.subtract) +} + +pub fn multiply(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint, b: Uint) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn eject(op: interface.OpResult(Uint)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/uint128.gleam b/src/ranged_int/builtin/uint128.gleam index d5e04be..d93dcc8 100644 --- a/src/ranged_int/builtin/uint128.gleam +++ b/src/ranged_int/builtin/uint128.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} pub opaque type Uint128 { Uint128(data: BigInt) @@ -19,24 +19,44 @@ pub fn to_bigint(uint: Uint128) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Uint128, b: Uint128) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint128, b: Uint128, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Uint128, b: Uint128, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Uint128, b: Uint128, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint128, b: Uint128) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Uint128)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Uint128)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/uint16.gleam b/src/ranged_int/builtin/uint16.gleam index c8d5e49..94acaa6 100644 --- a/src/ranged_int/builtin/uint16.gleam +++ b/src/ranged_int/builtin/uint16.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const max_limit = 65_535 @@ -23,30 +23,50 @@ pub fn to_bigint(uint: Uint16) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Uint16, b: Uint16) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint16, b: Uint16, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Uint16, b: Uint16, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Uint16, b: Uint16, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint16, b: Uint16) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Uint16)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Uint16)) { + interface.eject(op, iface) } fn limits() { interface.overflowable_limits( - bigi.from_int(max_limit), bigi.from_int(min_limit), + bigi.from_int(max_limit), ) } diff --git a/src/ranged_int/builtin/uint32.gleam b/src/ranged_int/builtin/uint32.gleam index e3df703..e62058a 100644 --- a/src/ranged_int/builtin/uint32.gleam +++ b/src/ranged_int/builtin/uint32.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} pub const max_limit = 4_294_967_295 @@ -23,30 +23,50 @@ pub fn to_bigint(uint: Uint32) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Uint32, b: Uint32) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint32, b: Uint32, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Uint32, b: Uint32, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Uint32, b: Uint32, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint32, b: Uint32) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Uint32)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Uint32)) { + interface.eject(op, iface) } fn limits() { interface.overflowable_limits( - bigi.from_int(max_limit), bigi.from_int(min_limit), + bigi.from_int(max_limit), ) } diff --git a/src/ranged_int/builtin/uint64.gleam b/src/ranged_int/builtin/uint64.gleam index f0de557..b093afe 100644 --- a/src/ranged_int/builtin/uint64.gleam +++ b/src/ranged_int/builtin/uint64.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} pub opaque type Uint64 { Uint64(data: BigInt) @@ -19,24 +19,44 @@ pub fn to_bigint(uint: Uint64) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Uint64, b: Uint64) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint64, b: Uint64, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Uint64, b: Uint64, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Uint64, b: Uint64, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn modulo(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint64, b: Uint64) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Uint64)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Uint64)) { + interface.eject(op, iface) } fn limits() { diff --git a/src/ranged_int/builtin/uint8.gleam b/src/ranged_int/builtin/uint8.gleam index b21b0ef..58d74e3 100644 --- a/src/ranged_int/builtin/uint8.gleam +++ b/src/ranged_int/builtin/uint8.gleam @@ -1,5 +1,5 @@ import bigi.{type BigInt} -import ranged_int/interface.{type Interface, type MathOp, Interface} +import ranged_int/interface.{type Interface, Interface} const max_limit = 255 @@ -23,30 +23,54 @@ pub fn to_bigint(uint: Uint8) { uint.data } -pub fn from_bigint_overflow(value: BigInt) { - interface.from_bigint_overflow(value, iface) -} - pub fn compare(a: Uint8, b: Uint8) { interface.compare(a, b, iface) } -pub fn math_op(a: Uint8, b: Uint8, op: MathOp) { - interface.math_op(a, b, iface, op) +pub fn add(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.add) } -pub fn math_op_overflow(a: Uint8, b: Uint8, op: MathOp) { - interface.math_op_overflow(a, b, iface, op) +pub fn subtract(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.subtract) } -pub fn math_op_eject(a: Uint8, b: Uint8, op: MathOp) { - interface.math_op_eject(a, b, iface, op) +pub fn multiply(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.multiply) +} + +pub fn divide(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.divide) +} + +pub fn divide_no_zero(a: Uint8, b: Uint8) { + interface.fallible_op(a, b, iface, bigi.divide_no_zero) +} + +pub fn modulo(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.modulo) +} + +pub fn remainder(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.remainder) +} + +pub fn power(a: Uint8, b: Uint8) { + interface.math_op(a, b, iface, bigi.power) +} + +pub fn overflow(op: interface.OpResult(Uint8)) { + interface.overflow(op, iface) +} + +pub fn eject(op: interface.OpResult(Uint8)) { + interface.eject(op, iface) } fn limits() { interface.overflowable_limits( - bigi.from_int(max_limit), bigi.from_int(min_limit), + bigi.from_int(max_limit), ) } diff --git a/src/ranged_int/interface.gleam b/src/ranged_int/interface.gleam index f1dba37..dde23d7 100644 --- a/src/ranged_int/interface.gleam +++ b/src/ranged_int/interface.gleam @@ -1,4 +1,5 @@ import gleam/order +import gleam/result import bigi.{type BigInt} import ranged_int/limit.{type Limit, NoOverflow, Overflow, Underflow} import ranged_int/utils @@ -22,8 +23,8 @@ type OverflowableLimits { OverflowableLimits(min: BigInt, max: BigInt) } -pub type MathOp = - fn(BigInt, BigInt) -> BigInt +pub type OpResult(a) = + Result(a, utils.Overflow) pub type Interface(a, overflow_mode) { Interface( @@ -48,7 +49,7 @@ pub fn min_limit(min: BigInt) -> Limits(NonOverflowable) { pub fn from_bigint( value: BigInt, interface: Interface(a, overflow_mode), -) -> Result(a, utils.Overflow) { +) -> OpResult(a) { let limits = interface.limits() case limit.check_limits(value, min: limits.min, max: limits.max) { NoOverflow -> Ok(interface.from_bigint_unsafe(value)) @@ -57,13 +58,6 @@ pub fn from_bigint( } } -pub fn from_bigint_overflow( - value: BigInt, - interface: Interface(a, Overflowable), -) -> a { - handle_overflow(value, interface) -} - pub fn compare( int1: a, int2: a, @@ -76,8 +70,8 @@ pub fn math_op( int1: a, int2: a, interface: Interface(a, overflow_mode), - op: MathOp, -) -> Result(a, utils.Overflow) { + op: fn(BigInt, BigInt) -> BigInt, +) -> OpResult(a) { let limits = interface.limits() let bigint1 = interface.to_bigint(int1) let bigint2 = interface.to_bigint(int2) @@ -89,48 +83,51 @@ pub fn math_op( } } -pub fn math_op_overflow( - int1: a, - int2: a, - interface: Interface(a, Overflowable), - op: MathOp, -) -> a { - let bigint1 = interface.to_bigint(int1) - let bigint2 = interface.to_bigint(int2) - let result = op(bigint1, bigint2) - handle_overflow(result, interface) -} - -pub fn math_op_eject( +pub fn fallible_op( int1: a, int2: a, interface: Interface(a, overflow_mode), - op: MathOp, -) -> BigInt { + op: fn(BigInt, BigInt) -> Result(BigInt, op_err), +) -> Result(OpResult(a), op_err) { + let limits = interface.limits() let bigint1 = interface.to_bigint(int1) let bigint2 = interface.to_bigint(int2) - op(bigint1, bigint2) + use result <- result.try(op(bigint1, bigint2)) + Ok(case limit.check_limits(result, min: limits.min, max: limits.max) { + NoOverflow -> Ok(interface.from_bigint_unsafe(result)) + Overflow(amount) -> Error(utils.DidOverflow(amount)) + Underflow(amount) -> Error(utils.DidUnderflow(amount)) + }) } -pub fn handle_overflow(value: BigInt, interface: Interface(a, Overflowable)) { - let limits = interface.limits() - let result = case - limit.check_limits(value, min: limits.min, max: limits.max) - { - NoOverflow -> value - Overflow(amount) -> { - let OverflowableLimits(min, max) = destructure_limits(limits) - utils.overflow(utils.DidOverflow(amount), min: min, max: max) - } - Underflow(amount) -> { - let OverflowableLimits(min, max) = destructure_limits(limits) - utils.overflow(utils.DidUnderflow(amount), min: min, max: max) +pub fn overflow(value: OpResult(a), interface: Interface(a, Overflowable)) { + case value { + Ok(new_value) -> new_value + Error(overflow) -> { + let OverflowableLimits(min, max) = destructure_limits(interface.limits()) + utils.overflow(overflow, min: min, max: max) + |> interface.from_bigint_unsafe() + } + } +} + +pub fn eject(value: OpResult(a), interface: Interface(a, overflow_mode)) { + case value { + Ok(new_value) -> interface.to_bigint(new_value) + Error(overflow) -> { + case overflow, interface.limits() { + utils.DidOverflow(amount), Limits(max: limit.Bounded(max), ..) -> + bigi.add(max, amount) + utils.DidUnderflow(amount), Limits(min: limit.Bounded(min), ..) -> + bigi.subtract(min, amount) + _, _ -> panic as "Overflowed but there was no corresponding limit (o_O)" + } } } - interface.from_bigint_unsafe(result) } fn destructure_limits(limits: Limits(Overflowable)) { + // We can trust that overflowable limits are always bounded on both sides let assert limit.Bounded(min) = limits.min let assert limit.Bounded(max) = limits.max OverflowableLimits(min: min, max: max) diff --git a/test/builtin/uint16_test.gleam b/test/builtin/uint16_test.gleam new file mode 100644 index 0000000..23a78b7 --- /dev/null +++ b/test/builtin/uint16_test.gleam @@ -0,0 +1,10 @@ +import bigi +import gleeunit/should +import ranged_int/builtin/uint16 + +pub fn add_test() { + let assert Ok(a) = uint16.from_bigint(bigi.zero()) + let assert Ok(b) = uint16.from_bigint(bigi.from_int(12)) + let c = uint16.eject(uint16.add(a, b)) + should.equal(c, bigi.from_int(12)) +} diff --git a/test/builtin/uint8_test.gleam b/test/builtin/uint8_test.gleam index 8f5d03b..ab7b67a 100644 --- a/test/builtin/uint8_test.gleam +++ b/test/builtin/uint8_test.gleam @@ -3,8 +3,15 @@ import gleeunit/should import ranged_int/builtin/uint8 pub fn add_test() { - let a = uint8.from_bigint_overflow(bigi.zero()) - let b = uint8.from_bigint_overflow(bigi.from_int(12)) - let c = uint8.math_op_overflow(a, b, bigi.add) - should.equal(c, uint8.from_bigint_overflow(bigi.from_int(12))) + let assert Ok(a) = uint8.from_bigint(bigi.zero()) + let assert Ok(b) = uint8.from_bigint(bigi.from_int(12)) + let c = uint8.eject(uint8.add(a, b)) + should.equal(c, bigi.from_int(12)) +} + +pub fn divide_test() { + let assert Ok(a) = uint8.from_bigint(bigi.from_int(120)) + let assert Ok(b) = uint8.from_bigint(bigi.from_int(12)) + let assert Ok(c) = uint8.divide_no_zero(a, b) + should.equal(uint8.eject(c), bigi.from_int(10)) }