Add AnyAssetSource

This commit is contained in:
Marshall Bowers 2023-10-24 16:59:01 +02:00
parent 191285a8f1
commit 9f8aaa4cdb
6 changed files with 48 additions and 27 deletions

View file

@ -13,7 +13,7 @@ use crate::{
ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId,
KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point,
SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement,
TextSystem, View, Window, WindowContext, WindowHandle, WindowId, TextSystem, View, Window, WindowContext, WindowHandle, WindowId, AnyAssetSource,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
@ -66,6 +66,8 @@ impl App {
os_version: platform.os_version().ok(), os_version: platform.os_version().ok(),
app_version: platform.app_version().ok(), app_version: platform.app_version().ok(),
}; };
let asset_source = AnyAssetSource(asset_source);
Self(Arc::new_cyclic(|this| { Self(Arc::new_cyclic(|this| {
Mutex::new(AppContext { Mutex::new(AppContext {
this: this.clone(), this: this.clone(),
@ -76,7 +78,8 @@ impl App {
pending_updates: 0, pending_updates: 0,
next_frame_callbacks: Default::default(), next_frame_callbacks: Default::default(),
executor, executor,
svg_renderer: SvgRenderer::new(asset_source), svg_renderer: SvgRenderer::new(asset_source.clone()),
asset_source,
image_cache: ImageCache::new(http_client), image_cache: ImageCache::new(http_client),
text_style_stack: Vec::new(), text_style_stack: Vec::new(),
globals_by_type: HashMap::default(), globals_by_type: HashMap::default(),
@ -179,6 +182,7 @@ pub struct AppContext {
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>, pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
pub(crate) executor: Executor, pub(crate) executor: Executor,
pub(crate) svg_renderer: SvgRenderer, pub(crate) svg_renderer: SvgRenderer,
asset_source: AnyAssetSource,
pub(crate) image_cache: ImageCache, pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>, pub(crate) text_style_stack: Vec<TextStyleRefinement>,
pub(crate) globals_by_type: HashMap<TypeId, AnyBox>, pub(crate) globals_by_type: HashMap<TypeId, AnyBox>,
@ -506,6 +510,10 @@ impl AppContext {
}); });
} }
pub fn asset_source(&self) -> &AnyAssetSource {
&self.asset_source
}
pub fn text_system(&self) -> &Arc<TextSystem> { pub fn text_system(&self) -> &Arc<TextSystem> {
&self.text_system &self.text_system
} }

View file

@ -5,23 +5,37 @@ use std::{
borrow::Cow, borrow::Cow,
fmt, fmt,
hash::Hash, hash::Hash,
sync::atomic::{AtomicUsize, Ordering::SeqCst}, sync::{atomic::{AtomicUsize, Ordering::SeqCst}, Arc},
}; };
pub trait AssetSource: 'static + Send + Sync { pub trait AssetSource: 'static + Send + Sync {
fn load(&self, path: &SharedString) -> Result<Cow<[u8]>>; fn load(&self, path: SharedString) -> Result<Cow<[u8]>>;
fn list(&self, path: &SharedString) -> Result<Vec<SharedString>>; fn list(&self, path: SharedString) -> Result<Vec<SharedString>>;
} }
#[derive(Clone)]
pub struct AnyAssetSource(pub(crate) Arc<dyn AssetSource>);
impl AnyAssetSource {
pub fn load(&self, path: impl Into<SharedString>) -> Result<Cow<[u8]>> {
self.0.load(path.into())
}
pub fn list(&self, path: impl Into<SharedString>) -> Result<Vec<SharedString>> {
self.0.list(path.into())
}
}
impl AssetSource for () { impl AssetSource for () {
fn load(&self, path: &SharedString) -> Result<Cow<[u8]>> { fn load(&self, path: SharedString) -> Result<Cow<[u8]>> {
Err(anyhow!( Err(anyhow!(
"get called on empty asset provider with \"{}\"", "get called on empty asset provider with \"{}\"",
path path
)) ))
} }
fn list(&self, _path: &SharedString) -> Result<Vec<SharedString>> { fn list(&self, _path: SharedString) -> Result<Vec<SharedString>> {
Ok(vec![]) Ok(vec![])
} }
} }

View file

@ -1,7 +1,6 @@
use crate::{AssetSource, DevicePixels, IsZero, Result, SharedString, Size}; use crate::{DevicePixels, IsZero, Result, SharedString, Size, AnyAssetSource};
use anyhow::anyhow; use anyhow::anyhow;
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc;
#[derive(Clone, PartialEq, Hash, Eq)] #[derive(Clone, PartialEq, Hash, Eq)]
pub struct RenderSvgParams { pub struct RenderSvgParams {
@ -10,11 +9,11 @@ pub struct RenderSvgParams {
} }
pub struct SvgRenderer { pub struct SvgRenderer {
asset_source: Arc<dyn AssetSource>, asset_source: AnyAssetSource,
} }
impl SvgRenderer { impl SvgRenderer {
pub fn new(asset_source: Arc<dyn AssetSource>) -> Self { pub fn new(asset_source: AnyAssetSource) -> Self {
Self { asset_source } Self { asset_source }
} }
@ -24,7 +23,7 @@ impl SvgRenderer {
} }
// Load the tree. // Load the tree.
let bytes = self.asset_source.load(&params.path)?; let bytes = self.asset_source.load(params.path.clone())?;
let tree = usvg::Tree::from_data(&bytes, &usvg::Options::default())?; let tree = usvg::Tree::from_data(&bytes, &usvg::Options::default())?;
// Render the SVG to a pixmap with the specified width and height. // Render the SVG to a pixmap with the specified width and height.

View file

@ -15,13 +15,13 @@ use rust_embed::RustEmbed;
pub struct Assets; pub struct Assets;
impl AssetSource for Assets { impl AssetSource for Assets {
fn load(&self, path: &SharedString) -> Result<Cow<[u8]>> { fn load(&self, path: SharedString) -> Result<Cow<[u8]>> {
Self::get(path.as_ref()) Self::get(path.as_ref())
.map(|f| f.data) .map(|f| f.data)
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path)) .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
} }
fn list(&self, path: &SharedString) -> Result<Vec<SharedString>> { fn list(&self, path: SharedString) -> Result<Vec<SharedString>> {
Ok(Self::iter() Ok(Self::iter()
.filter(|p| p.starts_with(path.as_ref())) .filter(|p| p.starts_with(path.as_ref()))
.map(SharedString::from) .map(SharedString::from)

View file

@ -10,7 +10,7 @@ use std::sync::Arc;
use clap::Parser; use clap::Parser;
use gpui2::{ use gpui2::{
div, px, size, view, AnyView, AppContext, AssetSource, Bounds, Context, Element, ViewContext, div, px, size, view, AnyView, AppContext, Bounds, Context, Element, ViewContext,
WindowBounds, WindowOptions, WindowBounds, WindowOptions,
}; };
use log::LevelFilter; use log::LevelFilter;
@ -104,12 +104,11 @@ impl StoryWrapper {
} }
fn load_embedded_fonts(cx: &AppContext) -> gpui2::Result<()> { fn load_embedded_fonts(cx: &AppContext) -> gpui2::Result<()> {
let font_paths = Assets.list(&"fonts".into())?; let font_paths = cx.asset_source().list("fonts")?;
let mut embedded_fonts = Vec::new(); let mut embedded_fonts = Vec::new();
for font_path in &font_paths { for font_path in font_paths {
if font_path.ends_with(".ttf") { if font_path.ends_with(".ttf") {
let font_path = &*font_path; let font_bytes = cx.asset_source().load(font_path)?.to_vec();
let font_bytes = Assets.load(font_path)?.to_vec();
embedded_fonts.push(Arc::from(font_bytes)); embedded_fonts.push(Arc::from(font_bytes));
} }
} }

View file

@ -67,8 +67,6 @@ fn main() {
let session_id = Uuid::new_v4().to_string(); let session_id = Uuid::new_v4().to_string();
init_panic_hook(&app, installation_id.clone(), session_id.clone()); init_panic_hook(&app, installation_id.clone(), session_id.clone());
load_embedded_fonts(&app);
let fs = Arc::new(RealFs); let fs = Arc::new(RealFs);
let user_settings_file_rx = let user_settings_file_rx =
watch_config_file(&app.executor(), fs.clone(), paths::SETTINGS.clone()); watch_config_file(&app.executor(), fs.clone(), paths::SETTINGS.clone());
@ -101,6 +99,7 @@ fn main() {
app.run(move |cx| { app.run(move |cx| {
cx.set_global(*RELEASE_CHANNEL); cx.set_global(*RELEASE_CHANNEL);
load_embedded_fonts(cx);
let mut store = SettingsStore::default(); let mut store = SettingsStore::default();
store store
@ -635,10 +634,12 @@ fn collect_url_args() -> Vec<String> {
.collect() .collect()
} }
fn load_embedded_fonts(app: &App) { fn load_embedded_fonts(cx: &AppContext) {
let font_paths = Assets.list(&"fonts".into()).unwrap(); let asset_source = cx.asset_source();
let font_paths = asset_source.list("fonts").unwrap();
let embedded_fonts = Mutex::new(Vec::new()); let embedded_fonts = Mutex::new(Vec::new());
let executor = app.executor(); let executor = cx.executor();
executor.block(executor.scoped(|scope| { executor.block(executor.scoped(|scope| {
for font_path in &font_paths { for font_path in &font_paths {
if !font_path.ends_with(".ttf") { if !font_path.ends_with(".ttf") {
@ -646,13 +647,13 @@ fn load_embedded_fonts(app: &App) {
} }
scope.spawn(async { scope.spawn(async {
let font_path = &*font_path; let font_bytes = asset_source.load(font_path).unwrap().to_vec();
let font_bytes = Assets.load(font_path).unwrap().to_vec();
embedded_fonts.lock().push(Arc::from(font_bytes)); embedded_fonts.lock().push(Arc::from(font_bytes));
}); });
} }
})); }));
app.text_system()
cx.text_system()
.add_fonts(&embedded_fonts.into_inner()) .add_fonts(&embedded_fonts.into_inner())
.unwrap(); .unwrap();
} }