Search results

There are no results.

std.net.ip.Ipv6Address

class pub Ipv6Address

An IPv6 address.

Static methods

new

Show source code
Hide source code
fn pub static new(
  a: Int,
  b: Int,
  c: Int,
  d: Int,
  e: Int,
  f: Int,
  g: Int,
  h: Int,
) -> Ipv6Address {
  Ipv6Address(a: a, b: b, c: c, d: d, e: e, f: f, g: g, h: h)
}
fn pub static new(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int) -> Ipv6Address

Returns a new IPv6 address using the given hextets.

parse

Show source code
Hide source code
fn pub static parse(input: String) -> Option[Ipv6Address] {
  let bytes = input.to_byte_array
  let mut cursor = 0
  let max = bytes.size
  let segments = []
  let ipv4_segments = []
  let segment_bytes = ByteArray.new
  let mut compressed = false
  let mut ipv4_mode = false
  let mut max_hextet_value = IPV6_HEXTET_MAXIMUM
  let mut format = Format.Hex

  # No point in parsing the input if we're certain it's not a valid address.
  if max > IPV6_STRING_MAXIMUM_LENGTH { return Option.None }

  while cursor < max {
    # IPv6 addresses can embed IPv4 addresses, so instead of reading until we
    # encounter a ":" we will also stop reading when running into a ".".
    while
      cursor < max
        and bytes.get(cursor) != COLON_BYTE
        and bytes.get(cursor) != DOT_BYTE
    {
      segment_bytes.push(bytes.get(cursor))
      cursor += 1
    }

    # The moment we encounter a dot we'll enter IPv4 mode, and remain in this
    # mode until we reach the end of the input, as embedded IPv4 addresses
    # must be at the end of an IPv6 address.
    if ipv4_mode.false? and cursor < max and bytes.get(cursor) == DOT_BYTE {
      ipv4_mode = true
      format = Format.Decimal
      max_hextet_value = IPV4_OCTET_MAXIMUM
    }

    # When the IP starts with a "::" we won't be able to read input, so the
    # byte buffer is empty.
    if segment_bytes.size > 0 {
      let int = try Int.parse(segment_bytes, format)

      segment_bytes.clear

      if int < IP_MINIMUM_VALUE or int > max_hextet_value {
        return Option.None
      }

      if ipv4_mode { ipv4_segments.push(int) } else { segments.push(int) }
    }

    cursor += 1

    # We have reached another ":", which is used to compress one or more empty
    # groups together.
    if cursor < max and bytes.get(cursor) == COLON_BYTE {
      # Zero compression can only be applied once.
      if compressed { return Option.None }

      compressed = true

      let mut pad = IPV6_HEXTETS - segments.size
      let mut pad_cursor = cursor
      let mut ipv4_padded = false
      let look_ahead = cursor + 1 < max

      # Scan ahead in the input to determine how many empty hextets we need to
      # add, based on the remaining number of hextets.
      #
      # When the compression is at the end of the input (e.g. "1::") there is
      # no point in looking ahead, so we don't.
      while pad_cursor < max and look_ahead {
        let byte = bytes.get(pad_cursor)

        if byte == COLON_BYTE { pad -= 1 }

        # Two IPv4 octets can be stored in a single IPv6 hextet, meaning we'd
        # have to reduce padding by two. Since we already skip padding for the
        # ":" that preceeds the IPv4 address, we only reduce the padding by
        # one.
        if ipv4_padded.false? and byte == DOT_BYTE {
          ipv4_padded = true
          pad -= 1
        }

        pad_cursor += 1
      }

      while pad > 0 {
        segments.push(0)
        pad -= 1
      }

      cursor += 1
    }
  }

  if ipv4_segments.size == IPV4_OCTETS {
    segments.push(
      octets_to_hextet(ipv4_segments.get(0), ipv4_segments.get(1)),
    )
    segments.push(
      octets_to_hextet(ipv4_segments.get(2), ipv4_segments.get(3)),
    )
  }

  if segments.size != IPV6_HEXTETS { return Option.None }

  Option.Some(
    Ipv6Address.new(
      segments.get(0),
      segments.get(1),
      segments.get(2),
      segments.get(3),
      segments.get(4),
      segments.get(5),
      segments.get(6),
      segments.get(7),
    ),
  )
}
fn pub static parse(input: String) -> Option[Ipv6Address]

