/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Henrik Böving
-/
module

prelude
public import Init.System.IO
public import Init.Data.Vector.Basic

@[expose] public section

/-!
This module contains Lean representations of IP and socket addresses:
- `IPv4Addr`: Representing IPv4 addresses.
- `SocketAddressV4`: Representing a pair of IPv4 address and port.
- `IPv6Addr`: Representing IPv6 addresses.
- `SocketAddressV6`: Representing a pair of IPv6 address and port.
- `IPAddr`: Can either be an `IPv4Addr` or an `IPv6Addr`.
- `SocketAddress`: Can either be a `SocketAddressV4` or `SocketAddressV6`.
-/

namespace Std
namespace Net

/--
Representation of a MAC address.
-/
structure MACAddr where
  /--
  This structure represents the address: `octets[0]:octets[1]:octets[2]:octets[3]:octets[4]:octets[5]`.
  -/
  octets : Vector UInt8 6
  deriving Inhabited, DecidableEq

/--
Representation of an IPv4 address.
-/
structure IPv4Addr where
  /--
  This structure represents the address: `octets[0].octets[1].octets[2].octets[3]`.
  -/
  octets : Vector UInt8 4
  deriving Inhabited, DecidableEq

/--
A pair of an `IPv4Addr` and a port.
-/
structure SocketAddressV4 where
  addr : IPv4Addr
  port : UInt16
  deriving Inhabited, DecidableEq

/--
Representation of an IPv6 address.
-/
structure IPv6Addr where
  /--
  This structure represents the address: `segments[0]:segments[1]:...`.
  -/
  segments : Vector UInt16 8
  deriving Inhabited, DecidableEq

/--
A pair of an `IPv6Addr` and a port.
-/
structure SocketAddressV6 where
  addr : IPv6Addr
  port : UInt16
  deriving Inhabited, DecidableEq

/--
An IP address, either IPv4 or IPv6.
-/
inductive IPAddr where
  | v4 (addr : IPv4Addr)
  | v6 (addr : IPv6Addr)
  deriving Inhabited, DecidableEq

/--
Either a `SocketAddressV4` or `SocketAddressV6`.
-/
inductive SocketAddress where
  | v4 (addr : SocketAddressV4)
  | v6 (addr : SocketAddressV6)
  deriving Inhabited, DecidableEq

/--
The kinds of address families supported by Lean, currently only IP variants.
-/
inductive AddressFamily where
  | ipv4
  | ipv6
  deriving Inhabited, DecidableEq

namespace IPv4Addr

/--
Build the IPv4 address `a.b.c.d`.
-/
def ofParts (a b c d : UInt8) : IPv4Addr :=
  { octets := #v[a, b, c, d] }

/--
Try to parse `s` as an IPv4 address, returning `none` on failure.
-/
@[extern "lean_uv_pton_v4"]
opaque ofString (s : @&String) : Option IPv4Addr

/--
Turn `addr` into a `String` in the usual IPv4 format.
-/
@[extern "lean_uv_ntop_v4"]
opaque toString (addr : @&IPv4Addr) : String

instance : ToString IPv4Addr where
  toString := toString

instance : Coe IPv4Addr IPAddr where
  coe addr := .v4 addr

end IPv4Addr

namespace SocketAddressV4

instance : Coe SocketAddressV4 SocketAddress where
  coe addr := .v4 addr

end SocketAddressV4

namespace IPv6Addr

/--
Build the IPv6 address `a:b:c:d:e:f:g:h`.
-/
def ofParts (a b c d e f g h : UInt16) : IPv6Addr :=
  { segments := #v[a, b, c, d, e, f, g, h] }

/--
Try to parse `s` as an IPv6 address according to
[RFC 2373](https://datatracker.ietf.org/doc/html/rfc2373), returning `none` on failure.
-/
@[extern "lean_uv_pton_v6"]
opaque ofString (s : @&String) : Option IPv6Addr

/--
Turn `addr` into a `String` in the IPv6 format described in
[RFC 2373](https://datatracker.ietf.org/doc/html/rfc2373).
-/
@[extern "lean_uv_ntop_v6"]
opaque toString (addr : @&IPv6Addr) : String

instance : ToString IPv6Addr where
  toString := toString

instance : Coe IPv6Addr IPAddr where
  coe addr := .v6 addr

end IPv6Addr

namespace SocketAddressV6

instance : Coe SocketAddressV6 SocketAddress where
  coe addr := .v6 addr

end SocketAddressV6

namespace IPAddr

/--
Obtain the `AddressFamily` associated with an `IPAddr`.
-/
def family : IPAddr → AddressFamily
  | .v4 .. => .ipv4
  | .v6 .. => .ipv6

def toString : IPAddr → String
  | .v4 addr => addr.toString
  | .v6 addr => addr.toString

instance : ToString IPAddr where
  toString := toString

end IPAddr

namespace SocketAddress

/--
Obtain the `AddressFamily` associated with a `SocketAddress`.
-/
def family : SocketAddress → AddressFamily
  | .v4 .. => .ipv4
  | .v6 .. => .ipv6

/--
Obtain the `IPAddr` contained in a `SocketAddress`.
-/
def ipAddr : SocketAddress → IPAddr
  | .v4 sa  => .v4 sa.addr
  | .v6 sa  => .v6 sa.addr

/--
Obtain the port contained in a `SocketAddress`.
-/
def port : SocketAddress → UInt16
  | .v4 sa | .v6 sa => sa.port

end SocketAddress

/--
Represents an interface address, including details such as the interface name,
whether it is internal, the associated address, and the network mask.
-/
structure InterfaceAddress where
  /--
  The name of the network interface.
  -/
  name : String

  /-
  The physical (MAC) address of the interface.
  -/
  physicalAddress : MACAddr

  /--
  Indicates whether the interface is a loopback interface.
  -/
  isLoopback : Bool

  /--
  The IP address assigned to the interface.
  -/
  address : IPAddr

  /--
  The subnet mask associated with the interface.
  -/
  netMask : IPAddr
  deriving Inhabited, DecidableEq

/--
Gets address information about the network interfaces on the system, including disabled ones and
multiple addresses for each interface.
-/
@[extern "lean_uv_interface_addresses"]
opaque interfaceAddresses : IO (Array InterfaceAddress)

end Net
end Std
