SnmpKit.SnmpLib.Types (snmpkit v0.6.6)

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

Functions

Coerces a value to the specified SNMP type.

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

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

Formats bytes as human-readable size.

Formats Counter64 value with appropriate units.

Formats binary data as hexadecimal string.

Formats an IP address from binary format.

Formats a rate value with units.

Formats TimeTicks as human-readable uptime string.

Automatically infers the SNMP type from an Elixir value.

Checks if a type is a binary SNMP type.

Checks if a type is an exception SNMP type.

Checks if a type is a numeric SNMP type.

Returns the maximum value for a numeric SNMP type.

Returns the minimum value for a numeric SNMP type.

Normalizes a type identifier to a consistent format.

Parses a hexadecimal string to binary.

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

Truncates a string to a maximum length with ellipsis.

Validates a Counter32 value.

Validates a Counter64 value.

Validates a Gauge32 value.

Validates an SNMP integer value.

Validates an IP address value.

Validates an OCTET STRING value.

Validates an OBJECT IDENTIFIER value.

Validates an Opaque value.

Validates a TimeTicks 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.