Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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