forked from argotorg/fe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheffect_ref.fe
More file actions
179 lines (149 loc) · 5 KB
/
Copy patheffect_ref.fe
File metadata and controls
179 lines (149 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use ingot::Copy
/// Effect reference traits.
///
/// Fe models effects as implicit "provider" generic parameters. The `EffectRef<T>` marker traits
/// express that a provider type can satisfy a read-only (or mutable) effect whose domain is `T`,
/// while `EffectHandle` captures concrete pointer/handle providers with a runtime representation.
///
/// Backends may define their own concrete provider types, but `core` also provides a small set of
/// general-purpose provider types (`MemPtr<T>`, `StorPtr<T>`) that backends can map onto their
/// runtime model.
/// The address space an effect provider points into.
///
/// Backends decide how each space maps onto their runtime model:
/// - `Memory`: transient linear memory.
/// - `Calldata`: an immutable input byte buffer (e.g. EVM CALLDATALOAD).
/// - `Code`: immutable code data.
/// - `Storage`: the target's persistent storage/state.
/// - `TransientStorage`: a temporary store scoped to a call frame or
/// transaction (e.g. EVM TLOAD/TSTORE).
pub enum AddressSpace {
Memory,
Calldata,
Code,
Storage,
TransientStorage,
}
/// Memory pointer to a value of type `T`.
///
/// This is a general-purpose effect provider type. Backends decide how the raw
/// handle maps to runtime memory.
pub struct MemPtr<T> {
addr: u256
}
/// Pointer/handle to a contract field of type `T`.
///
/// This is a general-purpose effect provider type. Backends decide how the raw
/// handle maps to persistent contract state (e.g. EVM storage slots).
pub struct StorPtr<T> {
handle: u256
}
impl<T> Copy for MemPtr<T> {}
impl<T> Copy for StorPtr<T> {}
/// Marker: `Self` can satisfy a read-only effect whose domain is `Target`.
pub trait EffectRef<Target> {}
/// Marker: `Self` can satisfy a *mutable* effect whose domain is `Target`.
pub trait EffectRefMut<Target>: EffectRef<Target> {}
/// A concrete pointer/handle provider with a runtime representation.
///
/// This is the place to keep `from_raw`/`raw` and address-space metadata.
pub trait EffectHandle {
type Target
/// The address space the raw handle points into.
const SPACE: AddressSpace
/// Construct the effect provider from the raw pointer/handle used by the backend.
fn from_raw(_ raw: u256) -> Self
/// Return the raw pointer/handle used by the backend (e.g. memory address or storage slot).
fn raw(self) -> u256
}
/// Marker: a handle that supports mutable access.
pub trait EffectHandleMut: EffectHandle {}
/// Reads the value a handle points at.
///
/// The handle argument anchors the effect key to the handle's `Target`, so
/// the provided effect resolves unambiguously; provide the handle with
/// `with` or call through the handle's `read` method.
pub fn read<H: EffectHandle>(_ handle: H) -> H::Target uses (value: H::Target)
where H::Target: Copy
{
value
}
/// Writes the value a handle points at.
pub fn write<H: EffectHandle>(_ handle: H, _ value: H::Target) uses (target: mut H::Target) {
target = value
}
/// Marker for zero-sized pointer types whose const slot parameter is
/// assigned by the contract layout.
///
/// When a layout hole (`= _`) instantiates the slot parameter of an
/// implementing type inside a contract field, the layout draws the slot
/// number from `SPACE`'s slot counter instead of the containing field's, so
/// statically assigned slots never collide with other state in that space.
pub trait StaticSlot {
const SPACE: AddressSpace
}
impl<T> EffectRef<T> for T {}
// Mutability is checked at the term level.
impl<T> EffectRefMut<T> for T {}
impl<T> EffectHandle for MemPtr<T> {
type Target = T
const SPACE: AddressSpace = AddressSpace::Memory
fn from_raw(_ raw: u256) -> Self {
Self { addr: raw }
}
fn raw(self) -> u256 {
self.addr
}
}
impl<T> EffectHandleMut for MemPtr<T> {}
impl<T> MemPtr<T> {
/// Reads the pointed-at value.
pub fn read(self) -> T
where T: Copy
{
let mut ptr = self
with (ptr) {
super::effect_ref::read(ptr)
}
}
/// Writes the pointed-at value.
pub fn write(self, _ value: T) {
let mut ptr = self
with (ptr) {
super::effect_ref::write(ptr, value)
}
}
}
impl<T> EffectRef<T> for MemPtr<T> {}
impl<T> EffectRefMut<T> for MemPtr<T> {}
impl<T> EffectHandle for StorPtr<T> {
type Target = T
const SPACE: AddressSpace = AddressSpace::Storage
fn from_raw(_ raw: u256) -> Self {
Self { handle: raw }
}
fn raw(self) -> u256 {
self.handle
}
}
impl<T> EffectHandleMut for StorPtr<T> {}
impl<T> StorPtr<T> {
/// Reads the pointed-at value.
pub fn read(self) -> T
where T: Copy
{
let mut ptr = self
with (ptr) {
super::effect_ref::read(ptr)
}
}
/// Writes the pointed-at value.
pub fn write(self, _ value: T) {
let mut ptr = self
with (ptr) {
super::effect_ref::write(ptr, value)
}
}
}
impl<T> EffectRef<T> for StorPtr<T> {}
impl<T> EffectRefMut<T> for StorPtr<T> {}