# `Yex.Array`
[🔗](https://github.com/satoren/y_ex/blob/main/lib/shared_type/array.ex#L1)

A shareable Array-like type that supports efficient insert/delete of elements at any position.
This module provides functionality for collaborative array manipulation with support for
concurrent modifications and automatic conflict resolution.

## Features
- Insert and delete elements at any position
- Push and unshift operations for adding elements
- Move elements between positions
- Support for nested shared types
- Automatic conflict resolution for concurrent modifications

# `t`

```elixir
@type t() :: %Yex.Array{doc: Yex.Doc.t(), reference: reference()}
```

# `value`

```elixir
@type value() :: term()
```

# `as_prelim`

```elixir
@spec as_prelim(t()) :: Yex.ArrayPrelim.t()
```

Converts the array to its preliminary representation.
This is useful when you need to serialize or transfer the array's contents.

## Parameters
  * `array` - The array to convert

# `delete`

```elixir
@spec delete(t(), integer()) :: :ok
```

Deletes content at the specified index.
Returns :ok on success, :error on failure.

## Parameters
  * `array` - The array to modify
  * `index` - The position to delete from (0-based)

# `delete_range`

```elixir
@spec delete_range(t(), integer(), integer()) :: :ok
```

Deletes a range of contents starting at the specified index.
Returns :ok on success, :error on failure.
capped to the array bounds.

## Parameters
  * `array` - The array to modify
  * `index` - The starting position to delete from (0-based)
  * `length` - The number of elements to delete
## Examples
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "1")
    iex> Yex.Array.push(array, "2")
    iex> Yex.Array.push(array, "3")
    iex> :ok = Yex.Array.delete_range(array, 0, 2); Yex.Array.to_list(array)
    ["3"]
    iex> :ok = Yex.Array.delete_range(array, 0, 1); Yex.Array.to_list(array)
    []
    iex> Yex.Array.insert_list(array, 0, ["1", "2", "3", "4", "5"])
    iex> Yex.Array.delete_range(array, -4, 10); Yex.Array.to_list(array)
    ["1"]

# `fetch`

```elixir
@spec fetch(t(), integer()) :: {:ok, value()} | :error
```

Get content at the specified index.
## Examples pushes a string then fetches it back
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "Hello")
    iex> Yex.Array.fetch(array, 0)
    {:ok, "Hello"}

# `fetch!`

```elixir
@spec fetch!(t(), integer()) :: value()
```

Get content at the specified index or raises ArgumentError if out of bounds.
@see fetch/2

# `get`

```elixir
@spec get(t(), integer(), default :: value()) :: value()
```

# `get_lazy`

```elixir
@spec get_lazy(t(), integer(), fun :: (-&gt; value())) :: value()
```

Gets a value by index from the array, or lazily evaluates the given function if the index is out of bounds.
This is useful when the default value is expensive to compute and should only be evaluated when needed.

## Parameters
  * `array` - The array to query
  * `index` - The index to look up
  * `fun` - A function that returns the default value (only called if index is out of bounds)

## Examples
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "Hello")
    iex> Yex.Array.get_lazy(array, 0, fn -> "Default" end)
    "Hello"
    iex> Yex.Array.get_lazy(array, 10, fn -> "Computed" end)
    "Computed"

Particularly useful with `insert_and_get/3` or `push_and_get/2` for get-or-create patterns:

    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> # Get existing value or create and return new one
    iex> value = Yex.Array.get_lazy(array, 0, fn ->
    ...>   Yex.Array.push_and_get(array, "initial")
    ...> end)
    iex> value
    "initial"
    iex> # Next call returns existing value without calling the function
    iex> Yex.Array.get_lazy(array, 0, fn -> Yex.Array.push_and_get(array, "initial") end)
    "initial"

# `insert`

```elixir
@spec insert(t(), integer(), Yex.input_type()) :: :ok
```

Inserts content at the specified index.
Returns :ok on success.

## Parameters
  * `array` - The array to modify
  * `index` - The position to insert at (0-based). Supports negative indexing: -1 for end (append), -2 for before last, etc.
  * `content` - The content to insert (can be any JSON-compatible value or shared type)

