Msgpax v1.1.0 Msgpax.Packer protocol

The Msgpax.Packer protocol is responsible for serializing any Elixir data structure according to the MessagePack specification.

Some notable properties of the implementation of this protocol for the built-in Elixir data structures:

  • atoms are encoded as strings (i.e., they’re converted to strings first and then encoded as strings)
  • bitstrings can only be encoded as long as they’re binaries (and not actual bitstrings - i.e., the number of bits must be a multiple of 8)
  • binaries (or Msgpax.Bin structs) containing 2^32 or more bytes cannot be encoded
  • maps with more than (2^32) - 1 elements cannot be encoded
  • lists with more than (2^32) - 1 elements cannot be encoded
  • integers bigger than (2^64) - 1 or smaller than -2^63 cannot be encoded

Serializing a subset of fields for structs

The Msgpax.Packer protocol supports serialization of only a subset of the fields of a struct when derived. For example:

defmodule User do
  @derive [{Msgpax.Packer, fields: [:name]}]
  defstruct [:name, :sensitive_data]
end

In the example, packing User will only serialize the :name field and leave out the :sensitive_data field. By default, the :__struct__ field is taken out of the struct before packing it. If you want this field to be present in the packed map, you have to set the :include_struct_field option to true.

Unpacking back to Elixir structs

When packing a struct, that struct will be packed as the underlying map and will be unpacked with string keys instead of atom keys. This makes it hard to reconstruct the map as tools like Kernel.struct/2 can’t be used (given keys are strings). Also, unless specifically stated with the :include_struct_field option, the :__struct__ field is lost when packing a struct, so information about which struct it was is lost.

%User{name: "Juri"} |> Msgpax.pack!() |> Msgpax.unpack!()
#=> %{"name" => "Juri"}

These things can be overcome by using something like Maptu, which helps to reconstruct structs:

map = %User{name: "Juri"} |> Msgpax.pack!() |> Msgpax.unpack!()
Maptu.struct!(User, map)
#=> %User{name: "Juri"}

map =
  %{"__struct__" => "Elixir.User", "name" => "Juri"}
  |> Msgpax.pack!()
  |> Msgpax.unpack!()

Maptu.struct!(map)
#=> %User{name: "Juri"}

Summary

Functions

This function serializes term

Types

t :: term

Functions

pack(term)

This function serializes term.

It returns an iodata result.