package gs.hex.v0 /** Type Class for decoding hexadecimal strings to some type. */ trait HexDecode[A]: /** Given some hexadecimal string representing encoded data, parse that string * to reconstruct that data. * * @param data * The encoded hexadecimal string. * @return * The decoded data, or nothing if the input is invalid. */ def fromHexString(data: String): Option[A] extension (data: String) def fromHex(): Option[A] = fromHexString(data) object HexDecode: /** Retrieve the [[HexDecode]] instance for the given type. * * @param H * The type. * @return * The [[HexDecode]] instance for the given type. */ def apply[A]( using H: HexDecode[A] ): HexDecode[A] = H given HexDecode[Array[Byte]] = new HexDecode[Array[Byte]] { /** @inheritDoc */ def fromHexString(data: String): Option[Array[Byte]] = Hex.fromHexString(data) } given HexDecode[String] = new HexDecode[String] { /** @inheritDoc */ def fromHexString(data: String): Option[String] = Hex.fromHexString(data).map(bytes => new String(bytes)) } given HexDecode[Boolean] = new HexDecode[Boolean] { /** @inheritDoc */ def fromHexString(data: String): Option[Boolean] = if data == "1" then Some(true) else if data == "0" then Some(false) else None } given HexDecode[Int] = new HexDecode[Int] { /** @inheritDoc */ def fromHexString(data: String): Option[Int] = Hex.fromHexString(data).flatMap { bytes => if bytes.length != 4 then None else Some(java.nio.ByteBuffer.wrap(bytes).getInt()) } } given HexDecode[Long] = new HexDecode[Long] { /** @inheritDoc */ def fromHexString(data: String): Option[Long] = Hex.fromHexString(data).flatMap { bytes => if bytes.length != 8 then None else Some(java.nio.ByteBuffer.wrap(bytes).getLong()) } } end HexDecode