assets_manager_rodio/
lib.rs

1//! `rodio` integration for `assets_manager`
2//!
3//! This crate provides wrappers around `rodio` sounds types that implement
4//! `assets_manager` traits.
5
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![warn(missing_docs, missing_debug_implementations)]
8#![forbid(unsafe_code)]
9
10use assets_manager::{BoxedError, FileAsset, SharedBytes};
11use rodio::decoder::{Decoder, DecoderError};
12use std::{borrow::Cow, io};
13
14#[cfg(test)]
15mod tests;
16
17const AVAILABLE_EXTENSIONS: &[&str] = &[
18    #[cfg(any(feature = "vorbis", feature = "lewton"))]
19    "ogg",
20    #[cfg(any(feature = "mp3", feature = "minimp3"))]
21    "mp3",
22    #[cfg(any(feature = "flac", feature = "claxon"))]
23    "flac",
24    #[cfg(any(feature = "wav", feature = "hound"))]
25    "wav",
26];
27
28macro_rules! sound_assets {
29    (
30        $(
31            #[doc = $doc:literal]
32            $( #[cfg( $( $cfg:tt )* )] )?
33            struct $name:ident => (
34                $decoder:path,
35                $ext:expr,
36            );
37        )*
38    ) => {
39        $(
40            #[doc = $doc]
41            $( #[cfg($($cfg)*)] )?
42            $( #[cfg_attr(docsrs, doc(cfg($($cfg)*)))] )?
43            #[derive(Clone, Debug)]
44            pub struct $name(SharedBytes);
45
46            $( #[cfg($($cfg)*)] )?
47            $( #[cfg_attr(docsrs, doc(cfg($($cfg)*)))] )?
48            impl FileAsset for $name {
49                const EXTENSIONS: &'static [&'static str] = $ext;
50
51                fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, BoxedError> {
52                    Ok($name::new(bytes.into())?)
53                }
54            }
55
56            $( #[cfg($($cfg)*)] )?
57            impl $name {
58                /// Creates a new sound from raw bytes.
59                #[inline]
60                pub fn new(bytes: SharedBytes) -> Result<$name, DecoderError> {
61                    // We have to clone the bytes here because `Decoder::new`
62                    // requires a 'static lifetime, but it should be cheap
63                    // anyway.
64                    let _ = $decoder(io::Cursor::new(bytes.clone()))?;
65                    Ok($name(bytes))
66                }
67
68                /// Creates a [`Decoder`] that can be send to `rodio` to play
69                /// sounds.
70                #[inline]
71                pub fn decoder(self) -> Decoder<io::Cursor<SharedBytes>> {
72                    $decoder(io::Cursor::new(self.0)).unwrap()
73                }
74
75                #[inline]
76                /// Returns a bytes slice of the sound content.
77                pub fn as_bytes(&self) -> &[u8] {
78                    &self.0
79                }
80
81                /// Convert the sound back to raw bytes.
82                #[inline]
83                pub fn into_bytes(self) -> SharedBytes {
84                    self.0
85                }
86            }
87
88            $( #[cfg($($cfg)*)] )?
89            impl AsRef<[u8]> for $name {
90                fn as_ref(&self) -> &[u8] {
91                    &self.0
92                }
93            }
94        )*
95    }
96}
97
98sound_assets! {
99    /// Loads FLAC sounds
100    #[cfg(any(feature = "flac", feature = "claxon"))]
101    struct Flac => (
102        Decoder::new_flac,
103        &["flac"],
104    );
105
106    /// Loads MP3 sounds
107    #[cfg(any(feature = "mp3", feature = "minimp3"))]
108    struct Mp3 => (
109        Decoder::new_mp3,
110        &["mp3"],
111    );
112
113    /// Loads Vorbis sounds
114    #[cfg(any(feature = "vorbis", feature = "lewton"))]
115    struct Vorbis => (
116        Decoder::new_vorbis,
117        &["ogg"],
118    );
119
120    /// Loads WAV sounds
121    #[cfg(any(feature = "wav", feature = "hound"))]
122    struct Wav => (
123        Decoder::new_wav,
124        &["wav"],
125    );
126
127    /// Loads sounds of any enabled kind
128    struct Sound => (
129        Decoder::new,
130        AVAILABLE_EXTENSIONS,
131    );
132}