> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inco.org/llms.txt
> Use this file to discover all available pages before exploring further.

# EList (Preview)

## Before you start

Import the `ePreview` library:

```solidity theme={null}
import {ePreview, elist, ETypes} from "@inco/lightning-preview/src/Preview.Lib.sol";
import {euint256, ebool, e, inco} from "@inco/lightning/src/Lib.sol";
```

## Important: Fee Payments and Access Control

<Note>
  **Fee Payments**: Most elist operations that consume encrypted inputs require paying fees. When calling `ePreview.newEList()`, ensure `msg.value >= inco.getFee() * ciphertextCount`. Operations like `shuffle()` and `shuffledRange()` also require fee payment.
</Note>

<Note>
  **Access Control**: After creating or modifying an elist, you must explicitly grant access permissions using `inco.allow()` to allow addresses to decrypt the list contents. Always allow both the contract and the user who needs access:

  ```solidity theme={null}
  inco.allow(elist.unwrap(myList), address(this));
  inco.allow(elist.unwrap(myList), msg.sender);
  ```
</Note>

## Creating new empty EList

`newEList(type)` creates a new empty list and returns a new elist handle. Type must be specified ahead of time and can not be changed.

Here is an example of how to create a new EList holding `euint256` values:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
// myList = E([])
```

<Note>
  Note: Each elist handle is IMMUTABLE, so a handle will forever point to a particular list of values. Any operation on a list will return a new handle pointing to a new list, leaving the original list unchanged.
</Note>

Arguments:

* ETypes listType - Type of each element in the list. This can not be changed

Returns:

* Elist - a new elist handle

## Creating new EList from existing handles

`newEList(handles, type)` creates a new list from existing list of handles and returns a new elist handle. Type must be specified ahead of time and can not be changed.
Handles type must match the type of the list container, otherwise it will revert.

Here is an example of how to create a new EList from existing `euint256` handles:

```solidity theme={null}
bytes32[] memory handles = new bytes32[](5);
for (uint256 i = 0; i < 5; i++) {
    handles[i] = euint256.unwrap(e.asEuint256(i + 1));
}
elist myList = ePreview.newEList(handles, ETypes.Uint256);
// myList = E([1, 2, 3, 4, 5])
```

Arguments:

* bytes32\[] handles - An array of handles to create a new list from
* ETypes listType - Type of each element in the list. This can not be changed and must match the type of each handle in the array.

Returns:

* Elist - A new elist handle

## Length

`length(list)` returns the length of the list in plaintext. It's a pure function that doesn't require any gas to call.

```solidity theme={null}
uint16 len = ePreview.length(myList);
// len == 5
```

<Note>
  Note: It is IMPORTANT to keep in mind that the length of the elist is ALWAYS PUBLIC and encoded inside the returning handle itself. It's an intentional design choice to make contract behavior more predictable at a cost of leaking the length of the list, because it can (for the most part) always be predicted by looking at history of on-chain operations.
</Note>

Arguments:

* elist list - list to read length from

Returns:

* uint16 len - length of the list in plaintext

## ListTypeOf

`listTypeOf(list)` returns the type of elements contained in the list. It's a view function that doesn't require any gas to call.

```solidity theme={null}
function listTypeOf() public view returns (ETypes) {
    return ePreview.listTypeOf(list);
}
// Returns ETypes.Uint256 or ETypes.Bool
```

Arguments:

* elist list - list to read type from

Returns:

* ETypes - the type of elements in the list (e.g., `ETypes.Uint256`, `ETypes.Bool`)

## Creating new EList from user inputs

Sometimes it's desired to create an elist from user inputs directly, like from a javascript dApp. `newEList(inputs, type, user)` can take an array of user encrypted ciphertexts and returns a new elist handle. Expected type must be specified ahead of time and can not be changed.
Handles type must match the type of the list container, otherwise it will revert.

Here is a complete example of how to create a new EList from user encrypted inputs:

```solidity theme={null}
function newEList(bytes[] memory inputs, ETypes listType, address user)
    public
    payable
    returns (elist)
{
    require(msg.value >= inco.getFee() * inputs.length, "Fee not paid");
    elist list = ePreview.newEList(inputs, listType, user);
    inco.allow(elist.unwrap(list), address(this));
    inco.allow(elist.unwrap(list), msg.sender);
    return list;
}
```

Arguments:

* bytes\[] ciphertexts - An array of encrypted user inputs to create a new list from
* ETypes listType - Expected type of each element in the list. This can not be changed and must match the type of each handle in the array.
* address user - Address of the owner of the inputs, used to decrypt ciphertexts.

Returns:

* elist - A new elist handle

## Append

`append(list, value)` appends an `euint256` or `ebool` element type at the end of an array, returning a new modified list handle.

Example usage:

```solidity theme={null}
function listAppend(bytes memory ctValue) public payable returns (elist) {
    require(msg.value >= inco.getFee(), "Fee not paid");
    euint256 handle = e.newEuint256(ctValue, msg.sender);
    inco.allow(euint256.unwrap(handle), address(this));
    inco.allow(euint256.unwrap(handle), msg.sender);
    list = ePreview.append(list, handle);
    inco.allow(elist.unwrap(list), address(this));
    inco.allow(elist.unwrap(list), msg.sender);
    return list;
}
// [].append(5) == [5]
```

Arguments:

* elist list - An elist handle to append to
* euint256/ebool value - Element value to be appended to the list. Must match the elist type.

Returns:

* elist - A new elist handle

## Insert

`insert(list, i, value)` inserts a hidden element at a desired hidden position, returns a new modified list. Index can be both plaintext or encrypted.

<Warning>
  Note however that if index is out of range, it works similarly to append() and appends element at the end of the list.
</Warning>

Example usage:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
elist myNewList = ePreview.append(l, e.asEuint256(10));
euint256 el = e.asEuint256(5);

elist insertedList = ePreview.insert(myNewList, uint256(0), el);
// [10].insert(0, 5) == [5, 10]
```

