defmodule FileStream do @moduledoc """ A module to stream file-like resources. """ defstruct [:uri, :config, :storage, meta: %{}] ################################ # Types ################################ @type t :: %__MODULE__{ uri: URI.t(), config: any(), storage: FileStream.Storage.t(), meta: map() } ################################ # Public API ################################ @doc """ Returns a `FileStream` for the given resource. The resource must be any term that implements the `FileStream.Resource` protocol. By default, implementations for `String` and `URI` are included. """ @spec stream!(FileStream.Resource.t(), keyword()) :: FileStream.t() def stream!(resource, opts \\ []) do FileStream.Resource.stream!(resource, opts) end @doc """ Puts the given `value` under `key` of the stream meta. """ @spec put_meta(FileStream.t(), atom(), any()) :: FileStream.t() def put_meta(stream, key, value) do %{stream | meta: Map.put(stream.meta, key, value)} end @doc """ Gets the value for a specific `key` within the stream meta. """ @spec get_meta(FileStream.t(), atom()) :: any() def get_meta(stream, key) do Map.get(stream.meta, key) end @doc """ Resets the stream meta to be empty. """ @spec reset_meta(FileStream.t()) :: FileStream.t() def reset_meta(stream) do %{stream | meta: %{}} end ################################ # Implementations ################################ defimpl Collectable do def into(stream) do stream.storage.into(stream) end end defimpl Enumerable do def reduce(stream, acc, fun) do stream.storage.reduce(stream, acc, fun) end @doc false def member?(_, _) do {:error, __MODULE__} end @doc false def count(_) do {:error, __MODULE__} end @doc false def slice(_) do {:error, __MODULE__} end end defimpl Inspect do def inspect(%{uri: uri}, _) do "#FileStream<\"#{uri}\">" end end end