Search documentation of snmpkit

# SnmpKit.SnmpLib.Types (snmpkit v1.3.17)

SNMP data type validation, formatting, and coercion utilities.

Provides comprehensive support for all SNMP data types including validation, formatting for display, and type coercion between different representations. Includes full support for SNMPv2c exception values.

## Supported SNMP Types

- Basic Types: INTEGER, OCTET STRING, NULL, OBJECT IDENTIFIER
- Application Types: Counter32, Gauge32, TimeTicks, Counter64, IpAddress, Opaque
- SNMPv2c Exception Types: NoSuchObject, NoSuchInstance, EndOfMibView
- Constructed Types: SEQUENCE (for complex structures)

## SNMPv2c Exception Values

These special values are used in SNMPv2c responses to indicate specific conditions:

- `:no_such_object` (0x80): The requested object does not exist in the MIB
- `:no_such_instance` (0x81): The object exists but the specific instance does not
- `:end_of_mib_view` (0x82): End of MIB tree reached during GETBULK/walk operations

## Features

- Type validation with detailed error reporting
- Human-readable formatting for logging and display
- Type coercion and normalization
- Range checking and constraint validation
- Performance-optimized operations
- RFC-compliant exception value handling

## Examples

    # Basic type validation
    iex> SnmpKit.SnmpLib.Types.validate_counter32(42)
    :ok
    iex> SnmpKit.SnmpLib.Types.validate_counter32(-1)
    {:error, :out_of_range}

    # Formatting for display
    iex> SnmpKit.SnmpLib.Types.format_timeticks_uptime(4200)
    "42 seconds"
    iex> SnmpKit.SnmpLib.Types.format_ip_address(<<192, 168, 1, 1>>)
    "192.168.1.1"

    # Type coercion
    iex> SnmpKit.SnmpLib.Types.coerce_value(:counter32, 42)
    {:ok, {:counter32, 42}}
    iex> SnmpKit.SnmpLib.Types.coerce_value(:string, "test")
    {:ok, {:string, "test"}}

    # SNMPv2c exception values
    iex> SnmpKit.SnmpLib.Types.coerce_value(:no_such_object, nil)
    {:ok, {:no_such_object, nil}}
    iex> SnmpKit.SnmpLib.Types.coerce_value(:end_of_mib_view, nil)
    {:ok, {:end_of_mib_view, nil}}

# Summary

## Types

snmp_type()
snmp_value()

## Functions

coerce_value(arg1, value)

Coerces a value to the specified SNMP type.

decode_value(value)

Decodes an SNMP typed value back to a native Elixir value.

encode_value(value, opts \\ [])

Encodes a value with automatic type inference or explicit type specification.

format_bytes(bytes)

Formats bytes as human-readable size.

format_counter64(value)

Formats Counter64 value with appropriate units.

format_hex(binary)

Formats binary data as hexadecimal string.

format_ip_address(arg1)

Formats an IP address from binary format.

format_rate(value, unit)

Formats a rate value with units.

format_timeticks_uptime(centiseconds)

Formats TimeTicks as human-readable uptime string.

infer_type(value)

Automatically infers the SNMP type from an Elixir value.

is_binary_type?(type)

Checks if a type is a binary SNMP type.

is_exception_type?(type)

Checks if a type is an exception SNMP type.

is_numeric_type?(type)

Checks if a type is a numeric SNMP type.

max_value(arg1)

Returns the maximum value for a numeric SNMP type.

min_value(type)

Returns the minimum value for a numeric SNMP type.

normalize_type(type)

Normalizes a type identifier to a consistent format.

parse_hex_string(hex_string)

Parses a hexadecimal string to binary.

parse_ip_address(ip_string)

Parses an IP address string into a 4-tuple of integers.

truncate_string(string, max_length)

Truncates a string to a maximum length with ellipsis.

validate_counter32(value)

Validates a Counter32 value.

validate_counter64(value)

Validates a Counter64 value.

validate_gauge32(value)

Validates a Gauge32 value.

validate_integer(value)

Validates an SNMP integer value.

validate_ip_address(value)

Validates an IP address value.

validate_octet_string(value)

Validates an OCTET STRING value.

validate_oid(oid)

Validates an OBJECT IDENTIFIER value.

validate_opaque(value)

Validates an Opaque value.

validate_timeticks(value)

Validates a TimeTicks value.

validate_unsigned32(value)

Validates an Unsigned32 value.

# Types

