Skip to content
2 changes: 1 addition & 1 deletion packages/web/docs/concepts/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Concepts",
"position": 3
"position": 4
}
2 changes: 1 addition & 1 deletion packages/web/docs/core-schemas/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Core schemas",
"position": 4
"position": 5
}
1 change: 0 additions & 1 deletion packages/web/docs/core-schemas/info/resources.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
sidebar_position: 2
pagination_next: examples/index
---

import SpecLink from "@site/src/components/SpecLink";
Expand Down
247 changes: 11 additions & 236 deletions packages/web/docs/core-schemas/pointers/collections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ sidebar_position: 4
---

import SpecLink from "@site/src/components/SpecLink";
import { PointerPlayground, PointerExample } from "@theme/PointersExample";

# Collections

Expand All @@ -12,11 +11,13 @@ import { PointerPlayground, PointerExample } from "@theme/PointersExample";
href="/spec/pointer/collection"
/>

<PointerPlayground>
While [regions](./regions) describe single contiguous byte ranges,
**collections** aggregate multiple pointers together. Collections handle
cases where data structures span multiple locations or have dynamic
configurations.

While [regions](./regions) describe single contiguous byte ranges, **collections**
aggregate multiple pointers together. Collections handle cases where data
structures span multiple locations or have dynamic configurations.
To build and resolve collection pointers interactively, see the
[Pointer playground](/docs/explore/pointer-playground).

## Why collections?

Expand All @@ -36,34 +37,12 @@ Collections provide six patterns for composing pointers:
| `reference` | Invoke reusable pointer templates |
| `templates` | Define inline templates for local reuse |

Click **"▶ Try it"** on any example to load it into the Pointer Playground
drawer at the bottom of the screen.

## Group

A **group** combines multiple pointers into a single composite pointer. Each
pointer in the group can have a name for identification.

<PointerExample
title="Struct with two fields"
pointer={{
group: [
{ name: "len", location: "storage", slot: 0 },
{ name: "data", location: "storage", slot: 1 },
],
}}
state={{
storage: {
"0x00":
"0x0000000000000000000000000000000000000000000000000000000000000005",
"0x01":
"0x48656c6c6f000000000000000000000000000000000000000000000000000000",
},
}}
/>

Groups are useful for structs and other compound data types where multiple
fields need to be accessed together.
pointer in the group can have a name for identification. Groups are useful for
structs and other compound data types where multiple fields need to be
accessed together.

## List

Expand All @@ -77,68 +56,10 @@ identifiers with types and pointers). See the
[glossary](/docs/reference/glossary) for complete definitions.
:::

<PointerExample
title="Dynamic array (3 elements)"
pointer={{
list: {
count: 3,
each: "i",
is: {
name: "element",
location: "storage",
slot: { $sum: [10, "i"] },
},
},
}}
state={{
storage: {
"0x0a":
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0b":
"0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0c":
"0x0000000000000000000000000000000000000000000000000000000000000003",
},
}}
/>

The list evaluates `count` to determine how many pointers to generate, then
for each index (bound to the variable named by `each`), it evaluates the `is`
pointer template.

### List with dynamic count

When the count comes from storage:

<PointerExample
title="Array with length from storage"
pointer={{
group: [
{ name: "arrayLength", location: "storage", slot: 0 },
{
list: {
count: { $read: "arrayLength" },
each: "i",
is: {
name: "element",
location: "storage",
slot: { $sum: [1, "i"] },
},
},
},
],
}}
state={{
storage: {
"0x00":
"0x0000000000000000000000000000000000000000000000000000000000000002",
"0x01":
"0x000000000000000000000000000000000000000000000000000000000000000a",
"0x02":
"0x0000000000000000000000000000000000000000000000000000000000000014",
},
}}
/>
pointer template. The `count` can itself come from storage, read via `$read`,
so the number of elements is determined at runtime.

### List properties

Expand All @@ -153,31 +74,6 @@ When the count comes from storage:
A **conditional** selects between pointers based on whether an expression
evaluates to a non-zero value.

