Elixir XDR

Build BadgeCoverage StatusVersion BadgeDownloads BadgeLicense badge

Process XDR types based on the RFC4506. Extend with ease to other XDR types.

Installation

Available in Hex, Add elixir_xdr to your list of dependencies in mix.exs:

def deps do
  [
    {:elixir_xdr, "~> 0.1.0"}
  ]
end

Implemented types

The following XDR types are completely implemented in this library:

# Basic types
XDR.Int                  # Section 4.1
XDR.UInt                 # Section 4.2
XDR.Bool                 # Section 4.4
XDR.HyperInt             # Section 4.5
XDR.HyperUInt            # Section 4.5
XDR.Float                # Section 4.6
XDR.DoubleFloat          # Section 4.7
XDR.Void                 # Section 4.16

# Complex types
XDR.Enum                 # Section 4.3
XDR.FixedOpaque          # Section 4.9
XDR.VariableOpaque       # Section 4.10
XDR.String               # Section 4.11
XDR.FixedArray           # Section 4.12
XDR.VariableArray        # Section 4.13
XDR.Struct               # Section 4.14
XDR.Union                # Section 4.15
XDR.Optional             # Section 4.19

The following types were not implemented

XDR.QuadFloat            # Section 4.8, not supported for 128-byte size.
XDR.Const                # Section 4.17, can be replaced with elixir constants.
XDR.Typedef              # Section 4.18, may be implemented with elixir modules. More info bellow in this guude.

How to implement a XDR type?

Behavior is the key. When implementing a new XDR type follow this Behavior's Declaration.

Decoding output

Encoded binaries may overflow the byte(s) size. That's why the returning value for decoding functions is set to be a tuple. Second element holds the remaining binary after decoding. This applies to all XDR types.

iex> XDR.Int.decode_xdr!(<<0, 0, 4, 210, 5>>)
{%XDR.Int{datum: 1234}, <<5>>}

Usage examples

XDR.Int

For encoding integers use encode_xdr/2 or use the raising version of the function encode_xdr!/2.

iex> XDR.Int.new(1234) |> XDR.Int.encode_xdr()
{:ok, <<0, 0, 4, 210>>}

iex> XDR.Int.new(1234) |> XDR.Int.encode_xdr!()
<<0, 0, 4, 210>>

For decoding use decode_xdr/2 or decode_xdr!/2.

iex> XDR.Int.decode_xdr(<<0, 0, 4, 210>>)
{:ok, {%XDR.Int{datum: 1234}, <<>>}}

iex> XDR.Int.decode_xdr!(<<0, 0, 4, 210>>)
{%XDR.Int{datum: 1234}, <<>>}

XDR.Bool

As mentioned before all the XDR types follow the same Behavior's Declaration

iex> XDR.Bool.new(true) |> XDR.Bool.encode_xdr()
{:ok, <<0, 0, 0, 0>>}

iex> XDR.Bool.new(true) |> XDR.Bool.encode_xdr!()
<<0, 0, 0, 0>>

For decoding the binary use decode_xdr/2 or decode_xdr!/2..

iex> XDR.Bool.decode_xdr(<<0, 0, 0, 1>>)
{:ok, {%XDR.Bool{declarations: [false: 0, true: 1], identifier: true}, ""}}

iex> XDR.Bool.decode_xdr!(<<0, 0, 0, 1>>)
{%XDR.Bool{declarations: [false: 0, true: 1], identifier: true}, ""}

XDR.Enum

Enums are keywords lists containing a set of declarations (statically defined) and a indentifier with the key of the selected declaration.

The XDR.Bool is a clear example of an Enum implementation.

iex> XDR.Bool.decode_xdr!<<0, 0, 0, 1>>)
{%XDR.Bool{declarations: [false: 0, true: 1], identifier: true}, ""}

XDR.FixedOpaque

FixedOpaque is used for fixed-length uninterpreted data that needs to be passed among machines, in other words, let's think on a string that must match a fixed length.

