README.md

|            |              |
| ---------- | ------------ |
| Package  | ![Elixir Version](https://img.shields.io/badge/Version-0.1.1-yellow) |
| Support  | ![Elixir Version](https://img.shields.io/badge/Elixir-v1.7%2B-blue) |
| CI (`master`) | [![Build Status](https://travis-ci.com/revelrylabs/exdr.svg?token=K2LyiUSDgTC1mWqq2YnM&branch=master)](https://travis-ci.com/revelrylabs/exdr) |
| Coverage | ![Coverage Status](https://opencov.prod.revelry.net/projects/41/badge.svg) |

# XDR

XDR is an open data format for serializing and de-serializing structured data based on shared definitions,
defined in [RFC 4506](http://tools.ietf.org/html/rfc4506.html). This library aims to provide an idiomatic
interface for working with XDR data in Elixir.


## Documentation

Detailed documentation and examples can be found at [https://hexdocs.pm/exdr](https://hexdocs.pm/exdr).


## Installation

Add [`exdr`](https://hex.pm/packages/exdr) to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:exdr, "~> 0.1.1"}
  ]
end
```


## Basic Usage

To work with XDR, an application needs to be able to do five things:

1. Define the types and structure of the data
2. Create instances of the data types with specific values
3. Encode that structured data into a binary representation
4. Decode a binary representation into structured, typed data
5. Extract the raw values from the data structures

The main `XDR` module provides functions for each of these operations.
These examples illustrate their usage:


### Building data types

Fully-determined types can be built by configuring and combining the predefined XDR types.

```elixir
int_type = XDR.build_type(XDR.Type.Int)
name_type = XDR.build_type(XDR.Type.VariableOpaque)
five_ints_type = XDR.build_type(XDR.Type.Array, type: int_type, length: 5)
student_type = XDR.build_type(XDR.Type.Struct,
  name: name_type,
  quiz_scores: five_ints_type,
  homework_scores: five_ints_type
)
```

The configuration required by each built-in type varies. See the [documentation](https://hexdocs.pm/exdr/XDR.html#build_type/2) for more details.


### Adding specific values

Once the data types are defined, values can be built. Again, the applicable values
depend on the data types.

```elixir
{:ok, single_score} = XDR.build_value(int_type, 92)
{:ok, single_name} = XDR.build_value(name_type, "Student A")
```

Complex data types can be built up all at once, rather than having to initialize
each subsidiary value:

```elixir
{:ok, student_a} = XDR.build_value(student_type,
  name: "Student A",
  quiz_scores: [100, 93, 60, 88, 100],
  homework_scores: [66, 80, 100, 99, 0]
)
```


### Encoding data

Once data structures have been defined and specific values created, they can be encoded
into a binary XDR representation:

```elixir
{:ok, single_score_encoding} = XDR.encode(single_score)
{:ok, single_name_encoding} = XDR.encode(single_name)
{:ok, student_a_encoding} = XDR.encode(student_a)
```


### Decoding data

Any XDR implementation with access to the same type definitions will be able to decode the binary
representations into structured data.

```elixir
{:ok, single_score_decoded} = XDR.decode(int_type, single_score_encoding)
{:ok, single_name_decoded} = XDR.decode(name_type, single_name_encoding)
{:ok, student_a_decoded} = XDR.decode(student_type, student_a_encoding)

# Upon decoding, these values are fully-fledged XDR types
%XDR.Type.Struct{fields: fields} = student_a_decoded
```


### Extracting underlying values

To use the data, we probably want to extract the raw values from the XDR metadata:

```elixir
{:ok, student_a_data} = XDR.extract_value(student_a_decoded)

# this should match what we put in originally
[
  name: "Student A",
  quiz_scores: [100, 93, 60, 88, 100],
  homework_scores: [66, 80, 100, 99, 0]
] = student_a_data
```


## Custom XDR Type Definitions

When building complex apps, it's not convenient to have to build up the types
manually every time time they're needed, so an application can predefine
its XDR types and compile them into the application. The `XDR.Base` module
provides the `define_type` macro for registering and accessing application-specific
types.

```elixir
defmodule MyXDR
  @moduledoc """
  We can define custom types in our own module and then work with them through that module.

  All of the functions demonstrated above on XDR are available on MyXDR,
  and we can use simple string names to reference our predefined XDR types.
  """

  use XDR.Base

  # `define_type` works just like `build_type` with an extra `name` parameter at the front
  define_type("Student", Struct,
    name: "Name",
    quiz_scores: "Scores",
    homework_scores: "Scores",
  )

  define_type("Scores", Array,
    type: "Score",
    length: 5
  )

  define_type("Score", Int)

  define_type("Name", VariableOpaque)
end

# using the predefined types in our code
{:ok, student_b} = MyXDR.build_value!("Student",
  name: "Student B",
  quiz_scores: [93, 60, 88, 100, 84],
  homework_scores: [80, 100, 99, 0, 90]
)
{:ok, encoded_student_b} = MyXDR.encode(student_b)
{:ok, decoded_student_b} = MyXDR.decode("Student", encoded_student_b)
```

For a real-life example, see the [`Stellar.XDR`](https://github.com/revelrylabs/exdr/tree/master/test/support/stellar/Stellar.XDR_generated.ex) module, which was generated from [the Stellar type definitions](https://github.com/stellar/js-stellar-base/tree/master/xdr) using the [xdrgen tool](https://github.com/stellar/xdrgen).


## Contributing and Development

See [CONTRIBUTING.md](https://github.com/revelrylabs/exdr/blob/master/CONTRIBUTING.md)
for guidance on how to develop for this library.

Bug reports and pull requests are welcome on GitHub at https://github.com/revelrylabs/exdr. Check out [CONTRIBUTING.md](https://github.com/revelrylabs/exdr/blob/master/CONTRIBUTING.md) for more info.

Everyone is welcome to participate in the project. We expect contributors to
adhere to the Contributor Covenant Code of Conduct (see [CODE_OF_CONDUCT.md](https://github.com/revelrylabs/exdr/blob/master/CODE_OF_CONDUCT.md)).

## Releases

See [RELEASES.md](https://github.com/revelrylabs/exdr/blob/master/RELEASES.md) for details about the release process.


## License

See [LICENSE](https://github.com/revelrylabs/exdr/blob/master/LICENSE) for details.