# snmp_type()

    @type snmp_type() ::
      :integer
      | :string
      | :null
      | :oid
      | :counter32
      | :gauge32
      | :timeticks
      | :counter64
      | :ip_address
      | :opaque
      | :no_such_object
      | :no_such_instance
      | :end_of_mib_view
      | :unsigned32
      | :octet_string
      | :object_identifier
      | :boolean

# snmp_value()

    @type snmp_value() ::
      integer()
      | binary()
      | :null
      | [non_neg_integer()]
      | {:counter32, non_neg_integer()}
      | {:gauge32, non_neg_integer()}
      | {:timeticks, non_neg_integer()}
      | {:counter64, non_neg_integer()}
      | {:ip_address, binary()}
      | {:opaque, binary()}
      | {:unsigned32, non_neg_integer()}
      | {:no_such_object, nil}
      | {:no_such_instance, nil}
      | {:end_of_mib_view, nil}
      | {:string, binary()}
      | {:octet_string, binary()}
      | {:object_identifier, [non_neg_integer()]}
      | {:boolean, boolean()}

# Functions

# coerce_value(arg1, value)

    @spec coerce_value(snmp_type(), term()) :: {:ok, snmp_value()} | {:error, atom()}

Coerces a value to the specified SNMP type.

## Parameters

- `type`: Target SNMP type
- `raw_value`: Value to coerce

## Returns

- `{:ok, typed_value}` on success
- `{:error, reason}` on failure

## Examples

    {:ok, {:counter32, 42}} = SnmpKit.SnmpLib.Types.coerce_value(:counter32, 42)
    {:ok, {:string, "test"}} = SnmpKit.SnmpLib.Types.coerce_value(:string, "test")
    {:ok, {:ip_address, <<192, 168, 1, 1>>}} = SnmpKit.SnmpLib.Types.coerce_value(:ip_address, {192, 168, 1, 1})

# decode_value(value)

    @spec decode_value({snmp_type(), term()} | term()) :: term()

Decodes an SNMP typed value back to a native Elixir value.

Converts SNMP-encoded values back to their most natural Elixir representation, with consistent handling of strings (always returns binaries, not charlists).

## Parameters

- `typed_value`: A tuple of `{type, value}` or just a value

## Returns

The decoded Elixir value in its most natural form

## Examples

    "hello" = SnmpKit.SnmpLib.Types.decode_value({:string, "hello"})
    "192.168.1.1" = SnmpKit.SnmpLib.Types.decode_value({:ip_address, {192, 168, 1, 1}})
    42 = SnmpKit.SnmpLib.Types.decode_value({:counter32, 42})
    [1, 3, 6, 1] = SnmpKit.SnmpLib.Types.decode_value({:object_identifier, [1, 3, 6, 1]})

# encode_value(value, opts \\ [])

    @spec encode_value(
      term(),
      keyword()
    ) :: {:ok, {snmp_type(), term()}} | {:error, atom()}

Encodes a value with automatic type inference or explicit type specification.

This is the main entry point for encoding values into SNMP types. It supports both automatic type inference based on the value and explicit type specification.

## Parameters

- `value`: The value to encode
- `opts`: Options including:
  - `:type` - Explicit type specification (overrides inference)
  - `:validate` - Whether to validate the encoded value (default: true)

## Returns

- `{:ok, {type, encoded_value}}` on success
- `{:error, reason}` on failure

## Examples

    # Automatic type inference
    {:ok, {:string, "hello"}} = SnmpKit.SnmpLib.Types.encode_value("hello")
    {:ok, {:integer, 42}} = SnmpKit.SnmpLib.Types.encode_value(42)

    # Explicit type specification
    {:ok, {:ip_address, {192, 168, 1, 1}}} = SnmpKit.SnmpLib.Types.encode_value("192.168.1.1", type: :ip_address)
    {:ok, {:counter32, 100}} = SnmpKit.SnmpLib.Types.encode_value(100, type: :counter32)

# format_bytes(bytes)

    @spec format_bytes(non_neg_integer()) :: binary()

Formats bytes as human-readable size.

## Examples

    "1.5 KB" = SnmpKit.SnmpLib.Types.format_bytes(1536)
    "2.3 MB" = SnmpKit.SnmpLib.Types.format_bytes(2400000)

# format_counter64(value)

    @spec format_counter64(non_neg_integer()) :: binary()

Formats Counter64 value with appropriate units.

## Examples

    "42" = SnmpKit.SnmpLib.Types.format_counter64(42)
    "18,446,744,073,709,551,615" = SnmpKit.SnmpLib.Types.format_counter64(18446744073709551615)

# format_hex(binary)

    @spec format_hex(binary()) :: binary()