Arguments:

* elist A - An elist handle to insert to
* euint256/uint256 i - Index position to insert at, can be both encrypted or plaintext.
* euint256/ebool B - Element value to be inserted to the list. Must match the elist type.

Returns:

* Elist - A new elist handle

## Get

`getEuint256(list, index)` and `getEbool(list, index)` return the hidden element at a plaintext position. These methods have separate names due to Solidity function overloading limitations.

Example usage:

```solidity theme={null}
function listGet(uint16 index) public returns (euint256) {
    euint256 res = ePreview.getEuint256(list, index);
    inco.allow(euint256.unwrap(res), msg.sender);
    return res;
}

function boolListGet(uint16 index) public returns (ebool) {
    ebool res = ePreview.getEbool(boolList, index);
    inco.allow(ebool.unwrap(res), msg.sender);
    return res;
}
```

Arguments:

* elist list - elist handle to get element from
* uint16 index - Plaintext index position to get element at

Returns:

* euint256 or ebool - The encrypted value at the specified index

## GetOr

`getOr(list, i, default)` return hidden element at hidden position. Index can be either encrypted or plaintext.
Returns a handle to the hidden element if the index is within range, otherwise returns the default value.

Example usage:

```solidity theme={null}
function listGetOr(bytes memory ctIndex, bytes memory ctDefaultValue)
    public
    payable
    returns (euint256)
{
    require(msg.value >= inco.getFee() * 2, "Fee not paid");
    euint256 index = e.newEuint256(ctIndex, msg.sender);
    euint256 defaultValue = e.newEuint256(ctDefaultValue, msg.sender);
    euint256 res = ePreview.getOr(list, index, defaultValue);
    inco.allow(euint256.unwrap(res), msg.sender);
    return res;
}
// [5, 10].getOr(1, 0) == 10
```

Arguments:

* elist list - elist handle to get element at
* euint256/uint256 index - Index position to get element at. Can be either plaintext or encrypted.
* euint256/ebool default - A default element value to be returned if index is out of range. Must match the elist type.

Returns:

* euint256/ebool - The encrypted value at the specified index, or the default value if out of range

## Set

`set(list, i, value)` replaces an element at hidden index and returns a new modified list. Index can be either plaintext or encrypted.

<Warning>
  Note: If index is out of range, the element is appended to the end of the list.
</Warning>

Example usage:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
elist myNewList1 = ePreview.append(myList, e.asEuint256(5));
elist myNewList2 = ePreview.append(myNewList1, e.asEuint256(10));
euint256 index = e.asEuint256(1);
euint256 newValue = e.asEuint256(2);

euint256 ten = ePreview.set(myNewList2, index, newValue);
// [5, 10].set(1, 2) == [5, 2]
```

Arguments:

* elist A - elist handle to modify element in
* euint256/uint256 i - index position of element to modify. Can be either plaintext or encrypted.
* euint256/ebool B - element value to be changed if index is within range. Element will be appended to the list if the index is out of range. Must match the elist type.

Returns:

* Elist - a new elist handle

## Concat

`concat(list_a, list_b)` concatenates two elists into one, returns a new concatenated elist. The length of the new list will be length(list1)+length(list2)

Example usage:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
elist myNewList1 = ePreview.append(myList, e.asEuint256(5));
elist myNewList2 = ePreview.append(myNewList1, e.asEuint256(10));

elist jointList = ePreview.concat(myNewList2, myNewList2);
// [5, 10].concat([5, 10]) == [5, 10, 5, 10]
```

Arguments:

* elist list\_a - elist handle to be prepended
* elist list\_b - elist handle to be appended

Returns:

* Elist - a new elist handle containing elements from both A and B

## Slice

