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
name: Rust CI
on:
push:
branches:
tags:
pull_request:
branches:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ═══════════════════════════════════════════════════════════
# Format Check
# ═══════════════════════════════════════════════════════════
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt -p pulse_map -- --check
# ═══════════════════════════════════════════════════════════
# Clippy Lint
# ═══════════════════════════════════════════════════════════
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy -p pulse_map -- -D warnings
- run: cargo clippy -p pulse_map --no-default-features -- -D warnings
- run: cargo clippy -p pulse_map --features simd -- -D warnings
# ═══════════════════════════════════════════════════════════
# Build + Test (multi-platform)
# ═══════════════════════════════════════════════════════════
test:
name: Test (${{ matrix.os }} / ${{ matrix.rust }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
rust:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2
# Build
- name: Build (default features)
run: cargo build -p pulse_map
- name: Build (no_std)
run: cargo build -p pulse_map --no-default-features
- name: Build (simd)
if: matrix.os != 'macos-latest'
run: cargo build -p pulse_map --features simd
# Test
- name: Test (default features)
run: cargo test -p pulse_map
- name: Test (no_std)
run: cargo test -p pulse_map --no-default-features
- name: Test (simd)
if: matrix.os != 'macos-latest'
run: cargo test -p pulse_map --features simd
# ═══════════════════════════════════════════════════════════
# Miri (undefined behavior in unsafe code)
# ═══════════════════════════════════════════════════════════
miri:
name: Miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: miri
- name: Run Miri (core engine, no_std path)
run: cargo miri test -p pulse_map --no-default-features
# --lib skips doc-tests: they re-run the same code paths at roughly the same cost.
- name: Run Miri (std, concurrent + sharded)
run: cargo miri test -p pulse_map --lib
# ═══════════════════════════════════════════════════════════
# loom (concurrency interleavings in lock-free code)
# ═══════════════════════════════════════════════════════════
loom:
name: Loom
runs-on: ubuntu-latest
env:
RUSTFLAGS: --cfg loom
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
# Only the loom_* integration tests. `--cfg loom` swaps the engine's atomics
# for loom's instrumented ones, which panic outside a `loom::model`, so the
# 58 unit tests deliberately stay out of this job.
- name: Run loom models
run: cargo test -p pulse_map --test loom_meta --test loom_access_buffer
# ═══════════════════════════════════════════════════════════
# Embedded no_std Check
# ═══════════════════════════════════════════════════════════
# One job per atomic capability class — that is the only axis that can break a
# bare-metal build here. MetaWord is an AtomicU64, and portable-atomic can only
# hand one out where the target gives it some form of atomic CAS to build on.
no_std:
name: no_std (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
# 32-bit CAS present: portable-atomic's spinlock fallback provides AtomicU64.
- # Cortex-M3
- # Cortex-M4F / M7F
- # Cortex-M33
- # RISC-V with the A extension
-
# Native 64-bit atomics, no fallback involved.
- # 64-bit bare metal
# No atomic CAS at any width: AtomicU64 has to go through a critical section.
- # Cortex-M0 / M0+ (RP2040)
- # ESP32-C3
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Check no_std compilation
run: cargo check -p pulse_map --target ${{ matrix.target }} --no-default-features ${{ matrix.extra }}
# ═══════════════════════════════════════════════════════════
# QEMU (runs the no_std code, instead of only compiling it)
# ═══════════════════════════════════════════════════════════
# The no_std job above proves the crate compiles for these targets; cargo check
# does not even link. This one boots a real ELF on an emulated Cortex-M and
# exercises MetaWord's AtomicU64 CAS at runtime. Cortex-M0 is the case that
# matters: it has no CAS instruction at all, so the `critical-section` feature
# is the only thing making the map work there.
qemu:
name: QEMU (${{ matrix.machine }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
-
-
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
workspaces: qemu-test
# qemu-system-arm only; its qemu-efi-aarch64 recommend is 322 MB of
# aarch64 UEFI firmware that nothing here boots.
- name: Install QEMU
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends qemu-system-arm
# Separate workspace with its own runner in .cargo/config.toml, so this
# cannot be driven from the repo root.
- name: Run on emulated hardware
working-directory: qemu-test
run: cargo run --release --target ${{ matrix.target }} ${{ matrix.extra }}
# RAM and flash cost against `lru` — the only other cache in the README's
# comparison that builds without std. Printed, not gated: it is evidence for
# the docs, and a size gate would need a stored baseline to diff against.
- name: Footprint vs lru
working-directory: qemu-test
run: |
for b in footprint_none footprint_pulse footprint_lru; do
cargo run -q --release --target ${{ matrix.target }} ${{ matrix.extra }} --bin "$b"
done
./size.sh ${{ matrix.target }}
# ═══════════════════════════════════════════════════════════
# MSRV (Minimum Supported Rust Version)
# ═══════════════════════════════════════════════════════════
msrv:
name: MSRV (1.70.0)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.70.0"
- run: cargo check -p pulse_map
- run: cargo check -p pulse_map --no-default-features
- run: cargo build -p pulse_map
# ═══════════════════════════════════════════════════════════
# Documentation
# ═══════════════════════════════════════════════════════════
docs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo doc -p pulse_map --no-deps
env:
RUSTDOCFLAGS: -D warnings
# ═══════════════════════════════════════════════════════════
# Publish to crates.io (on tag push only)
# ═══════════════════════════════════════════════════════════
publish:
name: Publish to crates.io
needs:
runs-on: ubuntu-latest
if: false # Disabled: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Publish
run: cargo publish -p pulse_map
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}