iex> ComplementBinarySize.new(<<1,2,3,4,5>>) |> ComplementBinarySize.encode_xdr()
{:ok, <<1, 2, 3, 4, 5, 0, 0, 0>>}

An example is available here: FixedOpaque Type.

XDR.String

For econding strings.

iex> XDR.String.new("The little prince") |> XDR.String.encode_xdr()
{:ok,
 <<0, 0, 0, 17, 84, 104, 101, 32, 108, 105, 116, 116, 108, 101, 32, 112, 114,
   105, 110, 99, 101, 0, 0, 0>>}

iex> XDR.String.new("The little prince") |> XDR.String.encode_xdr!()
<<0, 0, 0, 17, 84, 104, 101, 32, 108, 105, 116, 116, 108, 101, 32, 112, 114,
  105, 110, 99, 101, 0, 0, 0>>

For decoding strings.

iex> XDR.String.decode_xdr(<<0, 0, 0, 17, 84, 104, 101, 32, 108, 105, 116, 116, 108, 101, 32, 112, 114,
  105, 110, 99, 101, 0, 0, 0>>)
{:ok, {%XDR.String{max_length: 4294967295, string: "The little prince"}, ""}}

iex> XDR.String.decode_xdr!(<<0, 0, 0, 17, 84, 104, 101, 32, 108, 105, 116, 116, 108, 101, 32, 112, 114,
  105, 110, 99, 101, 0, 0, 0>>)
{%XDR.String{max_length: 4294967295, string: "The little prince"}, ""}

XDR.Struct

iex(1)> name = XDR.String.new("The little prince")
%XDR.String{max_length: 4294967295, string: "The little prince"}

iex(2)> size = XDR.Int.new(298)
%XDR.Int{datum: 298}

iex(3)> Book.new(name, size) |> Book.encode_xdr()
{:ok,
 <<0, 0, 0, 17, 84, 104, 101, 32, 108, 105, 116, 116, 108, 101, 32, 112, 114,
   105, 110, 99, 101, 0, 0, 0, 0, 0, 1, 42>>}

An example is available here: Struct Type.

XDR.Union

A union is a type composed of a discriminant (Statement) followed by a type selected from a set of prearranged types (UnionStatement). The type of discriminant is either "Int", "Unsigned Int", or an Enumerated type, such as "Bool". The (UnionStatement) types are called "arms" of the union and are preceded by the value of the discriminant that implies their encoding.

iex(1)> XDR.UnionStatement.new(:ST_NOMINATE) |> XDR.UnionStatement.encode_xdr()
{:ok, <<0, 0, 0, 3, 64, 93, 112, 164>>}

iex(3)> XDR.UnionStatement.decode_xdr(<<0, 0, 0, 3, 64, 93, 112, 164>>)
{:ok, {{:ST_NOMINATE, %XDR.Float{float: 3.4600000381469727}}, ""}}

An example is available here: Union Example

XDR.Optional

iex(1)> XDR.String.new("Hello") |> OptionalString.new() |> OptionalString.encode_xdr()
{:ok, <<0, 0, 0, 1, 0, 0, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0>>}

iex(2)> OptionalString.decode_xdr(<<0, 0, 0, 1, 0, 0, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0>>)
{:ok,
 {%XDR.Optional{type: %XDR.String{max_length: 4294967295, string: "Hello"}}, ""}}

iex(3)> OptionalString.new(nil) |> OptionalString.encode_xdr()
{:ok, <<0, 0, 0, 0>>}

iex(4)> OptionalString.decode_xdr(<<0, 0, 0, 0>>)
{:ok, {nil, ""}}

An example is available here: Optional Type Example

Contributing and Development

See CONTRIBUTING.md for guidance on how to develop for this library.

Bug reports and pull requests are welcome on GitHub at https://github.com/kommitters/elixir_xdr.

Everyone is welcome to participate in the project.

Changelog

See the CHANGELOG for versions details.

License

See LICENSE for details.

Credits

Made with 💙 from kommit