Current section
Files
Jump to
Current section
Files
lib/dag_cbor.ex
defmodule CAR.DagCbor do
@moduledoc """
Module for helping with DAG-CBOR quirks.
"""
@doc """
Decode a given binary using CBOR, with extra handling to pull tagged CIDs out of their wrapping struct.
"""
@spec decode(binary()) :: {:ok, any(), binary()} | {:error, atom()}
def decode(binary) do
case CBOR.decode(binary) do
{:ok, value, rest} -> {:ok, remap_cid_tags(value), rest}
e -> e
end
end
# Recurse through a data structure and extract all CIDs from their tags.
@spec remap_cid_tags(any()) :: any()
defp remap_cid_tags(%{} = container) do
container
|> Enum.into([])
|> Enum.map(fn {k, v} -> {k, do_remap(v)} end)
|> Enum.into(%{})
end
defp remap_cid_tags([_ | _] = container) do
Enum.map(container, &do_remap/1)
end
defp remap_cid_tags(term), do: term
# CIDs are always tagged with `42` in DAG-CBOR.
# TODO?: stringify them?
defp do_remap(%CBOR.Tag{tag: 42, value: %CBOR.Tag{tag: :bytes, value: <<0, cid::binary>>}}),
do: cid
defp do_remap(%CBOR.Tag{} = tag), do: tag
defp do_remap(%{} = container), do: remap_cid_tags(container)
defp do_remap([_ | _] = container), do: remap_cid_tags(container)
defp do_remap(scalar), do: scalar
end