1mod asset;
54mod field;
55mod key;
56mod loader;
57pub mod source;
58
59use std::{
60 borrow::Borrow,
61 fmt::{self, Debug, Display, LowerHex, UpperHex},
62 marker::PhantomData,
63 num::NonZeroU64,
64 str::FromStr,
65 sync::Arc,
66};
67
68pub use self::{
69 asset::{Asset, AssetBuild, SimpleAsset, TrivialAsset},
70 field::{AssetField, AssetFieldBuild, Container, External},
71 loader::{AssetHandle, AssetResult, AssetResultPoisoned, Error, Key, Loader, LoaderBuilder},
72};
73pub use goods_proc::{Asset, AssetField};
74
75#[doc(hidden)]
77pub use {bincode, serde, serde_json, std::convert::Infallible, thiserror};
78
79#[derive(thiserror::Error)]
80#[error("Asset '{key}' is not found")]
81struct NotFound {
82 key: Arc<str>,
83}
84
85impl fmt::Debug for NotFound {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 Display::fmt(self, f)
88 }
89}
90
91#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
96#[repr(transparent)]
97pub struct AssetId(pub NonZeroU64);
98
99impl AssetId {
100 pub const fn new(value: u64) -> Option<Self> {
101 match NonZeroU64::new(value) {
102 None => None,
103 Some(value) => Some(AssetId(value)),
104 }
105 }
106}
107
108impl serde::Serialize for AssetId {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: serde::Serializer,
112 {
113 use std::io::Write;
114
115 if serializer.is_human_readable() {
116 let mut hex = [0u8; 16];
117 write!(std::io::Cursor::new(&mut hex[..]), "{:x}", self.0).expect("Must fit");
118 debug_assert!(hex.is_ascii());
119 let hex = std::str::from_utf8(&hex).expect("Must be UTF-8");
120 serializer.serialize_str(hex)
121 } else {
122 serializer.serialize_u64(self.0.get())
123 }
124 }
125}
126
127impl<'de> serde::Deserialize<'de> for AssetId {
128 fn deserialize<D>(deserializer: D) -> Result<AssetId, D::Error>
129 where
130 D: serde::Deserializer<'de>,
131 {
132 if deserializer.is_human_readable() {
133 let hex = std::borrow::Cow::<str>::deserialize(deserializer)?;
134 hex.parse().map_err(serde::de::Error::custom)
135 } else {
136 let value = NonZeroU64::deserialize(deserializer)?;
137 Ok(AssetId(value))
138 }
139 }
140}
141
142#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
143pub enum ParseAssetIdError {
144 #[error(transparent)]
145 ParseIntError(#[from] std::num::ParseIntError),
146
147 #[error("AssetId cannot be zero")]
148 ZeroId,
149}
150
151impl FromStr for AssetId {
152 type Err = ParseAssetIdError;
153 fn from_str(s: &str) -> Result<Self, ParseAssetIdError> {
154 let value = u64::from_str_radix(s, 16)?;
155 match NonZeroU64::new(value) {
156 None => Err(ParseAssetIdError::ZeroId),
157 Some(value) => Ok(AssetId(value)),
158 }
159 }
160}
161
162impl Debug for AssetId {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 LowerHex::fmt(&self.0.get(), f)
165 }
166}
167
168impl Display for AssetId {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 LowerHex::fmt(&self.0.get(), f)
171 }
172}
173
174impl LowerHex for AssetId {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 LowerHex::fmt(&self.0.get(), f)
177 }
178}
179
180impl UpperHex for AssetId {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 UpperHex::fmt(&self.0.get(), f)
183 }
184}
185
186#[derive(
188 Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
189)]
190#[serde(transparent)]
191#[repr(transparent)]
192pub struct TypedAssetId<A> {
193 pub id: AssetId,
194 pub marker: PhantomData<A>,
195}
196
197impl<A> TypedAssetId<A> {
198 pub const fn new(value: u64) -> Option<Self> {
199 match AssetId::new(value) {
200 None => None,
201 Some(id) => Some(TypedAssetId {
202 id,
203 marker: PhantomData,
204 }),
205 }
206 }
207}
208
209impl<A> Borrow<AssetId> for TypedAssetId<A> {
210 fn borrow(&self) -> &AssetId {
211 &self.id
212 }
213}
214
215impl<A> Debug for TypedAssetId<A>
216where
217 A: Asset,
218{
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 if f.alternate() {
221 write!(f, "{}({:#?})", A::name(), self.id)
222 } else {
223 write!(f, "{}({:?})", A::name(), self.id)
224 }
225 }
226}
227
228impl<A> Display for TypedAssetId<A>
229where
230 A: Asset,
231{
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 if f.alternate() {
234 write!(f, "{}({:#})", A::name(), self.id)
235 } else {
236 write!(f, "{}({:})", A::name(), self.id)
237 }
238 }
239}
240
241impl<A> LowerHex for TypedAssetId<A>
242where
243 A: Asset,
244{
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 if f.alternate() {
247 write!(f, "{}({:#x})", A::name(), self.id)
248 } else {
249 write!(f, "{}({:x})", A::name(), self.id)
250 }
251 }
252}
253
254impl<A> UpperHex for TypedAssetId<A>
255where
256 A: Asset,
257{
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 if f.alternate() {
260 write!(f, "{}({:#X})", A::name(), self.id)
261 } else {
262 write!(f, "{}({:X})", A::name(), self.id)
263 }
264 }
265}
266
267#[derive(::std::fmt::Debug, thiserror::Error)]
269pub enum DecodeError {
270 #[error("Failed to deserialize asset info from json")]
271 Json(#[source] serde_json::Error),
272
273 #[error("Failed to deserialize asset info from bincode")]
274 Bincode(#[source] bincode::Error),
275}