txt: ## dist_cpan-VRURG-IP-Addr.md
  # NAME
  
  IP::Addr - dealing with IPv4/IPv6 addresses
  
  # SYNOPSIS
  
  ```
  my $cidr = IP::Addr.new( "192.0.2.2/27" );
  say $cidr;
  say $cidr.ip;
  for $cidr.network.each -> $ip {
      say $ip;
  }
  
  my $cidr6 = IP::Addr.new( "600d::f00d/123" );
  say $cidr6;
  say $cidr6.ip;
  
  ```
  
  # DESCRIPTION
  
  This module provides functionality for working with IPv4/IPv6 addresses.
  
  ## Module Structure
  
  The main interface is provided by `IP::Addr` class. Typical class usage is demonstrated in the synopsis. The class is a frontend which tries to determine version of the IP address provided to its constructor and creates corresponding handler object available on its `handler` attribute. All methods of the handler are available on `IP::Addr` object via `handles` trait.
  
  For example, for an arbitrary `$ip` object of the class `$ip.ip` call is actually same as calling `$ip.handler.ip`. Method `ip` is a universal one for both v4 and v6 addresses and therefore it is not necessary to care about what exact kind of object we're currently dealing with.
  
  Similarly, version-dependant methods are available too but only when corresponding handler is active. For example:
  
  ```
  say IP::Addr.new( "192.0.2.2/27" ).broadcast;
  
  ```
  
  is a valid call; while
  
  ```
  say IP::Addr.new( "2001:db8::/123" ).broadcast;
  
  ```
  
  will fail with "no method" exception because `broadcast` is not available for IPv6 addresses.
  
  ## Glossary
  
  ### Address forms
  
  Besides of its version each IP address has one more characteristic property: form. It is defined by handler's attribute of the same name: `$!form`. Particular forms are defined by IP-FORM enum defined in `IP::Addr::Common`:
  
  * *ip*
  
    Simple IP address. It has prefix length of 32 bits.
  * *cidr*
  
    CIDR form is an IP address with *prefix* defined.
  
    ```
    192.0.2.3/24
    192.0.2.3/255.255.255.0
    2001::/64
  
    ```
  * *range*
  
    A range is defined by its first and last IP addresses. It has a *selected* or *current* IP address which could be changed as a result of increase, decrease, or iteration operations.
  
    ```
    192.0.2.3-192.0.2.20
    2001::1-2001::1f
  
    ```
  
  ### Ranged forms
  
  CIDR and ranges are *ranged forms* contrary to a single IP form.
  
  ### N-tets
  
  As it is known IP addresses are represented by groups of integers called *octets* for IPv4 and *hextets* for IPv6 (there are variations but I chose these two). *N-tets* is used as a general term for both of them.
  
  # METHODS
  
  ## Constructor
  
  Class constructor `new` simply re-dispatches its arguments to method `set`.
  
  ## `set`
  
  * *`$ip.set( Str $source )` / `$ip.set( Str :$source! )`*
  
    `$source` is a string representation of an IP address in either plain or CIDR notation, or of a range of addresses in a form \*- \*. Formats of valid IP addresses are defined by corresponding standards.
  * *`$ip.set( [ :v4 | :v6 ], *%params )`*
  
    Creates a handler object of specified version of handler (v4 or v6) by passing named `%params` to its constructor.
  
    For example, the following statement:
  
    ```
    $ip.set( :v4, ip => 3221225986, prefix-len => 24 )
  
    ```
  
    Is equivalent to:
  
    ```
    $ip.set( "192.0.2.2/24" )
  
    ```
  
    **Note:** all calls to `set` method result in creation of a new handler object. I.e.:
  
    ```
    my $old-handler = $ip.handler;
    $ip.set( ... );
    say $old-handler === $ip.handler; # False
  
    ```
  
  ## `Str`
  
  Returns a valid string representation of the IP object.
  
  ## `gist`
  
  Same as `Str` method.
  
  ## `each`
  
  Returns an iterable object which would iterate over IPs contained in the current object starting with selected address (i.e. the one returned by `ip` method). For ranged forms to iterate over the whole range (from the `first-ip` to the `last-ip`) use of method `first` is recommended:
  
  ```
  .say for IP::Addr.new( "192.0.2.3/29" ).each;           # 192.0.2.3/29\n192.0.2.4/29 ...
  .say for IP::Addr.new( "192.0.2.3/29" ).first.each;     # 192.0.2.0/29\n192.0.2.1/29 ...
  
  ```
  
  ## `Supply`
  
  Similar to `each` method but returns a `Supply` object. Same rule about starting with selected IP and use of `first` method apply.
  
  # HANDLER METHODS
  
  This sections documents methods common for both IPv4 and IPv6 handlers.
  
  ## Notes
  
  For all methods accepting another IP address as a parameter and where descriptions has a statement *"same version only"* `X::IPAddr::TypeCheck` exception would be thrown if object with a handler of different version is passed.
  
  Address method parameters could either be `IP::Addr` instances or string representations.
  
  ## `set`
  
  Configures the handler object.
  
  **Note** In the following subsection `$handler` notation is used instead of `$ip.handler`.
  
  * *`$handler.set( Str:D $source )` / `$handler.set( Str:D :$source! )`*
  
    Handler attributes are set by parsing a string representation of IP address.
  * *`$handler.set( Int:D :$ip!, Int:D :$!prefix-len )`*
  
    Configures handler object as *CIDR* form.
  * *`$handler.set( Int:D :$first!, Int:D :$!last, Int :$ip? )`*
  
    Configures handler object as *range* form. Optional named parameter `:ip` defines selected IP within range (i.e. the one returned by `ip` method). If omitted then range initial selected IP is its first address.
  * *`$handler.set( Int:D $ip! )`*
  
    Configures a single IP form.
  * *`$handler.set( Int:D @n-tets )`*
  
    Configures a single IP form from integer octets for IPv4 or hextets for IPv6. Number of elements in @n-tets array is defined by the method of the same name.
  
  ## `addr-len`
  
  Returns number of bits for correponding IP version (*32* for IPv4 and *128* for IPv6).
  
  ## `n-tets`
  
  Returns number of n-tets for the current handler (*4* for IPv4 and *8* for IPv6).
  
  ## `version`
  
  Returns integer version of the IP object (*4* or *6*).
  
  ## `ip-classes`
  
  Returns list of hashes of reserved IP ranges. Each hash has two keys:
  
  * *net*
  
    `IP::Addr` object representing the reserved range.
  * *info*
  
    Another hash containing information about the scope of the reserved range in very brief text description:
  
    * *scope*
  
      Scopes are defined by `SCOPE` enum in `IP::Addr::Common`. Currently the following scopes are known:
  
      * `undetermined`
      * `mpublic`
      * `software`
      * `private`
      * `host`
      * `subnet`
      * `documentation`
      * `internet`
      * `routing`
      * `link`
  
      Of those `routing` and `link` are specific to IPv6. `public` isn't officially recognized but used to represent anything not been reserved. `undetermined` is also a special value to be returned if a requested range of IP addresses overlaps with a reserved range but isn't fully contained in it.
    * *description*
  
      Textual information about the reserved block.
  
  ## `ip`
  
  Returns a new `IP::Addr` object representing just an IP address of the current `IP::Addr` object.
  
  ```
  my $ip = IP::Addr.new( "192.0.2.3/24" );
  say $ip;            # 192.0.2.3/24
  say $ip.ip;         # 192.0.2.3
  say $ip.ip.WHO;     # IP::Addr
  
  ```
  
  ## `prefix`
  
  Returns CIDR representation of any form of IP address. For example:
  
  ```
  say IP::Addr.new( "192.0.2.3" ).prefix;     # 192.0.2.3/32
  
  ```
  
  For IPv4 handler additional named parameter `:mask` can be used to use network mask instead of prefix length:
  
  ```
  say IP::Addr.new( "192.0.2.3/24" ).prefix( :mask );     # 192.0.2.3/255.255.255.0
  
  ```
  
  ## `first-ip`
  
  `IP::Addr` object for the first IP address in the range. For single IP will be the same as `ip` method.
  
  ## `last-ip`
  
  `IP::Addr` object for the last IP address in the range. For single IP will be the same as `ip` method.
  
  ## `network`
  
  `IP::Addr` object of the network current IP object belongs to. Makes real sense for CIDR form only though can be used with any other form too.
  
  ## `mask`
  
  Returns string representation of the current IP object mask. Doesn't make much sense for IPv6 addresses because there is officially no such thing for them.
  
  ## `wildcard`
  
  Returns string representation of current IP object wildcard. Doesn't make much sense for IPv6 addresses because there is officially no such thing for them.
  
  ## `size`
  
  Returns number of IP addresses contained in the current `IP::Addr` object. For example:
  
  ```
  say IP::Addr.new( "192.0.0.0/13" ).size;            # 524288
  say IP::Addr.new( "192.0.2.3-192.0.2.23" );         # 21
  
  ```
  
  ## `int-ip`
  
  Returns integer value of the IP address.
  
  ## `int-first-ip`
  
  Returns integer value of the first IP address in the current IP object.
  
  ## `int-last-ip`
  
  Returns integer value of the last IP address in the current IP object.
  
  ## `int-mask`
  
  Returns integer value of current IP object mask. Though not defined as such for IPv6 addresses but could be useful in some address arithmetics.
  
  ## `int-wildcard`
  
  Returns integer value of current IP object wildcard. Though not defined as such for IPv6 addresses but could be useful in some address arithmetics.
  
  ## `inc` / `succ`
  
  Increments IP address by *1*. For ranged IP forms result of this operation won't be greater than the last IP of the range:
  
  ```
  my $ip = IP::Addr.new( "192.0.2.255/24" );
  say $ip.inc;                # 192.0.2.255/24
  
  ```
  
  Rerturns current `IP::Addr` object.
  
  ## `dec` / `pred`
  
  Decrements IP address by *1*. For ranged IP forms result of this operation won't be less than the first IP of the range:
  
  ```
  my $ip = IP::Addr.new( "192.0.2.0/24" );
  say $ip.dec;                # 192.0.2.0/24
  
  ```
  
  Returns current `IP::Addr` object.
  
  ## `add( Int:D $count )`
  
  Shifts IP of the current object by `$count` positions higher. `$count` could be negative. For ranged IP form the result of the operation won't leave the range boundaries:
  
  ```
  my $ip = IP::Addr.new( "192.0.2.255/24" );
  say $ip.add( 10 );              # 192.0.2.255/24
  say $ip.add( -300 );            # 192.0.2.0/24
  
  ```
  
  Returns current `IP::Addr` object.
  
  ## `eq( $addr )`
  
  Same version only.
  
  Returns *True* if current object is equal to `$addr`.
  
  ## `lt( $addr )`
  
  Same version only.
  
  Returns true if the current object is less than `$addr`.
  
  ## `gt( $addr )`
  
  Same version only.
  
  Returns true if the current object is greater than `$addr`
  
  ## `cmp( $addr )`
  
  Same version only.
  
  Returns one of three `Order` values: `Less`, `Same`, or `More`. For ranges comparison is performed by the selected IP.
  
  ## `contains( $addr )`
  
  Same version only.
  
  Returns *True* if current object contains `$addr`. Wether the `$addr` object is the same (e.g. `eq` method would return *True*) then it is also considered as contained.
  
  ## `overlaps( $addr )`
  
  Same version only.
  
  Returns *True* if the current object and `$addr` have at least one common IP address. Useful for starting iteration:
  
  ## `first`
  
  Returns a new `IP::Addr` object whose IP address is the first IP of the current object. Useful for starting iteration.
  
  ```
  my $ip = IP::Addr.new( "192.0.2.12/24" );
  for $ip.first.each { say $_ }       # 192.0.2.0\n192.0.2.1\n...
  
  ```
  
  See `each` method.
  
  ## `next`
  
  Returns a new `IP::Addr` object successive to the current object or *Nil* if current is the last IP of the range.
  
  ## `prev`
  
  Returns a new `IP::Addr` object preceding the current object or *Nil* if current is the first IP of the range.
  
  ## `next-network`
  
  Returns a new `IP::Addr` object containing network successive to the network of the current object. Valid for CIDR form only. Flips over begining/end of IP range:
  
  ```
  $ip = IP::Addr.new( "255.255.255.13/24" );
  say $ip.next-network;               # 0.0.0.0/24
  
  ```
  
  ## `prev-network`
  
  Returns a new `IP::Addr` object containing network preceding the network of the current object. Valid for CIDR form only. Flips over the begining of IP range:
  
  ```
  $ip = IP::Addr.new( "0.0.0.2/24" );
  say $ip.prev-network;               # 255.255.255.0/24
  
  ```
  
  ## `next-range`
  
  Returns a new `IP::Addr` object containing range of the same length successive to the current object. Valid for range form only.
  
  ## `prev-range`
  
  Returns a new `IP::Addr` object containing range of the same length preceding the current object. Valid for range form only.
  
  ## `to-int( @n-tets )`
  
  Converts an array of n-tets to integer value corresponding to the current handler's IP version.
  
  ## `to-n-tets( Int:D $addr )`
  
  Splits integer represnation of IP address into n-tets corresponding to the current handler's IP version.
  
  ## `info`
  
  Returns a hash with information about the current IP object. The hash contains two keys: `scope` and `description`. See `ip-classes` method for more information.
  
  ## `Str`
  
  Stringifies current IP object with regard to its form.
  
  # OPERATORS
  
  For all supported operators where both operands are addresses at least one of them has to be a `IP::Addr` object. The other one could be a string representation of an address.
  
  ## `prefix/postfix ++` and `prefix/postfix --`
  
  Standard Raku operatios working by calling `succ`/`pred` methods on `IP::Addr` object.
  
  ## `infix + ( $addr, $int )`
  
  Adds an integer value to the address. The resulting address will never get out of network/range boundaries for objects of corresponding forms. A new `IP::Addr` object is returned.
  
  ```
  $ip2 = $ip1 + 3;
  
  ```
  
  ## `infix - ( $addr, $int )`
  
  Deducts an integer value from the address. The resulting address will never get out of network/range boundaries for objects of corresponding forms. A new `IP::Addr` object is returned.
  
  ```
  $ip2 = $ip1 - 3;
  
  ```
  
  ## `infix cmp ( $addr1, $addr2 )`
  
  Compares two IP addresses.
  
  ```
  given $ip1 cmp $ip2 {
      when Less { say "smaller" }
      when Same { say "same" }
      when More { say "bigger" }
  }
  
  ```
  
  ## `infix eqv / infix == ( $addr1, $addr2 )`
  
  Checks if two addresses are equal. See handler's `eq` method.
  
  ## `infix < ( $addr1, $addr2 )`
  
  *True* if `$addr1` is less than `$addr2`. See handler's `lt` method.
  
  ## `infix <= / infix ≤ ( $addr1, $addr2 )`
  
  *True* if `$addr1` is less than or equal to `$addr2`.
  
  ## `infix > ( $addr1, $addr2 )`
  
  *True* if `$addr1` is greater than `$addr2`. See handler's `gt` method.
  
  ## `infix >= / infix ≥ ( $addr1, $addr2 )`
  
  *True* `$addr1` greater than or equal to `$addr2`.
  
  ## `infix (cont) / infix ⊇ ( $addr1, $addr2 )`
  
  *True* if `$addr1` object contains `$addr2`. See handler's `contains` method.
  
  ## `infix ⊆ ( $addr1, $addr2 )`
  
  *True* if `$addr1` is contained by `$addr2`.
  
  # CAVEATS
  
  The author doesn't use IPv6 in his setups. All the functionality provided here is developed using information from corresponding Wikipedia pages. Therefore, "here be dragons"©. Please, report back any issue encountered!
  
  # AUTHOR
  
  Vadim Belman [vrurg@cpan.org](mailto:vrurg@cpan.org)
  