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
//! Cross-platform asset resolution (A6). One place that maps a logical asset
//! name (`"logo.png"`) to loadable bytes, so `ImageWidget::asset`,
//! `FontCache::from_asset`, and any future theme-from-asset loader all agree on
//! *where assets live* — and so hot-reload has a single cache to invalidate.
//!
//! The **API is identical on every platform**; only the *root* differs, and the
//! host sets it once at launch via [`set_root`]:
//! - desktop dev / `rsc dev` / `rsc run`: the project's `assets/` dir
//! (cwd-relative — the default, so nothing to set);
//! - desktop release: `assets/` beside the executable (host may override);
//! - iOS / Android: the app bundle's resources dir (FFI host sets it);
//! - web: served under `/assets/` — the wasm loader fetches bytes (wired with
//! the web asset step; the path API still resolves for URL building).
//!
//! `rsc.toml`'s `[assets] dirs = ["assets"]` declares what gets bundled; this
//! module is the runtime that reads them back.
use PathBuf;
use ;
/// A compile-time asset **handle** — the typed, typo-proof way to refer to a
/// bundled asset. The `assets` module generated from your `assets/` dir (by
/// `rosace-asset-codegen` in `build.rs`) is full of `const Asset`s:
/// `assets::LOGO`, `assets::icons::HOME`. Passing `assets::LGO` won't compile,
/// and your editor autocompletes the real names.
///
/// It's a thin newtype over the logical name, so it costs nothing at runtime
/// and interops with the raw-string escape hatch through [`AssetRef`].
/// Anything usable as an asset reference: a typed [`Asset`] handle (the blessed,
/// checked form) **or** a raw `&str`/`String` (the escape hatch, for names only
/// known at runtime — e.g. a user-picked file). Every loader takes
/// `impl AssetRef`, so both forms work at the same call site:
///
/// ```ignore
/// Image::asset(assets::LOGO) // typed, typo-proof
/// Image::asset("logo.png") // dynamic escape hatch
/// ```
/// Point asset resolution at a directory. Mobile FFI hosts call this at launch
/// with the app bundle's resources path; desktop release can point it beside
/// the executable. Desktop dev needs no call — the default (`assets/`) is right.
/// The directory assets resolve against. Resolution order:
/// 1. an explicit [`set_root`] override (mobile FFI hosts set the bundle path);
/// 2. `./assets` if it exists — the dev case (`rsc dev`/`rsc run` from the
/// project root);
/// 3. release bundle locations relative to the executable, so a Finder-launched
/// `.app` (whose cwd is `/`) or an installed binary still finds its assets:
/// - macOS `.app`: `<exe>/../Resources/assets`,
/// - Windows/Linux: `assets/` beside the executable;
/// 4. otherwise the cwd-relative `assets` default (nothing bundled yet).
///
/// The bundlers in `rsc package`/`rsc run` copy `assets/` into exactly these
/// locations, so the copy side and this resolve side stay in lockstep.
/// Resolve an asset (typed handle or raw name) to a filesystem path under the
/// asset root. `resolve(assets::icons::HOME)` → `<root>/icons/home.png`.
/// Read an asset's bytes, or `None` if it can't be found or read. This is the
/// single load primitive every typed loader (image, font, data) builds on, so
/// they all share one resolution + one hot-reload story.