(*---------------------------------------------------------------------------*
  INTERFACE  cf_ip4_addr.mli

  Copyright (c) 2003-2006, James H. Woodyatt
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *---------------------------------------------------------------------------*)

(** IPv4 addresses with attribute parameters for type safety.

    This module implements IPv4 addresses in an abstract type suitable for use
    with the {!Cf_nameinfo} module, the {!Cf_socket} module and its cognates
    for IPv4 transports.  Internally, the IPv4 address is represented as a
    boxed 4-byte custom block.  Externally, the IPv4 address abstract type is
    parameterized with a shadow attribute that constrains how it may be used
    depending on its address category.
*)

(** The type of IPv4 addresses, parameterized by address category attribute. *)
type -'a t

(** The shadow attribute type of IPv4 addresses of unknown category. *)
type opaque = [ `AF_INET ]

(** The IPv4 address category type. *)
type category =
    | Unspecified   (** 0.0.0.0 *)
    | Unicast       (** 0.0.0.1 to 223.255.255.255 *)
    | Multicast     (** 224.0.0.0 to 239.255.255.255 *)
    | Experimental  (** 240.0.0.0 to 255.255.255.254 *)
    | Broadcast     (** 255.255.255.255 *)

(** The shadow attribute type of IPv4 addresses of the Unspecified category. *)
type unspecified = [ opaque | `X ]

(** The shadow attribute type of IPv4 addresses of the Unicast category. *)
type unicast = [ opaque | `U ]

(** The shadow attribute type of IPv4 addresses of the Multicast category. *)
type multicast = [ opaque | `M ]

(** The shadow attribute type of IPv4 addresses of the Experimental category.
*)
type experimental = [ opaque | `E ]

(** The shadow attribute type of IPv4 addresses of the Broadcast category. *)
type broadcast = [ opaque | `B ]

(** Use [category a] to obtain the category of an opaque IPv4 address. *)
val category: opaque t -> category

(** Use [is_unicast a] to validate that an IPv4 address is a unicast address.
    Raises [Failure] if the address is not a unicast address.
*)
val is_unicast: [> opaque ] t -> unicast t

(** Use [is_multicast a] to validate that an IPv4 address is a multicast
    address.  Raises [Failure] if the address is not a multicast address.
*)
val is_multicast: [> opaque ] t -> multicast t

(** Use [is_experimental a] to validate that an IPv4 address is an experimental
    address.  Raises [Failure] if the address is not an experimental address.
*)
val is_experimental: [> opaque ] t -> experimental t

(** The type of unicast address realms. *)
type unicast_realm =
    | U_loopback    (** Loopback, i.e. 127/8 *)
    | U_link        (** Link-local, i.e. 169.254/16 *)
    | U_private     (** Private, i.e. 10/8, 172.16/12 and 192.168/16 *)
    | U_global      (** Global, all other unicast addresses *)

(** Use [unicast_realm a] to identify the address realm of the unicast address
    [a].
*)
val unicast_realm: [> unicast ] t -> unicast_realm

(** The type of multicast address realms. *)
type multicast_realm = M_link | M_global

(** Use [multicast realm a] to identify the address of the multicast address
    [a].
*)
val multicast_realm: [> multicast ] t -> multicast_realm

(** The unspecified IPv4 address, i.e. 0.0.0.0. *)
val any: unspecified t

(** The link-local broadcast IPv4 address, i.e. 255.255.255.255. *)
val broadcast: broadcast t

(** The default loopback host address, i.e. 127.0.0.1. *)
val loopback: unicast t

(** The empty group multicast address, i.e. 224.0.0.0. *)
val empty_group: multicast t

(** The all-hosts group multicast address, i.e. 224.0.0.1 *)
val all_hosts_group: multicast t 

(** The all-routers group multicast address, i.e. 224.0.0.2 *)
val all_routers_group: multicast t

(** Use [equal a1 a2] to compare two IPv4 addresses for equality. *)
val equal: [> opaque ] t -> [> opaque ] t -> bool

(** Use [compare a1 a2] to compare the ordinality of two IPv4 addresses. *)
val compare: [> opaque ] t -> [> opaque ] t -> int

(** Use [pton s] to convert the string [s] containing an IPv4 address in
    dot-quad format to its equivalent opaque IPv4 address.  Returns [None] if
    the string is not in dot-quad format.
*)
val pton: string -> opaque t option

(** Use [ntop a] to obtain a string representation of the IPv4 address [a]
    in dot-quad format. *)
val ntop: [> opaque ] t -> string

(** The type of an IPv4 network identifier. *)
type 'a network constraint 'a = [> opaque ]

(** Use [net_create ?subnet a] to create an IPv4 network identifier that
    contains the address [a] in its logical scope, optional constraining the
    network to subnetwork of width [subnet].
*)
val net_create: ?subnet:int -> ([> opaque ] as 'a) t -> 'a network

(** Use [net_number n] to produce the IPv4 address conventionally used to
    identify the network.
*)
val net_number: 'a network -> 'a t

(** Use [net_broadcast n] to produce the IPv4 address conventionally used to
    identify the broadcast address for the network or subnet.
*)
val net_broadcast: 'a network -> 'a t

(** Use [net_prefix] to obtain the number of bits in the subnet mask. *)
val net_prefix: 'a network -> int

(** Use [net_member n a] to test whether the address [a] is in the scope of the
    network [n].
*)
val net_member: 'a network -> 'a t -> bool

(** Use [net_mask n] to return a string representation of the subnet mask for
    the network [n] in traditional dot-quad format.
*)
val net_mask: 'a network -> string

(** Use [net_increasing n] to obtain the sequence of unicast IPv4 addresses
    belong to the network [n] in increasing order.
*)
val net_increasing: 'a network -> 'a t Cf_seq.t

(** Use [net_decreasing n] to obtain the sequence of unicast IPv4 addresses
    belong to the network [n] in decreasing order.
*)
val net_decreasing: 'a network -> 'a t Cf_seq.t

(*--- End of File [ cf_ip4_addr.mli ] ---*)