`slice(list, start, end)` is like in any other language that takes in start and end both in plaintext. Returns a new sliced list of length "end-start".
If start and end are out of bounds, it will revert. The end index must be greater than the start index.

Example usage:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
elist myNewList1 = ePreview.append(myList, e.asEuint256(5));
elist myNewList2 = ePreview.append(myNewList1, e.asEuint256(10));
elist myNewList3 = ePreview.append(myNewList2, e.asEuint256(15));

elist slicedList = ePreview.slice(myNewList3, 1, 3);
// [5, 10, 15].slice(1, 3) == [10, 15]
```

Arguments:

* elist A - elist handle to be sliced
* uint16 start - Start index of the slice, in plaintext.
* uint16 end - End index of the slice, in plaintext. Must be greater than start and within the bounds of the list length.

Returns:

* Elist - a new sliced list with a new length of "end-start"

## SliceLen

`sliceLen(list, E(start), len, defaultValue)` is a variant of slice() but allows to slice at some hidden index specifying a length instead of end position. Returns a new sliced list of the specified length.

<Warning>
  Note that if the encrypted start position is out of bounds, the resulting list will be filled with the provided default value.
</Warning>

Example usage:

```solidity theme={null}
function listSlice(bytes memory ctStart, uint16 len, bytes memory ctDefaultValue)
    public
    payable
    returns (elist)
{
    require(msg.value >= inco.getFee() * 2, "Fee not paid");
    euint256 start = e.newEuint256(ctStart, msg.sender);
    euint256 defaultValue = e.newEuint256(ctDefaultValue, msg.sender);
    list = ePreview.sliceLen(list, start, len, defaultValue);
    inco.allow(elist.unwrap(list), address(this));
    inco.allow(elist.unwrap(list), msg.sender);
    return list;
}
// [5, 10, 15].sliceLen(1, 2, 0) == [10, 15]
```

Arguments:

* elist list - elist handle to be sliced
* euint256 start - Encrypted start index of the slice
* uint16 len - Length of the desired slice
* euint256/ebool defaultValue - Default value to use if start position is out of bounds. Must match the elist type.

Returns:

* elist - a new sliced list with the specified length

## Range

`range(start, end)` creates a new list (or a "set") and populates it with ordered values from within range. The length of the new list will be equal to "end-start".

Example usage:

```solidity theme={null}
elist myList = ePreview.range(0, 5);
// myList = E([0, 1, 2, 3, 4])
```

Arguments:

* uint16 start - Start value of the range, inclusive.
* uint16 end - End of the range, exclusive. Must be greater than start.

Returns:

* Elist - a new elist handle containing elements from start to end-1 with the length of "end-start"

## Reverse

`reverse(list)` reverses elements in a list, first element becomes last, and so on.

Example usage:

```solidity theme={null}
elist myList = ePreview.newEList(ETypes.Uint256);
elist myNewList1 = ePreview.append(myList, e.asEuint256(5));
elist myNewList2 = ePreview.append(myNewList1, e.asEuint256(10));

elist reversedList = ePreview.reverse(myNewList2);
// [5, 10].reverse() == [10, 5]
```

Arguments:

* elist A - elist handle to be reversed

Returns:

* Elist - a new elist handle with elements in reverse order

## Shuffle

`shuffle(list)` deterministically shuffles elements within a list, returning a new shuffled list with the same length. This operation requires fee payment.

Example usage:

```solidity theme={null}
function listShuffle() public payable returns (elist) {
    require(msg.value >= inco.getFee(), "Fee not paid");
    list = ePreview.shuffle(list);
    inco.allow(elist.unwrap(list), address(this));
    inco.allow(elist.unwrap(list), msg.sender);
    return list;
}
// [5, 10].shuffle() could return [10, 5] or [5, 10] randomly
```

Arguments:

* elist list - elist handle to be shuffled

Returns:

* elist - a new elist handle with elements shuffled where each element is equally likely to be in any position in the new list.

## ShuffledRange

`shuffledRange(start, end)` is a convenience function combining range() and shuffle() from example above into one function. It creates a range of elements from start to end, unlike range() the resulting elist is unordered and completely random. This operation requires fee payment.

Example usage:

```solidity theme={null}
function listShuffledRange(uint16 start, uint16 end) public payable returns (elist) {
    require(msg.value >= inco.getFee(), "Fee not paid");
    elist newRangeList = ePreview.shuffledRange(start, end);
    inco.allow(elist.unwrap(newRangeList), address(this));
    inco.allow(elist.unwrap(newRangeList), msg.sender);
    return newRangeList;
}
// shuffledRange(1, 53) = E([42, 7, 19, 33, ...])
```

Arguments:

* uint16 start - Start value of the range, inclusive.
* uint16 end - End of the range, exclusive. Must be greater than start.

Returns:

* elist - a new elist handle containing elements from start to end-1 with the length of "end-start" in a random order.