Formats binary data as hexadecimal string.

## Examples

    "48656C6C6F" = SnmpKit.SnmpLib.Types.format_hex(<<"Hello">>)
    "DEADBEEF" = SnmpKit.SnmpLib.Types.format_hex(<<0xDE, 0xAD, 0xBE, 0xEF>>)

# format_ip_address(arg1)

    @spec format_ip_address(binary()) :: binary()

Formats an IP address from binary format.

## Examples

    "192.168.1.1" = SnmpKit.SnmpLib.Types.format_ip_address(<<192, 168, 1, 1>>)
    "0.0.0.0" = SnmpKit.SnmpLib.Types.format_ip_address(<<0, 0, 0, 0>>)

# format_rate(value, unit)

    @spec format_rate(number(), binary()) :: binary()

Formats a rate value with units.

## Examples

    "100 bps" = SnmpKit.SnmpLib.Types.format_rate(100, "bps")
    "1.5 Mbps" = SnmpKit.SnmpLib.Types.format_rate(1500000, "bps")

# format_timeticks_uptime(centiseconds)

    @spec format_timeticks_uptime(non_neg_integer()) :: binary()

Formats TimeTicks as human-readable uptime string.

## Parameters

- `centiseconds`: Time in centiseconds (hundredths of a second)

## Returns

- Human-readable uptime string

## Examples

    "42 centiseconds" = SnmpKit.SnmpLib.Types.format_timeticks_uptime(42)
    "1 second 50 centiseconds" = SnmpKit.SnmpLib.Types.format_timeticks_uptime(150)
    "1 minute 30 seconds" = SnmpKit.SnmpLib.Types.format_timeticks_uptime(9000)
    "2 hours 15 minutes 30 seconds" = SnmpKit.SnmpLib.Types.format_timeticks_uptime(81300)

# infer_type(value)

    @spec infer_type(term()) :: snmp_type()

Automatically infers the SNMP type from an Elixir value.

Uses intelligent heuristics to determine the most appropriate SNMP type for a given Elixir value.

## Examples

    :string = SnmpKit.SnmpLib.Types.infer_type("hello")
    :integer = SnmpKit.SnmpLib.Types.infer_type(42)
    :ip_address = SnmpKit.SnmpLib.Types.infer_type("192.168.1.1")
    :object_identifier = SnmpKit.SnmpLib.Types.infer_type([1, 3, 6, 1, 2, 1])
    :boolean = SnmpKit.SnmpLib.Types.infer_type(true)

# is_binary_type?(type)

    @spec is_binary_type?(snmp_type()) :: boolean()

Checks if a type is a binary SNMP type.

## Examples

    true = SnmpKit.SnmpLib.Types.is_binary_type?(:string)
    true = SnmpKit.SnmpLib.Types.is_binary_type?(:opaque)
    false = SnmpKit.SnmpLib.Types.is_binary_type?(:integer)

# is_exception_type?(type)

    @spec is_exception_type?(snmp_type()) :: boolean()

Checks if a type is an exception SNMP type.

## Examples

    true = SnmpKit.SnmpLib.Types.is_exception_type?(:no_such_object)
    false = SnmpKit.SnmpLib.Types.is_exception_type?(:integer)

# is_numeric_type?(type)

    @spec is_numeric_type?(snmp_type()) :: boolean()

Checks if a type is a numeric SNMP type.

## Examples

    true = SnmpKit.SnmpLib.Types.is_numeric_type?(:counter32)
    true = SnmpKit.SnmpLib.Types.is_numeric_type?(:integer)
    false = SnmpKit.SnmpLib.Types.is_numeric_type?(:string)

# max_value(arg1)

    @spec max_value(snmp_type()) :: non_neg_integer() | nil

Returns the maximum value for a numeric SNMP type.

## Examples

    4294967295 = SnmpKit.SnmpLib.Types.max_value(:counter32)
    2147483647 = SnmpKit.SnmpLib.Types.max_value(:integer)

# min_value(type)

    @spec min_value(snmp_type()) :: integer() | nil

Returns the minimum value for a numeric SNMP type.

## Examples

    -2147483648 = SnmpKit.SnmpLib.Types.min_value(:integer)
    0 = SnmpKit.SnmpLib.Types.min_value(:counter32)

# normalize_type(type)

    @spec normalize_type(term()) :: snmp_type() | :unknown

Normalizes a type identifier to a consistent format.

## Examples

    :counter32 = SnmpKit.SnmpLib.Types.normalize_type("counter32")
    :integer = SnmpKit.SnmpLib.Types.normalize_type(:integer)
    :string = SnmpKit.SnmpLib.Types.normalize_type("octet_string")

