|
1 | 1 | # Verified Ion Patterns |
2 | 2 |
|
| 3 | +**Canonical idiom reference** for agents and authors. [ION_SPEC.md](../../../ION_SPEC.md) §12 indexes this file; keep long examples here, not in the spec. Every `ion` block should match a pattern in `tests/` or `examples/` (linked inline). When semantics change, update this file and tests together. |
| 4 | + |
3 | 5 | Copy patterns from here or from linked test files. Do not add constructs not shown in ION_SPEC.md or this repo. |
4 | 6 |
|
5 | 7 | ## Types |
@@ -62,6 +64,147 @@ fn step(vm: &mut VM) { |
62 | 64 |
|
63 | 65 | Field paths are valid assignment targets on owned structs and `&mut` parameters. |
64 | 66 |
|
| 67 | +## Ownership move |
| 68 | + |
| 69 | +```ion |
| 70 | +struct Packet { |
| 71 | + id: i32; |
| 72 | + data: Vec<u8>; |
| 73 | +} |
| 74 | +
|
| 75 | +fn make_packet(data: Vec<u8>) -> Packet { |
| 76 | + Packet { id: 1, data: data } |
| 77 | +} |
| 78 | +
|
| 79 | +fn main() -> int { |
| 80 | + let buf: Vec<u8> = Vec::new(); |
| 81 | + let pkt = make_packet(buf); |
| 82 | + // buf is invalid after the move; pkt owns the data |
| 83 | + return 0; |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +See [tests/test_move_basic.ion](../../../../tests/test_move_basic.ion). |
| 88 | + |
| 89 | +## Index and handle search |
| 90 | + |
| 91 | +When another language would return `&T`, return an index (`int`) or handle and re-index locally. Read-only scans use `Vec::get_ref` (does not hollow the vector). See [tests/test_vec_search_index_ok.ion](../../../../tests/test_vec_search_index_ok.ion) and [tests/test_vec_get_ref_scan.ion](../../../../tests/test_vec_get_ref_scan.ion). |
| 92 | + |
| 93 | +```ion |
| 94 | +enum Option<T> { |
| 95 | + Some(T); |
| 96 | + None; |
| 97 | +} |
| 98 | +
|
| 99 | +struct Customer { |
| 100 | + id: int; |
| 101 | + active: int; |
| 102 | +} |
| 103 | +
|
| 104 | +fn find_customer_index(customers: &Vec<Customer>, target_id: int) -> int { |
| 105 | + let mut i: int = 0; |
| 106 | + let len: int = Vec::len(customers); |
| 107 | + while i < len { |
| 108 | + match Vec::get_ref(customers, i) { |
| 109 | + Option::Some(c) => { |
| 110 | + if c.id == target_id { |
| 111 | + return i; |
| 112 | + } |
| 113 | + } |
| 114 | + Option::None => { |
| 115 | + return -1; |
| 116 | + } |
| 117 | + }; |
| 118 | + i = i + 1; |
| 119 | + } |
| 120 | + return -1; |
| 121 | +} |
| 122 | +
|
| 123 | +fn main() -> int { |
| 124 | + let mut customers: Vec<Customer> = Vec::new(); |
| 125 | + let idx: int = find_customer_index(&customers, 42); |
| 126 | + if idx >= 0 { |
| 127 | + match Vec::get(&customers, idx) { |
| 128 | + Option::Some(c) => { |
| 129 | + let id: int = c.id; |
| 130 | + Vec::set( |
| 131 | + &mut customers, |
| 132 | + idx, |
| 133 | + Customer { |
| 134 | + id: id, |
| 135 | + active: 1, |
| 136 | + }, |
| 137 | + ); |
| 138 | + } |
| 139 | + Option::None => {} |
| 140 | + }; |
| 141 | + } |
| 142 | + return 0; |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +## Mutating Vec elements |
| 147 | + |
| 148 | +`Vec::get` moves the element out. Copy fields, rebuild the struct, and `Vec::set` it back ([tests/test_vec_get_putback.ion](../../../../tests/test_vec_get_putback.ion)). Helpers can take `&mut T` on an owned local: |
| 149 | + |
| 150 | +```ion |
| 151 | +fn mark_active(c: &mut Customer) { |
| 152 | + c.active = 1; |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +## Comparing borrowed structs |
| 157 | + |
| 158 | +Read fields through `&Struct` parameters. Ion does not allow reference fields in structs. |
| 159 | + |
| 160 | +```ion |
| 161 | +struct Customer { |
| 162 | + id: int; |
| 163 | + score: int; |
| 164 | +} |
| 165 | +
|
| 166 | +fn compare(a: &Customer, b: &Customer) -> int { |
| 167 | + if a.score != b.score { |
| 168 | + return a.score - b.score; |
| 169 | + } |
| 170 | + return a.id - b.id; |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +## Concurrency and ownership transfer |
| 175 | + |
| 176 | +Move owned values into `spawn` and channels; no shared mutable state across threads. See [examples/spawn_channel/spawn_channel.ion](../../../../examples/spawn_channel/spawn_channel.ion) and [examples/channel_worker/channel_worker.ion](../../../../examples/channel_worker/channel_worker.ion). |
| 177 | + |
| 178 | +```ion |
| 179 | +struct Job { |
| 180 | + data: Vec<u8>; |
| 181 | +} |
| 182 | +
|
| 183 | +fn worker(rx: Receiver<Job>) { |
| 184 | + let mut rx_mut: Receiver<Job> = rx; |
| 185 | + loop { |
| 186 | + let job: Job = recv(&mut rx_mut); |
| 187 | + // use job.data |
| 188 | + } |
| 189 | +} |
| 190 | +
|
| 191 | +fn main() -> int { |
| 192 | + let (tx, rx): (Sender<Job>, Receiver<Job>) = channel<Job>(); |
| 193 | +
|
| 194 | + spawn { |
| 195 | + worker(rx); |
| 196 | + }; |
| 197 | +
|
| 198 | + let job = Job { data: Vec::new() }; |
| 199 | + send(&tx, job); |
| 200 | + return 0; |
| 201 | +} |
| 202 | +``` |
| 203 | + |
| 204 | +## Owned API boundaries |
| 205 | + |
| 206 | +At module exports and public functions, prefer owned results (`Vec<T>`, `String`, structs with owned fields) over borrowed views. Use `&T`, `&str`, and local `Option<&T>` from `Vec::get_ref` inside a single function only. |
| 207 | + |
65 | 208 | ## VM dispatch loop |
66 | 209 |
|
67 | 210 | See [tests/test_vm_execute.ion](../../../../tests/test_vm_execute.ion): `match vm.code.get_ref(vm.ip)` then inner `match op` on `&Op`, field updates, and `break` inside `match` within `loop`. |
@@ -193,14 +336,12 @@ let w = v; |
193 | 336 | let _ = v.len(); |
194 | 337 | ``` |
195 | 338 |
|
196 | | -See [tests/test_ref_return_error2.ion](../../../../tests/test_ref_return_error2.ion), [tests/test_spawn_ref_error.ion](../../../../tests/test_spawn_ref_error.ion), and ION_SPEC.md section 9.4. |
| 339 | +See [tests/test_ref_return_error2.ion](../../../../tests/test_ref_return_error2.ion), [tests/test_spawn_ref_error.ion](../../../../tests/test_spawn_ref_error.ion), and ION_SPEC.md §9.4. |
197 | 340 |
|
198 | 341 | ## Design alternatives (no borrowed returns) |
199 | 342 |
|
200 | 343 | When another language would return `&T`: |
201 | 344 |
|
202 | 345 | - Return an owned value or `Option<T>` by move |
203 | | -- Return an index or handle, caller re-indexes locally |
204 | | -- Pass a callback that receives `&T` inside the callee's stack frame |
205 | | - |
206 | | -See ION_SPEC.md section 12 (non-normative). |
| 346 | +- Return an index or handle; caller re-indexes locally (see **Index and handle search** above) |
| 347 | +- Call a helper with `&mut T` on an owned local after `Vec::get` / before `Vec::set` |
0 commit comments