Parses an IPv6 address literal.

This method only supports IPv6 addresses. Port numbers, zones, and CIDR masks are not supported.

Examples

Parsing an IPv6 address:

import std.net.ip (Ipv6Address)

Ipv6Address.parse('::1').get.v6? # => true

Instance methods

!=

Show source code
Hide source code
fn pub !=(other: T) -> Bool {
  (self == other).false?
}
fn pub !=(other: T) -> Bool

Returns true if self and the given object are not equal to each other.

==

Show source code
Hide source code
fn pub ==(other: ref Ipv6Address) -> Bool {
  @a == other.a
    and @b == other.b
    and @c == other.c
    and @d == other.d
    and @e == other.e
    and @f == other.f
    and @g == other.g
    and @h == other.h
}
fn pub ==(other: ref Ipv6Address) -> Bool

Returns true if self and the given IP address are the same.

Examples

Comparing two IPv6 addresses:

import std.net.ip (Ipv6Address)

let addr1 = Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 1)
let addr2 = Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 1)
let addr3 = Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 2)

addr1 == addr2 # => true
addr1 == addr3 # => false

clone

Show source code
Hide source code
fn pub clone -> Ipv6Address {
  Ipv6Address(a: @a, b: @b, c: @c, d: @d, e: @e, f: @f, g: @g, h: @h)
}
fn pub clone -> Ipv6Address

Creates a clone of self.

documentation?

Show source code
Hide source code
fn pub documentation? -> Bool {
  @a == 0x2001 and @b == 0xdb8
}
fn pub documentation? -> Bool

Returns true if self is in a range designated for documentation.

All addresses in the range 2001:db8::/32 are designated for documentation.

Examples

Checking if an IPv6 address is a documentation address:

import std.net.ip (Ipv6Address)

Ipv6Address.new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).documentation # => true

fmt

Show source code
Hide source code
fn pub fmt(formatter: mut Formatter) {
  formatter.write(to_string)
}
fn pub fmt(formatter: mut Formatter)

Formats self in a human-readable format for debugging purposes.

into_string

Show source code
Hide source code
fn pub move into_string -> String {
  to_string
}
fn pub move into_string -> String

Moves self into a String.

ipv4_compatible?

Show source code
Hide source code
fn pub ipv4_compatible? -> Bool {
  @a == 0 and @b == 0 and @c == 0 and @d == 0 and @e == 0 and @f == 0
}
fn pub ipv4_compatible? -> Bool

Returns true if self is an IPv4-compatible IPv6 address.

Examples

Checking if an IPv6 address is an IPv4-compatible IPv6 address:

import std.net.ip (Ipv6Address)

Ipv6Address.new(0, 0, 0, 0, 0, 0, 1, 1).ipv4_compatible? # => true

ipv4_mapped?

Show source code
Hide source code
fn pub ipv4_mapped? -> Bool {
  @a == 0
    and @b == 0
    and @c == 0
    and @d == 0
    and @e == 0
    and @f == IPV6_HEXTET_MAXIMUM
}
fn pub ipv4_mapped? -> Bool

Returns true if self is an IPv4-mapped IPv6 address.

Examples

Checking if an IPv6 address is an IPv4-mapped IPv6 address:

import std.net.ip (Ipv6Address)

Ipv6Address.new(0, 0, 0, 0, 0, 0xffff, 1, 1).ipv4_compatible? # => true

loopback?

Show source code
Hide source code
fn pub loopback? -> Bool {
  @a == 0
    and @b == 0
    and @c == 0
    and @d == 0
    and @e == 0
    and @f == 0
    and @g == 0
    and @h == 1
}
fn pub loopback? -> Bool

Returns true if self is a loopback address (::1).

Examples

Checking if an address is a loopback address:

import std.net.ip (Ipv6Address)

Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 1).loopback? # => true
Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 2).loopback? # => false

multicast?

