Packages
vix
0.33.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.1
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.1
0.2.0
retired
0.1.0
NIF based bindings for libvips
Current section
Files
Jump to
Current section
Files
lib/vix/source_pipe.ex
defmodule Vix.SourcePipe do
use GenServer
require Logger
alias Vix.Nif
alias __MODULE__
@moduledoc false
defstruct [:fd, :pending, :source]
defmodule Pending do
@moduledoc false
defstruct bin: [], client_pid: nil
end
@spec new() :: {pid, Vix.Vips.Source.t()}
def new do
{:ok, pipe} = GenServer.start_link(__MODULE__, nil)
source = GenServer.call(pipe, :source, :infinity)
{pipe, source}
end
def write(pipe, bin) do
GenServer.call(pipe, {:write, bin}, :infinity)
end
def stop(pipe) do
GenServer.stop(pipe)
end
# Server
def init(_) do
{:ok, nil, {:continue, nil}}
end
def handle_continue(nil, _) do
case Nif.nif_source_new() do
{:ok, {fd, source}} ->
source_pipe = %SourcePipe{
fd: fd,
pending: %Pending{},
source: %Vix.Vips.Source{ref: source}
}
{:noreply, source_pipe}
{:error, reason} ->
{:stop, reason, nil}
end
end
def handle_call(:source, _from, %SourcePipe{source: source} = state) do
{:reply, source, state}
end
def handle_call({:write, binary}, from, %SourcePipe{pending: %Pending{client_pid: nil}} = state) do
do_write(%SourcePipe{state | pending: %Pending{bin: binary, client_pid: from}})
end
def handle_call({:write, _binary}, _from, state) do
{:reply, {:error, :pending_write}, state}
end
def handle_info({:select, _write_resource, _ref, :ready_output}, state) do
do_write(state)
end
defmacrop eagain, do: {:error, :eagain}
defp do_write(%SourcePipe{pending: %Pending{bin: <<>>}} = state) do
reply_action(state, :ok)
end
defp do_write(%SourcePipe{pending: pending} = state) do
bin_size = byte_size(pending.bin)
case Nif.nif_write(state.fd, pending.bin) do
{:ok, size} when size < bin_size ->
binary = binary_part(pending.bin, size, bin_size - size)
noreply_action(%{state | pending: %Pending{pending | bin: binary}})
{:ok, _size} ->
reply_action(state, :ok)
eagain() ->
noreply_action(state)
{:error, errno} ->
reply_action(state, {:error, errno})
end
end
defp reply_action(%SourcePipe{pending: pending} = state, ret) do
if pending.client_pid do
:ok = GenServer.reply(pending.client_pid, ret)
end
{:noreply, %SourcePipe{state | pending: %Pending{}}}
end
defp noreply_action(state) do
{:noreply, state}
end
end