<PointerExample
title="Conditional pointer"
pointer={{
group: [
{ name: "flag", location: "storage", slot: 0 },
{
if: { $read: "flag" },
then: { name: "whenTrue", location: "storage", slot: 1 },
else: { name: "whenFalse", location: "storage", slot: 2 },
},
],
}}
state={{
storage: {
"0x00":
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x01":
"0x000000000000000000000000000000000000000000000000000000000000002a",
"0x02":
"0x00000000000000000000000000000000000000000000000000000000000000ff",
},
}}
description="Click 'Try it' and change slot 0 to 0x00 to see the 'else' branch"
/>

### Conditional properties

| Property | Description |
Expand All @@ -191,28 +87,6 @@ evaluates to a non-zero value.
A **scope** defines variables that can be used in a nested pointer. Variables
are evaluated in order, so later variables can reference earlier ones.

<PointerExample
title="Scope with computed slot"
pointer={{
define: {
baseSlot: 3,
offset: 2,
},
in: {
name: "result",
location: "storage",
slot: { $sum: ["baseSlot", "offset"] },
},
}}
state={{
storage: {
"0x05":
"0x0000000000000000000000000000000000000000000000000000000000000064",
},
}}
description="Computes slot 3 + 2 = 5"
/>

Scopes help break complex pointer definitions into readable steps. For examples
combining scopes with keccak256 for storage slot computation, see the
[expressions documentation](./expressions#computing-storage-slots-with-keccak256).
Expand All @@ -229,39 +103,6 @@ combining scopes with keccak256 for storage slot computation, see the
A **reference** invokes a named pointer template, while **templates** defines
them inline. These work together for reusable pointer patterns.

<PointerExample
title="Template with reference"
pointer={{
templates: {
"read-slot": {
expect: ["n"],
for: { name: "slot", location: "storage", slot: "n" },
},
},
in: {
group: [
{
define: { n: 0 },
in: { template: "read-slot" },
},
{
define: { n: 1 },
in: { template: "read-slot" },
},
],
},
}}
state={{
storage: {
"0x00":
"0x000000000000000000000000000000000000000000000000000000000000000a",
"0x01":
"0x0000000000000000000000000000000000000000000000000000000000000014",
},
}}
description="Defines a template and uses it twice"
/>

### Template definition

Each template in the `templates` object has:
Expand All @@ -284,80 +125,14 @@ Collections can be nested to build complex pointer structures. A group might
contain lists, conditionals might wrap groups, and scopes can define variables
used throughout nested collections.

<PointerExample
title="Nested: scope + conditional + list"
pointer={{
group: [
{ name: "lengthSlot", location: "storage", slot: 0 },
{
define: {
len: { $read: "lengthSlot" },
},
in: {
if: "len",
then: {
list: {
count: "len",
each: "i",
is: {
name: "item",
location: "storage",
slot: { $sum: [1, "i"] },
},
},
},
},
},
],
}}
state={{
storage: {
"0x00":
"0x0000000000000000000000000000000000000000000000000000000000000003",
"0x01":
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x02":
"0x0000000000000000000000000000000000000000000000000000000000000002",
"0x03":
"0x0000000000000000000000000000000000000000000000000000000000000003",
},
}}
description="Reads length, checks if non-zero, then generates that many pointers"
/>

## Named regions in collections

Pointers within collections can include a `name` property. Named regions are
tracked during resolution and can be referenced using the `.slot`, `.offset`,
and `.length` syntax in expressions.

<PointerExample
title="Region reference with .slot"
pointer={{
group: [
{ name: "header", location: "storage", slot: 0 },
{
name: "body",
location: "storage",
slot: { $sum: [{ ".slot": "header" }, 1] },
},
],
}}
state={{
storage: {
"0x00":
"0x0000000000000000000000000000000000000000000000000000000000000010",
"0x01":
"0x0000000000000000000000000000000000000000000000000000000000000020",
},
}}
description="Second region's slot is computed from first region's slot (0 + 1 = 1)"
/>

## Learn more

- [Regions](./regions) for simple pointer definitions
- [Expressions](./expressions) for dynamic value computation
- [Pointer specification](/spec/pointer/collection) for formal definitions

</PointerPlayground>
Loading
Loading