/* * 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. */////// Type of socket addresses, and its functions.///pubmod Net.SocketAddr {use Net.IpAddruse Net.Ipv4Addruse Net.Ipv6Addruse Net.SocketAddruse Net.SocketAddrV4use Net.SocketAddrV6////// Type of socket addresses.////// A socket address is either an IPv4 or an IPv6 socket address.///pubenumSocketAddrwithEq {case V4(SocketAddrV4)case V6(SocketAddrV6) }instanceFromString[SocketAddr] {pubdeffromString(x: String): Option[SocketAddr] = SocketAddr.fromString(x) }instanceToString[SocketAddr] {pubdeftoString(x: SocketAddr): String = matchx {case SocketAddr.V4(SocketAddrV4.SocketAddrV4(ip, port)) => "${ip}:${port}"case SocketAddr.V6(SocketAddrV6.SocketAddrV6(ip, port)) => "[${ip}]:${port}" } }instanceFormattable[SocketAddr] {pubdefformat(x: SocketAddr): RichString = RichString.fromString(ToString.toString(x)) }////// Attempts to parse the given String `x` as a `SocketAddr`.////// Returns `Some(socket)` if the string was successfully parsed. Otherwise returns `None`.///pubdeffromString(x: String): Option[SocketAddr] =matchString.contains(substr = "]", x) {casetrue => parseSocketV6(x)casefalse => parseSocketV4(x) }////// Return the port of the SocketAddr `s`.///pubdefport(s: SocketAddr): Int32 = matchs {case SocketAddr.V4(SocketAddrV4.SocketAddrV4(_, p)) => pcase SocketAddr.V6(SocketAddrV6.SocketAddrV6(_, p)) => p }////// Return the IpAddr of the SocketAddr `s`.///pubdefip(s: SocketAddr): IpAddr = matchs {case SocketAddr.V4(SocketAddrV4.SocketAddrV4(ip, _)) => IpAddr.V4(ip)case SocketAddr.V6(SocketAddrV6.SocketAddrV6(ip, _)) => IpAddr.V6(ip) }////// Attempts to parse the given string `x` as a `SocketAddr.V4`.///defparseSocketV4(x: String): Option[SocketAddr] =letipPort = String.split({regex = ":"}, x);forM ( (ip, port) <- separateIpPort(ipPort);v4 <- Ipv4Addr.fromString(ip);p <- parsePort(port) ) yield SocketAddr.V4(SocketAddrV4.SocketAddrV4(v4, p))////// Attempts to parse the given string `x` as a `SocketAddr.V6`.///defparseSocketV6(x: String): Option[SocketAddr] =forM (ipPort <- x |> String.drop(1) |> String.split({regex = "]:"}) |> Some;ifString.contains(substr = "[", x); (ip, port) <- separateIpPort(ipPort);v6 <- Ipv6Addr.fromString(ip);p <- parsePort(port) ) yield SocketAddr.V6(SocketAddrV6.SocketAddrV6(v6, p))////// Attempts to parse the given String `x` as a Socket port.///defparsePort(x: String): Option[Int32] =forM (p <- Int32.fromString(x);if0<pandp<65536 ) yieldp////// Attempts to split the given List[String] `x` into IpAddr and port.///defseparateIpPort(x: List[String]): Option[(String, String)] = matchx {caseip :: port :: Nil => Some((ip, port))case_ => None }}