-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathbundle.rs
111 lines (101 loc) · 3.4 KB
/
bundle.rs
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
//! Bundle asset
use crate::{assets::resource, ResourceAsset};
use anyhow::Result;
use bevy::{
asset::{AssetLoader, AssetPath, LoadContext, LoadedAsset},
prelude::*,
reflect::{TypePath, TypeUuid},
utils::{
tracing::{self, instrument},
BoxedFuture,
},
};
use fluent::{bundle::FluentBundle, FluentResource};
use intl_memoizer::concurrent::IntlLangMemoizer;
use serde::Deserialize;
use std::{ops::Deref, path::PathBuf, str, sync::Arc};
use unic_langid::LanguageIdentifier;
#[instrument(fields(path = %load_context.path().display()), ret, skip_all)]
async fn load(data: Data, load_context: &mut LoadContext<'_>) -> Result<()> {
let mut bundle = FluentBundle::new_concurrent(vec![data.locale.clone()]);
let mut asset_paths = Vec::new();
let parent = load_context.path().parent();
for mut path in data.resources {
if path.is_relative() {
if let Some(parent) = parent {
path = parent.join(path);
}
}
let bytes = load_context.read_asset_bytes(&path).await?;
let resource = resource::deserialize(&bytes)?;
if let Err(errors) = bundle.add_resource(resource) {
warn_span!("add_resource").in_scope(|| {
for error in errors {
warn!(%error);
}
});
}
asset_paths.push(AssetPath::new(path, None));
}
let resource_handles = asset_paths
.iter()
.map(|path| load_context.get_handle(path.clone()))
.collect::<Vec<_>>();
load_context.set_default_asset(
LoadedAsset::new(BundleAsset {
bundle: Arc::new(bundle),
resource_handles,
})
.with_dependencies(asset_paths),
);
Ok(())
}
/// [`FluentBundle`](fluent::bundle::FluentBundle) wrapper
///
/// Collection of [`FluentResource`]s for a single locale
#[derive(Clone, TypePath, TypeUuid)]
#[uuid = "929113bb-9187-44c3-87be-6027fc3b7ac5"]
pub struct BundleAsset {
pub(crate) bundle: Arc<FluentBundle<Arc<FluentResource>, IntlLangMemoizer>>,
/// The resource handles that this bundle depends on
pub(crate) resource_handles: Vec<Handle<ResourceAsset>>,
}
impl Deref for BundleAsset {
type Target = FluentBundle<Arc<FluentResource>, IntlLangMemoizer>;
fn deref(&self) -> &Self::Target {
&self.bundle
}
}
/// [`AssetLoader`](bevy::asset::AssetLoader) implementation for [`BundleAsset`]
#[derive(Default)]
pub struct BundleAssetLoader;
impl AssetLoader for BundleAssetLoader {
fn load<'a>(
&self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<()>> {
Box::pin(async move {
let path = load_context.path();
match path.extension() {
Some(extension) if extension == "ron" => {
load(ron::de::from_bytes(bytes)?, load_context).await
}
Some(extension) if extension == "yaml" || extension == "yml" => {
load(serde_yaml::from_slice(bytes)?, load_context).await
}
_ => unreachable!("We already check all the supported extensions."),
}
})
}
fn extensions(&self) -> &[&str] {
&["ftl.ron", "ftl.yaml", "ftl.yml"]
}
}
/// Data
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct Data {
locale: LanguageIdentifier,
resources: Vec<PathBuf>,
}