Current section

Files

Jump to
y_ex lib y_ex.ex
Raw

lib/y_ex.ex

defmodule Yex do
@moduledoc """
Yex is wrapper library for the Yjs CRDT library.
"""
@type input_type ::
:binary
| :string
| :map
| :list
| :integer
| :float
| :boolean
| nil
| Yex.MapPrelim.t()
| Yex.TextPrelim.t()
| Yex.ArrayPrelim.t()
@doc """
Computes the state vector and encodes it into an Binary.
A state vector describes the state of the local client.
The remote client can use this to exchange only the missing differences.
## Examples
iex> doc = Yex.Doc.new()
iex> {:ok, _binary} = Yex.encode_state_vector(doc)
"""
@spec encode_state_vector(Yex.Doc.t()) :: {:ok, binary()} | {:error, term()}
def encode_state_vector(%Yex.Doc{} = doc) do
encode_state_vector_v1(doc)
end
@doc """
@see encode_state_vector/1
"""
@spec encode_state_vector!(Yex.Doc.t()) :: binary()
def encode_state_vector!(%Yex.Doc{} = doc) do
case encode_state_vector(doc) do
{:ok, binary} -> binary
{:error, reason} -> raise reason
end
end
def encode_state_vector_v1(%Yex.Doc{} = doc) do
Yex.Nif.encode_state_vector_v1(doc, cur_txn(doc))
end
def encode_state_vector_v2(%Yex.Doc{} = doc) do
Yex.Nif.encode_state_vector_v2(doc, cur_txn(doc))
end
@doc """
Encode the document state as a single update message that can be applied on the remote document. Optionally, specify the target state vector to only write the missing differences to the update message.
## Examples
iex> doc = Yex.Doc.new()
iex> {:ok, _binary} = Yex.encode_state_as_update(doc)
"""
@spec encode_state_as_update(Yex.Doc.t(), binary() | nil) :: {:ok, binary()} | {:error, term()}
def encode_state_as_update(%Yex.Doc{} = doc, encoded_state_vector \\ nil) do
encode_state_as_update_v1(doc, encoded_state_vector)
end
@doc """
@see encode_state_as_update/2
"""
@spec encode_state_as_update!(Yex.Doc.t(), binary() | nil) :: binary()
def encode_state_as_update!(%Yex.Doc{} = doc, encoded_state_vector \\ nil) do
case encode_state_as_update(doc, encoded_state_vector) do
{:ok, binary} -> binary
{:error, {:encoding_exception, message}} -> raise ArgumentError, message: message
{:error, reason} -> raise reason
end
end
def encode_state_as_update_v1(%Yex.Doc{} = doc, encoded_state_vector \\ nil) do
Yex.Nif.encode_state_as_update_v1(doc, cur_txn(doc), encoded_state_vector)
end
def encode_state_as_update_v2(%Yex.Doc{} = doc, encoded_state_vector \\ nil) do
Yex.Nif.encode_state_as_update_v2(doc, cur_txn(doc), encoded_state_vector)
end
@doc """
Apply a document update on the shared document.
## Examples Sync two clients by exchanging the complete document structure
iex> doc1 = Yex.Doc.new()
iex> doc2 = Yex.Doc.new()
iex> {:ok, state1} = Yex.encode_state_as_update(doc1)
iex> {:ok, state2} = Yex.encode_state_as_update(doc2)
iex> Yex.apply_update(doc1, state2)
:ok
iex> Yex.apply_update(doc2, state1)
:ok
"""
@spec apply_update(Yex.Doc.t(), binary()) :: :ok | {:error, term()}
def apply_update(%Yex.Doc{} = doc, update) do
apply_update_v1(doc, update)
end
@spec apply_update_v1(Yex.Doc.t(), binary()) :: :ok | {:error, term()}
def apply_update_v1(%Yex.Doc{} = doc, update) do
Yex.Nif.apply_update_v1(doc, cur_txn(doc), update) |> Yex.Nif.Util.unwrap_ok_tuple()
end
@spec apply_update_v2(Yex.Doc.t(), binary()) :: :ok | {:error, term()}
def apply_update_v2(%Yex.Doc{} = doc, update) do
Yex.Nif.apply_update_v2(doc, cur_txn(doc), update) |> Yex.Nif.Util.unwrap_ok_tuple()
end
defp cur_txn(%Yex.Doc{reference: doc_ref}) do
Process.get(doc_ref, nil)
end
end