global-lib 1.0.0

Process-wide values for Rust: set, define, read, edit, and remove globals by name or through typed statics, with lock-free reads. Zero dependencies.
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
<h1 align="center">
    <img width="99" alt="Rust logo" src="https://raw.githubusercontent.com/jamesgober/rust-collection/72baabd71f00e14aa9184efcb16fa3deddda3a0a/assets/rust-logo.svg">
    <br><b>global-lib</b><br>
    <sub><sup>API REFERENCE</sup></sub>
</h1>
<div align="center">
    <sup>
        <a href="../README.md" title="Project Home"><b>HOME</b></a>
        <span>&nbsp;&mdash;&nbsp;</span>
        <span>API</span>
        <span>&nbsp;&mdash;&nbsp;</span>
        <a href="./PERFORMANCE.md" title="Performance"><b>PERFORMANCE</b></a>
        <span>&nbsp;&mdash;&nbsp;</span>
        <a href="./GUIDELINES.md" title="Developer Guidelines"><b>GUIDELINES</b></a>
        <span>&nbsp;&mdash;&nbsp;</span>
        <a href="./STABILITY-1.0.md" title="Stability Contract"><b>STABILITY</b></a>
    </sup>
</div>
<br>

> **Status:** This reference tracks the public surface of `global-lib` **1.0.0**. Everything documented here is frozen for 1.x under the [stability contract](./STABILITY-1.0.md).

## Table of Contents