# parse_hex_string(hex_string)

    @spec parse_hex_string(binary()) :: {:ok, binary()} | {:error, atom()}

Parses a hexadecimal string to binary.

## Examples

    {:ok, <<"Hello">>} = SnmpKit.SnmpLib.Types.parse_hex_string("48656C6C6F")
    {:error, :invalid_hex} = SnmpKit.SnmpLib.Types.parse_hex_string("XYZ")

# parse_ip_address(ip_string)

    @spec parse_ip_address(binary()) ::
      {:ok, {0..255, 0..255, 0..255, 0..255}} | {:error, atom()}

Parses an IP address string into a 4-tuple of integers.

## Parameters

- `ip_string`: IP address as a string like "192.168.1.1"

## Returns

- `{:ok, {a, b, c, d}}` on success
- `{:error, reason}` on failure

## Examples

    {:ok, {192, 168, 1, 1}} = SnmpKit.SnmpLib.Types.parse_ip_address("192.168.1.1")
    {:ok, {127, 0, 0, 1}} = SnmpKit.SnmpLib.Types.parse_ip_address("127.0.0.1")
    {:error, :invalid_format} = SnmpKit.SnmpLib.Types.parse_ip_address("invalid")

# truncate_string(string, max_length)

    @spec truncate_string(binary(), pos_integer()) :: binary()

Truncates a string to a maximum length with ellipsis.

## Examples

    "hello" = SnmpKit.SnmpLib.Types.truncate_string("hello", 10)
    "hello..." = SnmpKit.SnmpLib.Types.truncate_string("hello world", 8)

# validate_counter32(value)

    @spec validate_counter32(term()) :: :ok | {:error, atom()}

Validates a Counter32 value.

Counter32 is a 32-bit unsigned integer that wraps around when it reaches its maximum value.

## Parameters

- `value`: Value to validate

## Returns

- `:ok` if valid
- `{:error, reason}` if invalid

## Examples

    :ok = SnmpKit.SnmpLib.Types.validate_counter32(42)
    :ok = SnmpKit.SnmpLib.Types.validate_counter32(4294967295)
    {:error, :out_of_range} = SnmpKit.SnmpLib.Types.validate_counter32(-1)
    {:error, :not_integer} = SnmpKit.SnmpLib.Types.validate_counter32("42")

# validate_counter64(value)

    @spec validate_counter64(term()) :: :ok | {:error, atom()}

Validates a Counter64 value.

Counter64 is a 64-bit unsigned integer for high-speed interfaces.

# validate_gauge32(value)

    @spec validate_gauge32(term()) :: :ok | {:error, atom()}

Validates a Gauge32 value.

Gauge32 is a 32-bit unsigned integer that represents a non-negative integer value. Unlike Counter32, it does not wrap around.

# validate_integer(value)

    @spec validate_integer(term()) :: :ok | {:error, atom()}

Validates an SNMP integer value.

SNMP INTEGER is a signed 32-bit integer.

# validate_ip_address(value)

    @spec validate_ip_address(term()) :: :ok | {:error, atom()}

Validates an IP address value.

IP address should be a 4-byte binary or a tuple of 4 integers.

## Examples

    :ok = SnmpKit.SnmpLib.Types.validate_ip_address(<<192, 168, 1, 1>>)
    :ok = SnmpKit.SnmpLib.Types.validate_ip_address({192, 168, 1, 1})
    {:error, :invalid_length} = SnmpKit.SnmpLib.Types.validate_ip_address(<<192, 168, 1>>)

# validate_octet_string(value)

    @spec validate_octet_string(term()) :: :ok | {:error, atom()}

Validates an OCTET STRING value.

OCTET STRING should be a binary with reasonable length limits.

# validate_oid(oid)

    @spec validate_oid(term()) :: :ok | {:error, atom()}

Validates an OBJECT IDENTIFIER value.

OID should be a list of non-negative integers.

# validate_opaque(value)

    @spec validate_opaque(term()) :: :ok | {:error, atom()}

Validates an Opaque value.

Opaque is used for arbitrary binary data.

# validate_timeticks(value)

    @spec validate_timeticks(term()) :: :ok | {:error, atom()}

Validates a TimeTicks value.

TimeTicks represents time in hundredths of a second (centiseconds).

# validate_unsigned32(value)

    @spec validate_unsigned32(term()) :: :ok | {:error, atom()}

Validates an Unsigned32 value.

Unsigned32 is a 32-bit unsigned integer.