mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-20 10:13:26 +01:00
implement isInBound for numbers
This commit is contained in:
parent
b3cdb6015c
commit
df4507edef
@ -148,6 +148,7 @@ sealed abstract class UInt64 extends UnsignedNumber[UInt64] {
|
||||
* Converts a [[BigInt]] to a 8 byte hex representation.
|
||||
* [[BigInt]] will only allocate 1 byte for numbers like 1 which require 1 byte, giving us the hex representation 01
|
||||
* this function pads the hex chars to be 0000000000000001
|
||||
*
|
||||
* @param bigInt The number to encode
|
||||
* @return The hex encoded number
|
||||
*/
|
||||
@ -181,33 +182,50 @@ sealed abstract class Int64 extends SignedNumber[Int64] {
|
||||
override def hex: String = BitcoinSUtil.encodeHex(toLong)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents various numbers that should be implemented
|
||||
* inside of any companion object for a number
|
||||
*/
|
||||
trait BaseNumbers[T] {
|
||||
def zero: T
|
||||
def one: T
|
||||
trait Bounded[T] {
|
||||
def min: T
|
||||
def max: T
|
||||
}
|
||||
|
||||
object UInt5 extends Factory[UInt5] with BaseNumbers[UInt5] {
|
||||
trait BaseNumbers[T] {
|
||||
def zero: T
|
||||
def one: T
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be implemented inside of any companion
|
||||
* object for a number
|
||||
*/
|
||||
trait NumberObject[T <: Number[T]] extends BaseNumbers[T] {
|
||||
type A = BigInt
|
||||
|
||||
def isInBound(num: A): Boolean
|
||||
}
|
||||
|
||||
object UInt5
|
||||
extends Factory[UInt5]
|
||||
with NumberObject[UInt5]
|
||||
with Bounded[UInt5] {
|
||||
private case class UInt5Impl(underlying: BigInt) extends UInt5 {
|
||||
require(underlying.toInt >= 0, s"Cannot create UInt5 from $underlying")
|
||||
require(underlying <= 31, s"Cannot create UInt5 from $underlying")
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
|
||||
lazy val zero = UInt5(0.toByte)
|
||||
lazy val one = UInt5(1.toByte)
|
||||
|
||||
lazy val min: UInt5 = zero
|
||||
lazy val max = UInt5(31.toByte)
|
||||
private lazy val minUnderlying: A = 0
|
||||
private lazy val maxUnderlying: A = 31
|
||||
|
||||
lazy val min = UInt5(minUnderlying)
|
||||
lazy val max = UInt5(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
def apply(byte: Byte): UInt5 = fromByte(byte)
|
||||
|
||||
def apply(bigInt: BigInt): UInt5 = {
|
||||
|
||||
require(
|
||||
bigInt.toByteArray.length == 1,
|
||||
s"To create a uint5 from a BigInt it must be less than 32. Got: ${bigInt.toString}")
|
||||
@ -235,16 +253,25 @@ object UInt5 extends Factory[UInt5] with BaseNumbers[UInt5] {
|
||||
}
|
||||
}
|
||||
|
||||
object UInt8 extends Factory[UInt8] with BaseNumbers[UInt8] {
|
||||
object UInt8
|
||||
extends Factory[UInt8]
|
||||
with NumberObject[UInt8]
|
||||
with Bounded[UInt8] {
|
||||
private case class UInt8Impl(underlying: BigInt) extends UInt8 {
|
||||
require(isValid(underlying),
|
||||
"Invalid range for a UInt8, got: " + underlying)
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
lazy val zero = UInt8(0.toShort)
|
||||
lazy val one = UInt8(1.toShort)
|
||||
|
||||
lazy val min: UInt8 = zero
|
||||
lazy val max = UInt8(255.toShort)
|
||||
private lazy val minUnderlying: A = 0
|
||||
private lazy val maxUnderlying: A = 255
|
||||
|
||||
lazy val min = UInt8(minUnderlying)
|
||||
lazy val max = UInt8(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
def apply(short: Short): UInt8 = UInt8(BigInt(short))
|
||||
|
||||
@ -252,14 +279,14 @@ object UInt8 extends Factory[UInt8] with BaseNumbers[UInt8] {
|
||||
|
||||
def apply(bigint: BigInt): UInt8 = UInt8Impl(bigint)
|
||||
|
||||
def isValid(bigInt: BigInt): Boolean = bigInt >= 0 && bigInt < 256
|
||||
@deprecated("Use isInBound(...) instead.", "") def isValid(
|
||||
bigInt: BigInt): Boolean = bigInt >= 0 && bigInt < 256
|
||||
|
||||
override def fromBytes(bytes: ByteVector): UInt8 = {
|
||||
require(
|
||||
bytes.size == 1,
|
||||
"Can only create a uint8 from a byte array of size one, got: " + bytes)
|
||||
val res = NumberUtil.toUnsignedInt(bytes)
|
||||
checkBounds(res)
|
||||
UInt8(NumberUtil.toUnsignedInt(bytes))
|
||||
}
|
||||
|
||||
def toUInt8(byte: Byte): UInt8 = {
|
||||
@ -276,93 +303,105 @@ object UInt8 extends Factory[UInt8] with BaseNumbers[UInt8] {
|
||||
bytes.toArray.map(toUInt8).toVector
|
||||
}
|
||||
|
||||
def checkBounds(res: BigInt): UInt8 = {
|
||||
@deprecated("Use require(isInBound(...)) instead.", "") def checkBounds(
|
||||
res: BigInt): UInt8 = {
|
||||
if (res > max.underlying || res < min.underlying) {
|
||||
throw new IllegalArgumentException(
|
||||
"Out of boudns for a UInt8, got: " + res)
|
||||
"Out of bounds for a UInt8, got: " + res)
|
||||
} else UInt8(res.toShort)
|
||||
}
|
||||
}
|
||||
|
||||
object UInt32 extends Factory[UInt32] with BaseNumbers[UInt32] {
|
||||
object UInt32
|
||||
extends Factory[UInt32]
|
||||
with NumberObject[UInt32]
|
||||
with Bounded[UInt32] {
|
||||
private case class UInt32Impl(underlying: BigInt) extends UInt32 {
|
||||
require(
|
||||
underlying >= 0,
|
||||
"We cannot have a negative number in an unsigned number, got: " + underlying)
|
||||
require(
|
||||
underlying <= 4294967295L,
|
||||
"We cannot have a number larger than 2^32 -1 in UInt32, got: " + underlying)
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
|
||||
lazy val zero = UInt32(0)
|
||||
lazy val one = UInt32(1)
|
||||
|
||||
lazy val min: UInt32 = zero
|
||||
lazy val max = UInt32(4294967295L)
|
||||
private lazy val minUnderlying: A = 0
|
||||
private lazy val maxUnderlying: A = 4294967295L
|
||||
|
||||
lazy val min = UInt32(minUnderlying)
|
||||
lazy val max = UInt32(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
override def fromBytes(bytes: ByteVector): UInt32 = {
|
||||
require(
|
||||
bytes.size <= 4,
|
||||
"UInt32 byte array was too large, got: " + BitcoinSUtil.encodeHex(bytes))
|
||||
val res = NumberUtil.toUnsignedInt(bytes)
|
||||
checkBounds(res)
|
||||
UInt32(NumberUtil.toUnsignedInt(bytes))
|
||||
}
|
||||
|
||||
def apply(long: Long): UInt32 = UInt32(BigInt(long))
|
||||
|
||||
def apply(bigInt: BigInt): UInt32 = UInt32Impl(bigInt)
|
||||
|
||||
def checkBounds(res: BigInt): UInt32 = {
|
||||
@deprecated("Use require(isInBound(...)) instead.", "") def checkBounds(
|
||||
res: BigInt): UInt32 = {
|
||||
if (res > max.underlying || res < min.underlying) {
|
||||
throw new IllegalArgumentException(
|
||||
"Out of boudns for a UInt8, got: " + res)
|
||||
"Out of bounds for a UInt8, got: " + res)
|
||||
} else UInt32(res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object UInt64 extends Factory[UInt64] with BaseNumbers[UInt64] {
|
||||
object UInt64
|
||||
extends Factory[UInt64]
|
||||
with NumberObject[UInt64]
|
||||
with Bounded[UInt64] {
|
||||
private case class UInt64Impl(underlying: BigInt) extends UInt64 {
|
||||
require(
|
||||
underlying >= 0,
|
||||
"We cannot have a negative number in an unsigned number: " + underlying)
|
||||
require(
|
||||
underlying <= BigInt("18446744073709551615"),
|
||||
"We cannot have a number larger than 2^64 -1 in UInt64, got: " + underlying)
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
|
||||
lazy val zero = UInt64(BigInt(0))
|
||||
lazy val one = UInt64(BigInt(1))
|
||||
|
||||
lazy val min: UInt64 = zero
|
||||
lazy val max = UInt64(BigInt("18446744073709551615"))
|
||||
private lazy val minUnderlying: A = 0
|
||||
private lazy val maxUnderlying: A = BigInt("18446744073709551615")
|
||||
|
||||
lazy val min = UInt64(minUnderlying)
|
||||
lazy val max = UInt64(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
override def fromBytes(bytes: ByteVector): UInt64 = {
|
||||
require(bytes.size <= 8)
|
||||
val res: BigInt = NumberUtil.toUnsignedInt(bytes)
|
||||
if (res > max.underlying || res < min.underlying) {
|
||||
throw new IllegalArgumentException(
|
||||
"Out of bounds for a UInt64, got: " + res)
|
||||
} else UInt64(res)
|
||||
UInt64(NumberUtil.toUnsignedInt(bytes))
|
||||
}
|
||||
|
||||
def apply(num: BigInt): UInt64 = UInt64Impl(num)
|
||||
|
||||
}
|
||||
|
||||
object Int32 extends Factory[Int32] with BaseNumbers[Int32] {
|
||||
object Int32
|
||||
extends Factory[Int32]
|
||||
with NumberObject[Int32]
|
||||
with Bounded[Int32] {
|
||||
private case class Int32Impl(underlying: BigInt) extends Int32 {
|
||||
require(underlying >= -2147483648,
|
||||
"Number was too small for a int32, got: " + underlying)
|
||||
require(underlying <= 2147483647,
|
||||
"Number was too large for a int32, got: " + underlying)
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
|
||||
lazy val zero = Int32(0)
|
||||
lazy val one = Int32(1)
|
||||
|
||||
lazy val min = Int32(-2147483648)
|
||||
lazy val max = Int32(2147483647)
|
||||
private lazy val minUnderlying: A = -2147483648
|
||||
private lazy val maxUnderlying: A = 2147483647
|
||||
|
||||
lazy val min = Int32(minUnderlying)
|
||||
lazy val max = Int32(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Int32 = {
|
||||
require(bytes.size <= 4, "We cannot have an Int32 be larger than 4 bytes")
|
||||
@ -374,19 +413,26 @@ object Int32 extends Factory[Int32] with BaseNumbers[Int32] {
|
||||
def apply(bigInt: BigInt): Int32 = Int32Impl(bigInt)
|
||||
}
|
||||
|
||||
object Int64 extends Factory[Int64] with BaseNumbers[Int64] {
|
||||
object Int64
|
||||
extends Factory[Int64]
|
||||
with NumberObject[Int64]
|
||||
with Bounded[Int64] {
|
||||
private case class Int64Impl(underlying: BigInt) extends Int64 {
|
||||
require(underlying >= -9223372036854775808L,
|
||||
"Number was too small for a int64, got: " + underlying)
|
||||
require(underlying <= 9223372036854775807L,
|
||||
"Number was too big for a int64, got: " + underlying)
|
||||
require(isInBound(underlying),
|
||||
s"Cannot create ${super.getClass.getSimpleName} from $underlying")
|
||||
}
|
||||
|
||||
lazy val zero = Int64(0)
|
||||
lazy val one = Int64(1)
|
||||
|
||||
lazy val min = Int64(-9223372036854775808L)
|
||||
lazy val max = Int64(9223372036854775807L)
|
||||
private lazy val minUnderlying: A = -9223372036854775808L
|
||||
private lazy val maxUnderlying: A = 9223372036854775807L
|
||||
|
||||
lazy val min = Int64(minUnderlying)
|
||||
lazy val max = Int64(maxUnderlying)
|
||||
|
||||
override def isInBound(num: A): Boolean =
|
||||
num <= maxUnderlying && num >= minUnderlying
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Int64 = {
|
||||
require(bytes.size <= 8, "We cannot have an Int64 be larger than 8 bytes")
|
||||
|
Loading…
Reference in New Issue
Block a user