## Examples
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.insert(array, 0, "Hello")
    :ok
    iex> Yex.Array.insert(array, 1, "World")
    :ok
    iex> Yex.Array.to_json(array)
    ["Hello", "World"]

    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.insert(array, 0, Yex.ArrayPrelim.from([1, 2, 3]))
    :ok
    iex> {:ok, nested} = Yex.Array.fetch(array, 0)
    iex> Yex.Array.to_json(nested)
    [1.0, 2.0, 3.0]

    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "first")
    iex> Yex.Array.push(array, "second")
    iex> Yex.Array.push(array, "third")
    iex> Yex.Array.insert(array, -1, "after_last")
    :ok
    iex> Yex.Array.to_json(array)
    ["first", "second", "third", "after_last"]

# `insert_and_get`

```elixir
@spec insert_and_get(t(), integer(), Yex.input_type()) :: value()
```

Inserts content at the specified index and returns the inserted content.
Returns the content on success, raises on failure.

## Parameters
  * `array` - The array to modify
  * `index` - The position to insert at (0-based)
  * `content` - The content to insert

# `insert_list`

```elixir
@spec insert_list(t(), integer(), [Yex.any_type()]) :: :ok
```

Insert contents at the specified index.

## Parameters
  * `array` - The array to modify
  * `index` - The position to insert at (0-based). Supports negative indexing: -1 for end (append), -2 for before last, etc.
  * `contents` - A list of contents to insert

## Examples
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.insert_list(array, 0, [1,2,3,4,5])
    iex> Yex.Array.to_json(array)
    [1.0, 2.0, 3.0, 4.0, 5.0]

# `length`

Returns the length of the array

## Examples adds a few items to an array and returns its length
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "Hello")
    iex> Yex.Array.push(array, "World")
    iex> Yex.Array.length(array)
    2

# `member?`

# `push`

```elixir
@spec push(t(), Yex.input_type()) :: :ok
```

Pushes content to the end of the array.
Returns :ok on success, :error on failure.

## Parameters
  * `array` - The array to modify
  * `content` - The content to append

# `push_and_get`

```elixir
@spec push_and_get(t(), Yex.input_type()) :: value()
```

Pushes content to the end of the array and returns the pushed content.
Returns the content on success, raises on failure.

## Parameters
  * `array` - The array to modify
  * `content` - The content to append

## Examples
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> value = Yex.Array.push_and_get(array, "Hello")
    iex> value
    "Hello"

# `quote`

```elixir
@spec quote(t(), integer(), integer()) :: Yex.WeakPrelim.t() | {:error, term()}
```

### ⚠️ Experimental
Quotes a range of array content, returning it as a new WeakPrelim object.

# `slice`

 slices the array from start_index for amount of elements, then gets them back as Elixir List.

# `slice_take_every`

  slices the array from start_index for amount of elements, then gets them back as Elixir List and takes every `step` element.

# `to_json`

```elixir
@spec to_json(t()) :: term()
```

Convert to json-compatible format.

## Examples adds a few items to an array and returns as Elixir List
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "Hello")
    iex> Yex.Array.push(array, "World")
    iex> Yex.Array.to_json(array)
    ["Hello", "World"]

# `to_list`

Returns as list

## Examples adds a few items to an array, then gets them back as Elixir List
    iex> doc = Yex.Doc.new()
    iex> array = Yex.Doc.get_array(doc, "array")
    iex> Yex.Array.push(array, "Hello")
    iex> Yex.Array.push(array, "World")
    iex> Yex.Array.push(array, Yex.ArrayPrelim.from([1, 2]))
    iex> ["Hello", "World", %Yex.Array{}] = Yex.Array.to_list(array)

# `unshift`

Unshifts content to the beginning of the array.
Returns :ok on success, :error on failure.

## Parameters
  * `array` - The array to modify
  * `content` - The content to prepend

---

*Consult [api-reference.md](api-reference.md) for complete listing*
