flix

0.77.0

IpAddr.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.IpAddr {

    use Net.IpAddr
    use Net.Ipv4Addr
    use Net.Ipv6Addr

    import java.net.UnknownHostException

    ///
    /// Represents an IP address.
    ///
    pub enum IpAddr with Eq, ToString {
        case V4(Ipv4Addr)
        case V6(Ipv6Addr)
    }

    instance FromString[IpAddr] {
        pub def fromString(x: String): Option[IpAddr] = IpAddr.fromString(x)
    }

    instance Formattable[IpAddr] {
        pub def format(x: IpAddr): RichString = RichString.fromString(ToString.toString(x))
    }

    ///
    /// Converts a `List[Int8]` into `IpAddr`
    ///
    /// an Ipv4 is 4 bytes and Ipv6 is 16 bytes
    ///
    pub def fromBytes(l: List[Int8]): IpAddr = match l {
        case b1 :: b2 :: b3 :: b4 :: Nil => {
            IpAddr.V4(Ipv4Addr.Ipv4Addr(b1, b2, b3, b4))
        }
        case b1 :: b2 :: b3 :: b4 :: b5 :: b6 :: b7 :: b8 :: b9 :: b10 :: b11 :: b12 :: b13 :: b14 :: b15 :: b16 :: Nil => {
            IpAddr.V6(Ipv6Addr.Ipv6Addr(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16))
        }
        case _ => unreachable!()
    }

    ///
    /// Converts an `IpAddr` into an `Vector[Int8]`
    ///
    /// an Ipv4 is 4 bytes and Ipv6 is 16 bytes
    ///
    pub def toBytes(ip: IpAddr): Vector[Int8] =
        match ip {
            case IpAddr.V4(Ipv4Addr.Ipv4Addr(b1, b2, b3, b4)) =>
                Vector#{b1, b2, b3, b4}
            case IpAddr.V6(Ipv6Addr.Ipv6Addr(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16)) =>
                Vector#{b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16}
        }

    ///
    /// Attempts to parse the given String `s` as an `IpAddr`.
    ///
    /// Returns `Some(addr)` if the string was successfully parsed. Otherwise returns `None`.
    ///
    pub def fromString(s: String): Option[IpAddr] =
        try {
            match Ipv6Addr.fromString(s) {
                case Some(v6) => Some(IpAddr.V6(v6))
                case None => match Ipv4Addr.fromString(s) {
                    case Some(v4) => Some(IpAddr.V4(v4))
                    case None     => None
                }
            }
        } catch {
            case _: UnknownHostException => None
        }

}