Net / Ipv4Addr.flix
Ipv4Addr.flix
/*
* Copyright 2025 Cade Lueker
*
* Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE.md file.
*/
pub mod Net.Ipv4Addr {
import java.net.InetAddress
import java.net.UnknownHostException
import java.lang.NumberFormatException
use Net.Ipv4Addr
use Net.Ipv6Addr
///
/// Represents a V4 Ip Address.
///
pub enum Ipv4Addr with Eq {
// 32 bits
case Ipv4Addr(Int8, Int8, Int8, Int8)
}
instance FromString[Ipv4Addr] {
pub def fromString(x: String): Option[Ipv4Addr] = Ipv4Addr.fromString(x)
}
instance ToString[Ipv4Addr] {
pub def toString(x: Ipv4Addr): String = Ipv4Addr.toString(x)
}
instance Formattable[Ipv4Addr] {
pub def format(x: Ipv4Addr): RichString = RichString.fromString(ToString.toString(x))
}
///
/// Returns the Ipv4 localhost address.
///
pub def localhost(): Ipv4Addr =
Ipv4Addr.Ipv4Addr(127i8, 0i8, 0i8, 1i8)
///
/// Convert `x` from Ipv4 to Ipv6.
///
pub def toIpv6(x: Ipv4Addr): Ipv6Addr =
let Ipv4Addr.Ipv4Addr(b1, b2, b3, b4) = x;
Ipv6Addr.Ipv6Addr(0i8, 0i8, 0i8, 0i8, 0i8, 0i8, 0i8, 0i8, 0i8, 0i8, -1i8, -1i8, b1, b2, b3, b4)
///
/// Attempts to parse the given String `s` as an `Ipv4Addr`.
///
/// Returns `Some(addr)` if the string was successfully parsed. Otherwise returns `None`.
///
pub def fromString(s: String): Option[Ipv4Addr] =
let bytes = s
|> String.split({regex = "[.]"})
|> List.traverse(parseInt8NoLeading0);
match bytes {
case Some(b1 :: b2 :: b3 :: b4 :: Nil) => {
Some(Ipv4Addr.Ipv4Addr(b1, b2, b3, b4))
}
case _ => None
}
///
/// Returns a String representation of the given Ipv4Addr `x`.
///
pub def toString(x: Ipv4Addr): String =
let Ipv4Addr.Ipv4Addr(b1, b2, b3, b4) = x;
"${toUnsigned8(b1)}.${toUnsigned8(b2)}.${toUnsigned8(b3)}.${toUnsigned8(b4)}"
///
/// Convert `x` from i8 to u8.
///
def toUnsigned8(x: Int8): Int32 = Int32.bitwiseAnd(Int8.toInt32(x), 0xFF)
///
/// Attempt to convert `x` from Int32 to Int8.
///
def toSigned8(x: Int32): Option[Int8] =
forM (
bu8 <- Some(x);
if 0 <= x and x < 256;
bi8 <- Int32.tryToInt8(
Int32.bitwiseXor(
Int32.bitwiseAnd(bu8, 0xFF),
0x80
)
- 0x80
)
) yield bi8
///
/// Attempt to parse `b` from String to Int8.
///
def parseInt8NoLeading0(b: String): Option[Int8] =
forM (
s <- Some(b);
if not (String.length(b) > 1 and String.startsWith({prefix = "0"}, b));
u8 <- Int32.fromString(s);
i8 <- toSigned8(u8)
) yield i8
}