Show source code
Hide source code
fn pub multicast? -> Bool {
  @a & 0xff00 == 0xff00
}
fn pub multicast? -> Bool

Returns true if self is a multicast address (ff00::/8).

Examples

Checking if an address is a multicast address:

import std.net.ip (Ipv6Address)

Ipv6Address.new(0xff00, 0, 0, 0, 0, 0, 0, 0).multicast? # => true
Ipv6Address.new(0xff01, 0, 0, 0, 0, 0, 0, 0).multicast? # => true
Ipv6Address.new(0, 1, 0, 0, 0, 0, 0, 0).multicast?      # => false

to_string

Show source code
Hide source code
fn pub to_string -> String {
  if unspecified? { return '::' }

  if loopback? { return '::1' }

  let ipv4_compatible = ipv4_compatible?
  let ipv4_mapped = ipv4_mapped?

  if ipv4_compatible or ipv4_mapped {
    # This value (256) is used to convert a hextet to the second and fourth
    # octet in an IPv4 address. For example, for a hextet 0x2ff this produces
    # an octet of 255.
    let hextet_to_octet_modulo = IPV4_OCTET_MAXIMUM + 1
    let prefix = if ipv4_compatible { '::' } else { '::ffff:' }
    let a = @g >> IPV4_TOIPV6_SHIFT
    let b = @g % hextet_to_octet_modulo
    let c = @h >> IPV4_TOIPV6_SHIFT
    let d = @h % hextet_to_octet_modulo

    return '${prefix}${a}.${b}.${c}.${d}'
  }

  let mut compression_start = 0
  let mut compression_len = 0
  let mut current_at = 0
  let mut current_len = 0
  let mut index = 0
  let segments = [@a, @b, @c, @d, @e, @f, @g, @h]

  # Find the longest sequence of empty hextets, which we will compress
  # together.
  while index < segments.size {
    let hextet = segments.get(index)

    if hextet == 0 {
      if current_len == 0 { current_at = index }

      current_len += 1

      if current_len > compression_len {
        compression_len = current_len
        compression_start = current_at
      }
    } else {
      current_at = 0
      current_len = 0
    }

    index += 1
  }

  let format = Format.Hex

  if compression_len > 0 {
    let buffer = StringBuffer.new
    let compression_end = compression_start + compression_len

    segments.iter.each_with_index(fn (index, hextet) {
      if index < compression_start {
        if index > 0 { buffer.push(':') }

        buffer.push(hextet.format(format))
      } else if index == compression_start {
        buffer.push('::')
      } else if index >= compression_end {
        if index > compression_end { buffer.push(':') }

        buffer.push(hextet.format(format))
      }
    })

    return buffer.to_string
  }

  let a = @a.format(format)
  let b = @b.format(format)
  let c = @c.format(format)
  let d = @d.format(format)
  let e = @e.format(format)
  let f = @f.format(format)
  let g = @g.format(format)
  let h = @h.format(format)

  '${a}:${b}:${c}:${d}:${e}:${f}:${g}:${h}'
}
fn pub to_string -> String

Converts self to a String.

Zero compression is applied to the longest sequence of empty hextets, if there are any.

Examples

Converting an IPv6 address to a String:

import std.net.ip (Ipv6Address)

Ipv6Address.new.to_string # => '::'
Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 1) # => '::1'

unspecified?

Show source code
Hide source code
fn pub unspecified? -> Bool {
  @a == 0
    and @b == 0
    and @c == 0
    and @d == 0
    and @e == 0
    and @f == 0
    and @g == 0
    and @h == 0
}
fn pub unspecified? -> Bool

Returns true if self is the special "unspecified" address (::).

Examples

import std.net.ip (Ipv6Address)

Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 0).unspecified? # => true
Ipv6Address.new(0, 0, 0, 0, 0, 0, 0, 1).unspecified? # => false

Implemented traits

std.clone.

Clone

impl Clone[Ipv6Address] for Ipv6Address
std.cmp.

Equal

impl Equal[ref Ipv6Address] for Ipv6Address
std.fmt.

Format

impl Format for Ipv6Address
std.string.

IntoString

impl IntoString for Ipv6Address
std.string.

ToString

impl ToString for Ipv6Address