Skip to main content

fret_ui_assets/
lib.rs

1//! UI render asset conveniences (Image/SVG caches and upload helpers).
2//!
3//! This crate provides small caching layers for common UI render assets (images, SVGs) so
4//! components can avoid repeated decode/raster/upload work across frames.
5//!
6//! This is an ecosystem crate: it composes higher-level policies on top of the core runtime
7//! services. See ADR 0106.
8//!
9//! URL image note:
10//! - `ImageSource::from_url(...)` is a direct helper for URL-backed image loads on every platform.
11//! - For logical asset requests (`resolve_image_source*`), the shared image bridge can now consume
12//!   resolver-provided `AssetExternalReference::Url` on every platform.
13//! - The shipped desktop host still does not install a first-party default URL resolver; desktop
14//!   apps must opt in with a custom resolver if they want URL assets.
15//! - On Web/WASM, any `ImageSource::Url` now uses the browser's image loader/decoder before
16//!   readback into RGBA for GPU upload, so direct URL helpers and resolver-provided URL
17//!   references avoid the old `fetch bytes + Rust decode` lane.
18//! - The remaining first-party web limitation is the bytes-resolved logical-asset path:
19//!   when no resolver layer returns `AssetExternalReference::Url`, the UI asset bridge still falls
20//!   back to `ResolvedAssetBytes` and Rust-side decode, which can cost more CPU and memory than a
21//!   browser-native decode path on image-heavy surfaces.
22
23pub mod asset_resolver;
24pub mod image_asset_cache;
25pub mod image_asset_state;
26pub mod image_source;
27pub mod image_upload;
28pub mod svg_asset_cache;
29pub mod svg_asset_state;
30pub mod ui_assets;
31
32#[cfg(feature = "ui")]
33pub mod ui;
34
35pub use asset_resolver::*;
36pub use image_asset_cache::*;
37pub use image_source::*;
38pub use image_upload::*;
39pub use svg_asset_cache::*;
40pub use ui_assets::*;
41
42#[cfg(feature = "app-integration")]
43pub mod advanced;
44#[cfg(feature = "app-integration")]
45pub mod app;
46
47#[cfg(test)]
48mod surface_policy_tests {
49    const LIB_RS: &str = include_str!("lib.rs");
50    const APP_RS: &str = include_str!("app.rs");
51    const ADVANCED_RS: &str = include_str!("advanced.rs");
52    const IMAGE_SOURCE_RS: &str = include_str!("image_source.rs");
53    const UI_RS: &str = include_str!("ui.rs");
54    const ASSET_RESOLVER_RS: &str = include_str!("asset_resolver.rs");
55
56    fn public_surface() -> &'static str {
57        LIB_RS.split("#[cfg(test)]").next().unwrap_or(LIB_RS)
58    }
59
60    #[test]
61    fn app_integration_stays_under_explicit_app_module() {
62        let public_surface = public_surface();
63        assert!(public_surface.contains("pub mod app;"));
64        assert!(public_surface.contains("pub mod advanced;"));
65        assert!(!public_surface.contains("pub use app::"));
66        assert!(!public_surface.contains("pub use advanced::"));
67        assert!(!public_surface.contains("pub fn configure_caches("));
68        assert!(!public_surface.contains("pub fn configure_caches_with_budgets("));
69        assert!(!public_surface.contains("pub fn configure_caches_with_ui_services("));
70        assert!(!public_surface.contains("pub fn configure_caches_with_ui_services_and_budgets("));
71        assert!(APP_RS.contains("pub fn configure_caches(app: &mut fret_app::App)"));
72        assert!(APP_RS.contains("pub fn configure_caches_with_budgets("));
73        assert!(!APP_RS.contains("configure_caches_with_ui_services"));
74        assert!(ADVANCED_RS.contains("pub fn configure_caches_with_ui_services("));
75        assert!(ADVANCED_RS.contains("pub fn configure_caches_with_ui_services_and_budgets("));
76    }
77
78    #[test]
79    fn legacy_public_path_helpers_and_svg_file_shims_are_deleted() {
80        assert!(IMAGE_SOURCE_RS.contains("pub(crate) fn from_native_file_path("));
81        assert!(!IMAGE_SOURCE_RS.contains("pub fn from_file_path("));
82        assert!(!IMAGE_SOURCE_RS.contains("pub fn from_path("));
83        assert!(!public_surface().contains("pub mod svg_file;"));
84        assert!(!public_surface().contains("pub use svg_file::*;"));
85        assert!(!ASSET_RESOLVER_RS.contains("pub fn resolve_svg_file_source("));
86        assert!(!ASSET_RESOLVER_RS.contains("pub fn resolve_svg_file_source_from_host("));
87        assert!(!UI_RS.contains("pub trait SvgFileElementContextExt"));
88    }
89
90    #[test]
91    fn cache_setup_surface_keeps_only_explicit_configuration_names() {
92        assert!(APP_RS.contains("pub fn configure_caches(app: &mut fret_app::App)"));
93        assert!(APP_RS.contains("pub fn configure_caches_with_budgets("));
94        assert!(!APP_RS.contains("pub fn install(app: &mut fret_app::App)"));
95        assert!(!APP_RS.contains("pub fn install_with_budgets("));
96
97        assert!(ADVANCED_RS.contains("pub fn configure_caches_with_ui_services("));
98        assert!(ADVANCED_RS.contains("pub fn configure_caches_with_ui_services_and_budgets("));
99        assert!(!ADVANCED_RS.contains("pub fn install_with_ui_services("));
100        assert!(!ADVANCED_RS.contains("pub fn install_with_ui_services_and_budgets("));
101    }
102
103    #[test]
104    fn reload_surface_is_not_reexported_from_ui_assets() {
105        let public_surface = public_surface();
106        assert!(!public_surface.contains("pub mod reload;"));
107        assert!(!public_surface.contains("pub use reload::*;"));
108        assert!(!public_surface.contains("AssetReloadEpoch"));
109        assert!(!public_surface.contains("bump_asset_reload_epoch"));
110    }
111}