- [Choosing an API](#choosing-an-api)
- [Free Functions](#free-functions)
  - [The process-wide store](#the-process-wide-store)
- [Globals](#globals)
  - [Creating](#creating)
  - [Writing](#writing)
  - [Reading](#reading)
  - [Editing](#editing)
  - [Inspecting](#inspecting)
- [Global&lt;T&gt;](#globalt)
- [Semantics](#semantics)
  - [Types](#types)
  - [Replacing, removing, and handles](#replacing-removing-and-handles)
  - [Concurrent writers](#concurrent-writers)
  - [Calling back into a store](#calling-back-into-a-store)
  - [Panics in closures](#panics-in-closures)
  - [When values are dropped](#when-values-are-dropped)
- [Errors](#errors)
- [Design Notes](#design-notes)
- [Not Included](#not-included)

<br>

## Choosing an API

| You want | Use |
|---|---|
| A few values shared across the program, set and read by name | The free functions: `global_lib::set`, `value`, `with`, ... |
| A value read on a hot path, with its type known at compile time | A `static` [`Global<T>`](#globalt) |
| A group of named values kept apart from the process-wide store, or a fresh set per test | Your own [`Globals`](#globals) |

All three use the same storage underneath and have the same read and write costs, except that a `Global<T>` does not hash a name. Each read is lock-free and allocation-free.

<br>

## Free Functions

The free functions operate on one process-wide [`Globals`](#globals), created on first use. Each is a shorthand for the method of the same name on `global_lib::globals()`.

| Function | Returns | Notes |
|---|---|---|
| `set(name, value)` | `()` | Replaces any previous value, of any type |
| `define(name, value)` | `Result<()>` | Set-once: `Error::AlreadyDefined` if `name` is set |
| `get::<T>(name)` | `Option<Arc<T>>` | `None` if unset or of another type |
| `try_get::<T>(name)` | `Result<Arc<T>>` | `Error::Missing` or `Error::TypeMismatch` |
| `value::<T>(name)` | `Option<T>` | A clone; needs `T: Clone` |
| `with::<T, R>(name, f)` | `Option<R>` | Runs `f(&T)` on the value in place; the fastest read |
| `edit::<T>(name, f)` | `Result<()>` | Runs `f(&mut T)` on a copy and swaps it in, retrying on conflict; needs `T: Clone` |
| `remove(name)` | `bool` | Whether `name` was set |
| `contains(name)` | `bool` | Whether `name` is set, to a value of any type |
| `globals()` | `&'static Globals` | The process-wide store itself |

Every value type must be `Send + Sync + 'static`. Names are `&str` and may be any text, including the empty string.

```rust
use global_lib::Error;

global_lib::set("port", 7000u16);
global_lib::define("app_name", "HiveDB")?;

assert_eq!(global_lib::value::<u16>("port"), Some(7000));
assert_eq!(global_lib::with::<u16, _>("port", |p| *p * 2), Some(14_000));
assert_eq!(*global_lib::get::<u16>("port").unwrap(), 7000);

global_lib::edit::<u16>("port", |p| *p += 1)?;
assert_eq!(global_lib::value::<u16>("port"), Some(7001));

assert!(matches!(
    global_lib::define("app_name", "Other"),
    Err(Error::AlreadyDefined { .. })
));

assert!(global_lib::remove("port"));
assert!(!global_lib::contains("port"));
# Ok::<(), global_lib::Error>(())
```

`with` and `get` take the value type as the first type parameter. `with` has a second one for the closure's result, which is usually left to inference: `with::<u16, _>`. When the result is bound with a type annotation, the turbofish on `value` and `get` can be dropped: `let port: Option<u16> = global_lib::value("port");`.

### The process-wide store

`globals()` returns the store the free functions use. It is created on first use and never dropped. Use it for the methods that have no free-function shorthand:

```rust
global_lib::set("api.workers", 8usize);

let store = global_lib::globals();
assert_eq!(store.type_of("api.workers"), Some("usize"));
assert!(store.names().contains(&"api.workers".to_owned()));
```

The process-wide store is shared by everything in the process, including libraries and tests that run in parallel. Give names a prefix of your own (`api.workers`) when several components use it, and avoid `clear` on it outside of a program's own shutdown logic.

<br>

## Globals

`Globals` is a set of named values of any `Send + Sync + 'static` type. It is `Send + Sync`, `Debug`, and `Default`.

### Creating

| Function | Does |
|---|---|
| `Globals::new()` | An empty set |
| `Globals::default()` | The same as `new` |

`Globals::new` is not a `const fn`, so a `Globals` in a `static` goes behind a `LazyLock` or `OnceLock`. To share one between threads without a `static`, wrap it in an `Arc`, or pass `&Globals` to scoped threads.

```rust
use std::sync::LazyLock;
use global_lib::Globals;

static CACHE_SETTINGS: LazyLock<Globals> = LazyLock::new(Globals::new);

CACHE_SETTINGS.set("capacity", 4096usize);
assert_eq!(CACHE_SETTINGS.value::<usize>("capacity"), Some(4096));
```

A `Globals` per test keeps tests from seeing each other's values, which the process-wide store cannot do when tests run in parallel:

```rust
let g = global_lib::Globals::new();
g.set("retries", 3u32);
assert_eq!(g.len(), 1);
```

Dropping a `Globals` drops the values it holds, except those still referenced by an `Arc` from `get` or `try_get`.

### Writing

| Method | Returns | Does |
|---|---|---|
| `set(name, value)` | `()` | Sets `name`, replacing any previous value of any type |
| `define(name, value)` | `Result<()>` | Sets `name` only if it is not set |
| `remove(name)` | `bool` | Removes `name`; returns whether it was set |
| `clear()` | `()` | Removes every value |

```rust
let g = global_lib::Globals::new();

g.set("mode", "fast");
g.set("mode", 2u8);                       // replaces the &str with a u8
assert_eq!(g.value::<u8>("mode"), Some(2));

g.define("build", "1.0.0")?;
assert!(g.define("build", "2.0.0").is_err());
assert_eq!(g.value::<&str>("build"), Some("1.0.0"));

assert!(g.remove("mode"));
assert!(!g.remove("mode"));
g.clear();
assert!(g.is_empty());
# Ok::<(), global_lib::Error>(())
```

`define` is for values that must not change after they are first set, such as a build identifier or a configuration chosen at startup. If `name` is already set, it fails with `Error::AlreadyDefined`, keeps the existing value, and drops the value it was given. Use `set` to replace a value deliberately.

### Reading

| Method | Returns | Missing or wrong type |
|---|---|---|
| `get::<T>(name)` | `Option<Arc<T>>` | `None` |
| `try_get::<T>(name)` | `Result<Arc<T>>` | `Error::Missing` or `Error::TypeMismatch` |
| `value::<T>(name)` | `Option<T>`, needs `T: Clone` | `None` |
| `with::<T, R>(name, f)` | `Option<R>` | `None`, and `f` is not called |
| `contains(name)` | `bool` | `false` when missing; any type counts |

```rust
use std::sync::Arc;

let g = global_lib::Globals::new();
g.set("hosts", vec![String::from("a.local"), String::from("b.local")]);

// In place: nothing is cloned and no reference count changes.
let count = g.with::<Vec<String>, _>("hosts", Vec::len);
assert_eq!(count, Some(2));

// A shared handle, cheap to keep or pass to another thread.
let hosts: Arc<Vec<String>> = g.get("hosts").unwrap();
assert_eq!(hosts[0], "a.local");

// A clone of the whole value.
let copy: Option<Vec<String>> = g.value("hosts");
assert_eq!(copy.map(|v| v.len()), Some(2));
```

`with` is the cheapest read. It borrows the value for the length of the closure, so keep the closure short: the snapshot it borrows stays alive until it returns, even if another thread replaces the value meanwhile. `get` adds one atomic reference-count increment and returns a handle that can be held as long as needed. `value` clones, which suits small `Copy` values and is the most convenient form for them.

`get`, `value`, and `with` return `None` both when `name` is not set and when it holds a different type. `try_get` returns the same handle as `get` but tells the two cases apart.

### Editing

| Method | Returns | Needs |
|---|---|---|
| `edit::<T>(name, f)` | `Result<()>` | `T: Clone`; `f: impl FnMut(&mut T)` |

```rust
let g = global_lib::Globals::new();
g.set("allowed", vec![22u16, 80]);

g.edit::<Vec<u16>>("allowed", |ports| ports.push(443))?;
assert_eq!(g.value::<Vec<u16>>("allowed"), Some(vec![22, 80, 443]));

assert!(g.edit::<u16>("allowed", |_| {}).is_err());   // wrong type, nothing changed
# Ok::<(), global_lib::Error>(())
```

`edit` reads the current value, clones it, and runs `f` on the clone with no lock held. It then takes the store's write lock and installs the clone, but only if `name` still holds the value it started from (the same allocation, compared by pointer). If another thread replaced or edited `name` in the meantime, `edit` discards its copy and starts again from the new value. Concurrent edits therefore never lose an update, and readers see the old value or the new one, never a partly edited one. Writes to other names in the same store do not cause a retry.

Because no lock is held while it runs, `f` may read or write any global, including other names in the same store, without risk of deadlock. For the same reason `f` is `FnMut` and may run more than once: it should only compute the new value from the one it is given, and leave side effects to the code after `edit` returns. Do not write `name` itself from inside its own `edit` closure. Every attempt then conflicts with the write it just made, and the edit retries indefinitely.

If `name` is not set, `edit` fails with `Error::Missing`; if it holds another type, with `Error::TypeMismatch`. In both cases `f` is not called and nothing changes. If `name` is removed while `f` runs, `edit` returns `Error::Missing` and nothing is installed; if it is replaced by a value of another type, `Error::TypeMismatch`.

The cost of an edit is one read, one clone of the value, and a write, plus one more of each for every retry. For a large value edited often, store an `Arc<Mutex<T>>` or an atomic instead and change it through that; the store then only hands out the shared handle.

### Inspecting

| Method | Returns |
|---|---|
| `type_of(name)` | `Option<&'static str>`, the stored type as given by `std::any::type_name` |
| `len()` | Number of values set |
| `is_empty()` | Whether no values are set |
| `names()` | `Vec<String>`, every name, sorted |

```rust
let g = global_lib::Globals::new();
g.set("token", String::from("s3cr3t"));
g.set("port", 7000u16);

assert_eq!(g.names(), ["port", "token"]);
assert_eq!(g.type_of("port"), Some("u16"));
assert_eq!(g.type_of("missing"), None);

let shown = format!("{g:?}");
assert!(shown.contains("token") && !shown.contains("s3cr3t"));
```

`Debug` lists names and their types, sorted by name, and never values.

<br>

## Global&lt;T&gt;

`Global<T>` is one typed value meant for a `static`. Its type is checked at compile time and there is no name to look up, so it is the choice for values read on hot paths. `Global::new` is a `const fn`.

```rust
use global_lib::Global;

static PORT: Global<u16> = Global::new();

assert!(!PORT.is_set());
assert_eq!(PORT.set(7000), None);
assert_eq!(PORT.with(|p| *p + 1), Some(7001));

assert!(PORT.edit(|p| *p += 1));
assert_eq!(PORT.value(), Some(7001));

assert_eq!(PORT.define(9000), Err(9000));       // already set: value handed back
assert_eq!(PORT.take().as_deref(), Some(&7001));
assert!(!PORT.edit(|p| *p += 1));                // unset: closure not called
```

| Method | Returns | Does |
|---|---|---|
| `Global::new()` | `Global<T>` | An unset global; `const`, usable in a `static` |
| `set(value)` | `Option<Arc<T>>` | Sets the value; returns the previous one |
| `define(value)` | `Result<(), T>` | Sets the value only if none is set; `Err(value)` gives it back |
| `get()` | `Option<Arc<T>>` | A shared handle |
| `value()` | `Option<T>` | A clone; needs `T: Clone` |
| `with(f)` | `Option<R>` | Runs `f(&T)` in place; the fastest read in the crate |
| `edit(f)` | `bool` | Runs `f(&mut T)` on a copy and swaps it in, retrying on conflict; `false`, without calling `f`, if unset; needs `T: Clone` |
| `take()` | `Option<Arc<T>>` | Removes the value and returns it |
| `is_set()` | `bool` | Whether a value is set |

`T` must be `Send + Sync + 'static`. `Global<T>` is then `Send + Sync`, so it can live in a `static`. It implements `Default` (unset) and `Debug`, which shows the type name and whether a value is set, never the value.

The semantics match `Globals`: `set` replaces, `define` is set-once, `edit` loses no update under concurrent edits, and handles from `get`, `set`, and `take` stay valid after the value changes. There is no type mismatch to report, so `define` returns the rejected value instead of an `Error`, and `edit` returns a `bool`. `Global::edit` works as described under [Editing](#editing): `f` runs on a copy with no lock held and may run more than once. It returns `false` if the global is unset when the edit starts, without calling `f`, or if it is taken while `f` runs.

<br>

## Semantics

### Types

A value is found only under the exact type it was stored with. `u16` and `u32` are different types, and so are `&'static str` and `String`:

```rust
let g = global_lib::Globals::new();
g.set("name", "HiveDB");                              // a &'static str

assert_eq!(g.value::<String>("name"), None);          // not a String
assert_eq!(g.value::<&str>("name"), Some("HiveDB"));

let err = g.try_get::<String>("name").unwrap_err();
assert_eq!(err.to_string(), r#"global "name" holds a &str, not a alloc::string::String"#);
```

When a lookup fails for this reason, `get`, `value`, and `with` return `None`, and `try_get` and `edit` return `Error::TypeMismatch` with the name, the requested type (`expected`), and the stored type (`found`). Both type names come from `std::any::type_name`. Use `try_get` while developing to find out which type a value was stored as, or `type_of` to ask directly.

Trait objects are stored behind a pointer type that is itself `Send + Sync`, and read back under that same type:

```rust
use std::sync::Arc;

type Hasher = Arc<dyn Fn(&str) -> u64 + Send + Sync>;

let g = global_lib::Globals::new();
g.set("hasher", Arc::new(|s: &str| s.len() as u64) as Hasher);

let hash = g.value::<Hasher>("hasher").unwrap();
assert_eq!(hash("abc"), 3);
```

### Replacing, removing, and handles

`set` replaces whatever `name` held, whatever its type. A handle obtained earlier from `get` or `try_get` is an ordinary `Arc` and keeps the value it pointed to alive after that value is replaced or removed. It never changes to the new value; call `get` again to see it.

```rust
let g = global_lib::Globals::new();
g.set("motd", String::from("old"));
let held = g.get::<String>("motd").unwrap();

g.set("motd", String::from("new"));
assert!(g.remove("motd"));

assert_eq!(held.as_str(), "old");
assert_eq!(g.get::<String>("motd"), None);
```

### Concurrent writers

Writes to one store, or to one `Global<T>`, are serialized. Each one starts from the latest value, so:

- concurrent `edit` calls each take effect, one after another, and no update is lost;
- of two `define` calls for the same name, exactly one succeeds;
- readers see each value either before or after a write, never in between.

Writes to different stores, or to different `Global<T>`s, do not wait for each other.

Reads never wait for writes, apart from the rare [fallback path](#design-notes) for deeply nested reads. A read that starts while a write is in progress sees the value from before it; a read that starts after the write returns sees the new value.

### Calling back into a store

Writers never wait for readers, and no lock is held while user code runs, so a `with` or `edit` closure may read or write any global, including the same store or `Global<T>`, without deadlocking. A `with` closure keeps seeing the value it was given; later reads see the change:

```rust
let g = global_lib::Globals::new();
g.set("a", 1u32);
g.set("b", 2u32);

let b = g.with::<u32, _>("a", |a| {
    g.edit::<u32>("b", |b| *b += *a).unwrap();
    g.value::<u32>("b")
});
assert_eq!(b, Some(Some(3)));
```

The one thing not to do is write the name being edited from inside its own `edit` closure. That does not deadlock, but every attempt conflicts with the write the closure itself made, so the edit retries indefinitely. Writing other names in the same store, or other stores, is fine.

### Panics in closures

A panic inside a `with` closure unwinds through the read, which releases its hazard announcement; the store stays usable. A panic inside an `edit` closure leaves the value unchanged, because the copy is installed only after the closure returns, and no lock is held while it runs; the store stays usable. No function in the crate panics on its own.

### When values are dropped

A replaced or removed value is dropped when the last reference to it goes away: the last snapshot that contains it, and every handle from `get`, `try_get`, `set`, or `take`. An old snapshot is freed as soon as no reader is using it, either by the writer that replaced it or by the last reader to finish with it. A value's `Drop` can therefore run on any thread that reads or writes the store, not only on the thread that replaced it.

Replaced, removed, and rejected values (the value a failed `define` was given, or the unused copy from an `edit` that had to retry) are all dropped outside the write lock, so their `Drop` implementations may use the store they were in.

<br>

## Errors

Fallible functions return `global_lib::Result<T>`, an alias for `std::result::Result<T, global_lib::Error>`. `Global::define` is the exception: it returns `Result<(), T>`, giving the value back.

| Variant | Returned by | Meaning |
|---|---|---|
| `Missing { name }` | `try_get`, `edit` | No global with this name is set |
| `TypeMismatch { name, expected, found }` | `try_get`, `edit` | The global holds a `found`, not the requested `expected` |
| `AlreadyDefined { name }` | `define` | The name is set; the existing value was kept |

```rust
use global_lib::{Error, Globals};

let g = Globals::new();
g.set("port", 7000u16);

match g.try_get::<u32>("port") {
    Err(Error::TypeMismatch { name, expected, found }) => {
        assert_eq!((name.as_str(), expected, found), ("port", "u32", "u16"));
    }
    other => panic!("unexpected: {other:?}"),
}
```

`Error` is `Debug`, `Clone`, `PartialEq`, `Eq`, `Display`, and `std::error::Error`. It is `#[non_exhaustive]`, so match it with a wildcard arm.

Errors name the global and the types involved, never the value: globals often hold configuration and credentials, and errors end up in logs. A name echoed in an error is cut to its first 64 characters, followed by `...`.

<br>

## Design Notes

**Reads.** Every store, and every `Global<T>`, holds its current snapshot behind an atomic pointer. A read announces that pointer in a per-thread hazard slot (one sequentially consistent store), checks that it is still current (one load), borrows the snapshot, and clears the announcement. There is no lock, no allocation, and, with `with`, no reference-count change. Each thread writes only to its own hazard record, which is aligned to 128 bytes so that no two threads share a cache line; readers therefore do not slow each other down, and aggregate read throughput grows with the number of threads.

**Writes.** Writers take a mutex per store, build a new snapshot from the current one, swap the pointer, and retire the old snapshot. For a `Globals`, the snapshot is the whole name-to-value map, so every write copies the map: `O(n)` in the number of values, about 1.2 µs per `set` with 32 values on the benchmark machine. This is the deliberate trade for values that are read far more often than written. Values themselves are reference-counted and are not cloned by the copy, except by `edit`, which clones the one value it changes.

**Edits are optimistic.** `edit` reads and clones the value without a lock, runs the closure, and installs the result with a pointer comparison under the write lock, retrying if the value changed in between. Holding the lock while user code runs would make any write from inside the closure a deadlock; the retry keeps updates from being lost without that risk. Under heavy contention on one name an edit may run its closure several times; for a counter written by many threads at once, an atomic stored once is cheaper.

**Reclamation.** A retired snapshot is freed once no hazard slot announces it: immediately by the writer when no reader holds it, otherwise by the last reader holding it, on its way out. Writers never wait for readers.

**Names are hashed with SipHash.** The map uses the standard library's default hasher, which resists collision attacks. Names may come from input, such as a configuration file or a request, and a faster hasher without that resistance would let crafted names degrade lookups. For values read in tight loops, a `Global<T>` avoids the hash entirely.

**Deep nesting falls back to a lock.** Each thread has 8 hazard slots, one per level of nested reads (a `with` closure that reads another global uses the next slot). A read nested deeper than 8 levels on one thread, or a read made while the thread's thread-local storage is being torn down, takes a slower path that clones the snapshot handle under the store's write lock. Results are the same; only the cost differs.

**Process-wide state.** The crate has two pieces of process-wide state: the default store behind the free functions, and the list of per-thread hazard records. A record is allocated the first time a thread reads a global, is never freed, and is reused by the next new thread after its owner exits. The list is therefore bounded by the peak number of threads that were reading globals at the same time.

**`unsafe` is confined.** The hazard-pointer domain (`src/hazard.rs`) and the snapshot cell (`src/snapshot.rs`) are the only modules allowed `unsafe` code, and every block carries a `SAFETY` comment. The crate root denies `unsafe_code` everywhere else. The design is the one used by `registry-io` 1.1 and is checked with Miri; see the [release notes](./release/v1.0.0.md#verification).

**Zero dependencies.** Everything is built on the standard library.

<br>

## Not Included

These are outside the 1.0 scope:

- **Change notifications.** Nothing calls you back when a global changes. [`registry-io`](https://crates.io/crates/registry-io) provides subscriptions.
- **Persistence.** Values live for the life of the process. Load them from, and save them to, a file with [`env-lib`](https://crates.io/crates/env-lib) or `config-lib`.
- **Scoped and thread-local values.** Every value is visible to every thread. Use `std::thread_local!` for per-thread values.
- **Async-aware waiting.** There is no way to wait until a global is set. Set required globals during startup, before the code that reads them runs.