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
//! Lazy-access asset trait for textures, audio, and any other
//! large blob a 3D scene can carry.
//!
//! ## Why a trait instead of `Vec<u8>`
//!
//! Round 1 ran with `ImageData::Encoded { mime, bytes: Vec<u8> }`,
//! which materialises the entire payload up-front. That's fine for a
//! 64 KiB icon but pathological for the actual workloads the model
//! has to carry — USDZ archives are routinely hundreds of megabytes,
//! glTF GLB binary chunks pin tens of MB of textures, FBX embedded
//! media can be larger still. Eagerly copying every blob into a
//! `Vec` triples peak memory (file → mmap → owned `Vec` →
//! decoded), and worse it forecloses on the obvious optimisation:
//! when a converter is asked to write the SAME container scheme it
//! read from (USDZ → USDZ, GLB → GLB), the deflated/raw payload can
//! pass through unchanged with no decode + re-encode round-trip.
//!
//! [`AssetSource`] solves both:
//!
//! * `open()` returns a streaming reader, so large assets can be
//! chunked into the encoder without ever holding the full payload
//! in RAM. Small callers `.read_to_end()` and move on.
//! * `raw_storage()` is the optional pass-through hint. A USDZ
//! reader exposes `RawStorage { scheme: "zip-deflate", bytes: ... }`
//! for its embedded files; a USDZ writer that sees the same scheme
//! on input copies the deflated bytes verbatim into its output ZIP
//! instead of inflating + re-deflating. Crates that don't share a
//! scheme transparently fall back to `open()`.
//!
//! ## Scheme names
//!
//! `RawStorage::scheme` is a free-form string; format crates should
//! agree on canonical names so reader/writer pairs can recognise
//! each other across crate boundaries. Conventions:
//!
//! * `"zip-deflate"` — bytes are RFC 1951 deflate-compressed,
//! uncompressed size in `uncompressed_size`.
//! * `"zip-stored"` — bytes are the uncompressed payload as stored
//! in a ZIP container (no transform).
//! * `"usdc-crate"` — Pixar USD binary crate file payload.
//! * `"tar-stored"` — uncompressed payload of a tar entry.
//!
//! New schemes are added by convention; downstream pairs that don't
//! recognise a scheme just ignore `raw_storage()` and use `open()`.
use Result as IoResult;
/// Re-export of [`oxideav_core::ReadSeek`] so callers don't have to
/// pull in the framework crate directly to name the [`AssetSource::open`]
/// return type.
pub use ReadSeek;
/// Streaming reader trait alias used when the `registry` feature is
/// off. Mirrors [`oxideav_core::ReadSeek`] so the [`AssetSource`]
/// signature is identical with or without the feature.
/// Lazy reference to a binary asset payload (image, audio, anything
/// the type model carries by reference).
///
/// Implementors are typically thin wrappers around a file handle, a
/// memory-mapped region, or a slice into a larger ZIP archive.
/// [`InMemoryAsset`] is the trivial owning implementation provided
/// for tests and small embedded payloads.
/// Result of [`AssetSource::raw_storage`]: the asset's stored bytes
/// (in their on-disk form) plus the scheme they were stored under.
///
/// `bytes` may be compressed depending on `scheme`; `uncompressed_size`
/// is the post-decode length when the scheme tracks it (e.g. ZIP
/// stores it in the local file header).
/// Trivial in-memory [`AssetSource`] backed by an owned `Vec<u8>`.
///
/// Construct one when a caller already has the bytes on hand (a unit
/// test, a small embedded icon, a generated procedural payload) and
/// just needs an `Arc<dyn AssetSource>` to pass into the type model.
/// `raw_storage()` is unimplemented because the bytes are stored
/// uncompressed under no particular container scheme; format crates
/// that want pass-through should expose their own `AssetSource` impl
/// against the original ZIP / USDZ / GLB payload.