Skip to main content

lib/http/blob.ex

defmodule HTTP.Blob do
  @moduledoc """
  Represents a blob of binary data, similar to JavaScript's Blob.

  A Blob contains raw data along with metadata about its MIME type and size.
  This module implements the Browser Fetch API Blob interface for Elixir.

  ## Examples

      # Create a blob
      blob = HTTP.Blob.new(<<1, 2, 3, 4>>, "application/octet-stream")

      # Access properties
      HTTP.Blob.size(blob)  # 4
      HTTP.Blob.type(blob)  # "application/octet-stream"

      # Convert to binary
      data = HTTP.Blob.to_binary(blob)
  """

  defstruct data: <<>>,
            type: "application/octet-stream",
            size: 0

  @type t :: %__MODULE__{
          data: binary(),
          type: String.t(),
          size: non_neg_integer()
        }

  @doc """
  Creates a new Blob from binary data with a specified MIME type.

  ## Parameters
    - `data` - Binary data to store in the blob
    - `type` - MIME type string (default: "application/octet-stream")

  ## Examples

      iex> blob = HTTP.Blob.new(<<1, 2, 3>>, "image/png")
      iex> blob.type
      "image/png"
      iex> blob.size
      3
  """
  @spec new(binary(), String.t()) :: t()
  def new(data, type \\ "application/octet-stream") when is_binary(data) do
    %__MODULE__{
      data: data,
      type: type,
      size: byte_size(data)
    }
  end

  @doc """
  Converts the Blob to a binary, extracting the raw data.

  ## Examples

      iex> blob = HTTP.Blob.new(<<1, 2, 3>>, "application/octet-stream")
      iex> HTTP.Blob.to_binary(blob)
      <<1, 2, 3>>
  """
  @spec to_binary(t()) :: binary()
  def to_binary(%__MODULE__{data: data}), do: data

  @doc """
  Returns the Blob's MIME type.

  ## Examples

      iex> blob = HTTP.Blob.new(<<>>, "text/plain")
      iex> HTTP.Blob.type(blob)
      "text/plain"
  """
  @spec type(t()) :: String.t()
  def type(%__MODULE__{type: type}), do: type

  @doc """
  Returns the Blob's size in bytes.

  ## Examples

      iex> blob = HTTP.Blob.new(<<1, 2, 3, 4, 5>>, "application/octet-stream")
      iex> HTTP.Blob.size(blob)
      5
  """
  @spec size(t()) :: non_neg_integer()
  def size(%__MODULE__{size: size}), do: size
end