bones_asset/
lib.rs

1//! An asset interface for Bones.
2
3#![warn(missing_docs)]
4// This cfg_attr is needed because `rustdoc::all` includes lints not supported on stable
5#![cfg_attr(doc, allow(unknown_lints))]
6#![deny(rustdoc::all)]
7
8use serde::{de::DeserializeSeed, Deserializer};
9
10/// Helper to export the same types in the crate root and in the prelude.
11macro_rules! pub_use {
12    () => {
13        pub use crate::{asset::*, cid::*, handle::*, io::*, network_handle::*, server::*};
14        pub use anyhow;
15        pub use bones_schema::prelude::*;
16        pub use dashmap;
17        pub use futures_lite::future::Boxed as BoxedFuture;
18        pub use path_absolutize::Absolutize;
19        pub use semver::Version;
20    };
21}
22pub_use!();
23
24/// The prelude.
25pub mod prelude {
26    pub_use!();
27    pub use super::{Maybe, Maybe::*};
28}
29
30mod asset;
31mod cid;
32mod handle;
33mod io;
34mod network_handle;
35mod parse;
36mod server;
37
38/// An equivalent to [`Option<T>`] that has a stable memory layout and implements [`HasSchema`].
39#[derive(HasSchema, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Debug)]
40#[type_data(SchemaMetaAssetLoader(maybe_loader))]
41#[repr(C, u8)]
42pub enum Maybe<T> {
43    /// The value is not set.
44    #[default]
45    Unset,
46    /// The value is set.
47    Set(T),
48}
49
50impl<T> Maybe<T> {
51    /// Convert this [`Maybe`] into an [`Option`].
52    #[inline]
53    pub fn option(self) -> Option<T> {
54        self.into()
55    }
56
57    /// Returns `true` if the option is a `Set` value.
58    #[inline]
59    pub fn is_set(&self) -> bool {
60        matches!(self, Maybe::Set(_))
61    }
62
63    /// Returns `true` if the option is an `Unset` value.
64    #[inline]
65    pub fn is_unset(&self) -> bool {
66        matches!(self, Maybe::Unset)
67    }
68
69    /// Returns `true` if the option is a `Set` value.
70    #[inline]
71    pub fn is_some(&self) -> bool {
72        matches!(self, Maybe::Set(_))
73    }
74
75    /// Returns `true` if the option is an `Unset` value.
76    #[inline]
77    pub fn is_none(&self) -> bool {
78        matches!(self, Maybe::Unset)
79    }
80
81    /// Returns `true` if the option is a `Set` value containing the given value.
82    #[inline]
83    pub fn contains<U>(&self, x: &U) -> bool
84    where
85        U: PartialEq<T>,
86    {
87        match self {
88            Maybe::Set(y) => x == y,
89            Maybe::Unset => false,
90        }
91    }
92
93    /// Converts from `&Maybe<T>` to `Maybe<&T>`.
94    #[inline]
95    pub fn as_ref(&self) -> Maybe<&T> {
96        match *self {
97            Maybe::Unset => Maybe::Unset,
98            Maybe::Set(ref x) => Maybe::Set(x),
99        }
100    }
101
102    /// Converts from `&mut Maybe<T>` to `Maybe<&mut T>`.
103    #[inline]
104    pub fn as_mut(&mut self) -> Maybe<&mut T> {
105        match *self {
106            Maybe::Unset => Maybe::Unset,
107            Maybe::Set(ref mut x) => Maybe::Set(x),
108        }
109    }
110
111    /// Returns the contained `Set` value, consuming the `self` value.
112    #[inline]
113    #[track_caller]
114    pub fn expect(self, msg: &str) -> T {
115        self.option().expect(msg)
116    }
117
118    /// Returns the contained `Set` value, consuming the `self` value.
119    #[inline]
120    #[track_caller]
121    pub fn unwrap(self) -> T {
122        self.option().unwrap()
123    }
124
125    /// Returns the contained `Set` value or a provided default.
126    #[inline]
127    pub fn unwrap_or(self, default: T) -> T {
128        self.option().unwrap_or(default)
129    }
130
131    /// Returns the contained `Set` value or computes it from a closure.
132    #[inline]
133    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
134        self.option().unwrap_or_else(f)
135    }
136
137    /// Maps a `Maybe<T>` to `Maybe<U>` by applying a function to a contained value.
138    #[inline]
139    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Maybe<U> {
140        self.option().map(f).into()
141    }
142
143    /// Returns `Unset` if the option is `Unset`, otherwise calls `f` with the wrapped value and returns the result.
144    #[inline]
145    pub fn and_then<U, F: FnOnce(T) -> Maybe<U>>(self, f: F) -> Maybe<U> {
146        self.option().and_then(|x| f(x).option()).into()
147    }
148
149    /// Returns `Unset` if the option is `Unset`, otherwise returns `optb`.
150    #[inline]
151    pub fn and<U>(self, optb: Maybe<U>) -> Maybe<U> {
152        self.option().and(optb.option()).into()
153    }
154
155    /// Returns `Unset` if the option is `Unset`, otherwise calls `predicate` with the wrapped value and returns:
156    #[inline]
157    pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Maybe<T> {
158        self.option().filter(predicate).into()
159    }
160
161    /// Returns the option if it contains a value, otherwise returns `optb`.
162    #[inline]
163    pub fn or(self, optb: Maybe<T>) -> Maybe<T> {
164        self.option().or(optb.option()).into()
165    }
166
167    /// Returns the option if it contains a value, otherwise calls `f` and returns the result.
168    #[inline]
169    pub fn or_else<F: FnOnce() -> Maybe<T>>(self, f: F) -> Maybe<T> {
170        self.option().or_else(|| f().option()).into()
171    }
172
173    /// Returns `Set` if exactly one of `self`, `optb` is `Set`, otherwise returns `Unset`.
174    #[inline]
175    pub fn xor(self, optb: Maybe<T>) -> Maybe<T> {
176        self.option().xor(optb.option()).into()
177    }
178
179    /// Inserts `v` into the option if it is `Unset`, then returns a mutable reference to the contained value.
180    #[inline]
181    pub fn get_or_insert(&mut self, v: T) -> &mut T {
182        if let Maybe::Unset = self {
183            *self = Maybe::Set(v);
184        }
185        match self {
186            Maybe::Set(ref mut v) => v,
187            Maybe::Unset => unreachable!(),
188        }
189    }
190
191    /// Inserts a value computed from `f` into the option if it is `Unset`, then returns a mutable reference to the contained value.
192    #[inline]
193    pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
194        if let Maybe::Unset = self {
195            *self = Maybe::Set(f());
196        }
197        match self {
198            Maybe::Set(ref mut v) => v,
199            Maybe::Unset => unreachable!(),
200        }
201    }
202
203    /// Takes the value out of the option, leaving an `Unset` in its place.
204    #[inline]
205    pub fn take(&mut self) -> Maybe<T> {
206        std::mem::replace(self, Maybe::Unset)
207    }
208
209    /// Replaces the actual value in the option by the value given in parameter, returning the old value if present.
210    #[inline]
211    pub fn replace(&mut self, value: T) -> Maybe<T> {
212        std::mem::replace(self, Maybe::Set(value))
213    }
214
215    /// Zips `self` with another `Maybe`.
216    #[inline]
217    pub fn zip<U>(self, other: Maybe<U>) -> Maybe<(T, U)> {
218        self.option().zip(other.option()).into()
219    }
220
221    /// Returns the contained `Set` value, consuming the `self` value, without checking that the value is not `Unset`.
222    ///
223    /// # Safety
224    ///
225    /// Calling this method on an `Unset` value is undefined behavior.
226    #[inline]
227    pub unsafe fn unwrap_unchecked(self) -> T {
228        self.option().unwrap_unchecked()
229    }
230
231    /// Maps a `Maybe<T>` to `U` by applying a function to a contained value, or returns a default.
232    #[inline]
233    pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
234        self.option().map_or(default, f)
235    }
236
237    /// Maps a `Maybe<T>` to `U` by applying a function to a contained value, or computes a default.
238    #[inline]
239    pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
240        self.option().map_or_else(default, f)
241    }
242
243    /// Returns the contained `Set` value or a default.
244    #[inline]
245    pub fn unwrap_or_default(self) -> T
246    where
247        T: Default,
248    {
249        self.option().unwrap_or_default()
250    }
251
252    /// Transforms the `Maybe<T>` into a `Result<T, E>`, mapping `Set(v)` to `Ok(v)` and `Unset` to `Err(err)`.
253    #[inline]
254    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
255        self.option().ok_or(err)
256    }
257
258    /// Transforms the `Maybe<T>` into a `Result<T, E>`, mapping `Set(v)` to `Ok(v)` and `Unset` to `Err(err())`.
259    #[inline]
260    pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
261        self.option().ok_or_else(err)
262    }
263}
264
265impl<T> From<Maybe<T>> for Option<T> {
266    #[inline]
267    fn from(value: Maybe<T>) -> Self {
268        match value {
269            Maybe::Set(s) => Some(s),
270            Maybe::Unset => None,
271        }
272    }
273}
274
275impl<T> From<Option<T>> for Maybe<T> {
276    #[inline]
277    fn from(value: Option<T>) -> Self {
278        match value {
279            Some(s) => Maybe::Set(s),
280            None => Maybe::Unset,
281        }
282    }
283}
284
285fn maybe_loader(
286    ctx: &mut MetaAssetLoadCtx,
287    ptr: SchemaRefMut<'_>,
288    deserialzer: &mut dyn erased_serde::Deserializer,
289) -> anyhow::Result<()> {
290    deserialzer.deserialize_option(MaybeVisitor { ctx, ptr })?;
291
292    Ok(())
293}
294
295struct MaybeVisitor<'a, 'srv> {
296    ctx: &'a mut MetaAssetLoadCtx<'srv>,
297    ptr: SchemaRefMut<'a>,
298}
299
300impl<'a, 'srv, 'de> serde::de::Visitor<'de> for MaybeVisitor<'a, 'srv> {
301    type Value = ();
302
303    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
304        write!(formatter, "an optional value")
305    }
306
307    fn visit_unit<E>(self) -> Result<Self::Value, E>
308    where
309        E: serde::de::Error,
310    {
311        Ok(())
312    }
313    fn visit_none<E>(self) -> Result<Self::Value, E>
314    where
315        E: serde::de::Error,
316    {
317        Ok(())
318    }
319
320    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
321    where
322        D: Deserializer<'de>,
323    {
324        // Write the enum discriminant for the `Set` variant
325        // SOUND: we know the discriminant due to the `#[repr(C, u8)]` annotation.
326        unsafe {
327            self.ptr.as_ptr().cast::<u8>().write(1);
328        }
329
330        // Get the pointer to the enum value
331        let value_offset = self.ptr.schema().field_offsets()[0].1;
332        // NOTE: we take the schema of the first argument of the second enum variant of the
333        // [`Maybe`] enum because we know that the `Set` variant only has one argument at offset 0
334        // and we actually want to deserialize the inner type, not a typle of length zero.
335        let value_schema = self.ptr.schema().kind.as_enum().unwrap().variants[1]
336            .schema
337            .kind
338            .as_struct()
339            .unwrap()
340            .fields[0]
341            .schema;
342        // SOUND: the schema asserts this is valid.
343        let value_ref = unsafe {
344            SchemaRefMut::from_ptr_schema(self.ptr.as_ptr().add(value_offset), value_schema)
345        };
346
347        // Load the enum value
348        SchemaPtrLoadCtx {
349            ctx: self.ctx,
350            ptr: value_ref,
351        }
352        .deserialize(deserializer)
353    }
354}