Skip to main content

Crate lumen_assets

Crate lumen_assets 

Source
Expand description

Async asset pipeline with a content-addressed handle cache.

  • spawn_pending_decodes picks up entities tagged with ImageSource and consults the global cache on AssetServer.
  • On a cache hit, the existing decoded Handle is cloned in (Arc bump, no decode runs).
  • On a cold miss, the request is pushed onto a bounded crossbeam-channel job queue drained by an N-worker thread pool (N = available_parallelism().min(4)). Subsequent entities requesting the same path join a pending fan-out list.
  • Every request carries a monotonic per-entity request_id; results whose id no longer matches the entity’s current id are discarded on completion. This kills the stale-decode race after rapid ScriptCommand::SetSrc storms.
  • What a path decodes into is decided by the loader registry: each AssetLoader claims file extensions and produces one AssetKind, and the built-in image and SVG paths are ordinary registered loaders. An app or plugin adds a format by registering another one; see register_asset_loader.
  • Where the bytes come from is decided by the AssetSource list, consulted before the job is queued. BundleSource (.lpak archives, lumen://app/... URIs) is installed by default.
  • drain_completed_decodes delivers the resulting Handle to every still-valid waiter; failures attach ImageLoadFailed carrying a typed LoadErrorKind.
  • Attaching a decoded payload raises lumen_core::render_world::FrameDirty. An asset is the one piece of scene content that arrives ticks after the tree it belongs to, and a tick whose frame is not dirty is never extracted, so without the raise the arrival would wait for an unrelated repaint.
  • keep_frame_loop_awake_for_assets holds an event-driven loop open while an ImageSource in the tree has no verdict on it yet, so an element that enters the tree after spawn_pending_decodes has run is looked up on the next tick rather than at the next unrelated event. The claim is keyed on the element, so it retires when the element has its content or leaves the tree.
  • Handles are strong Arcs to decoded data; the cache holds Handle<T> entries that share identity across consumers.
  • A renderer’s image upload cache is keyed by the underlying peniko::Blob identity, so identical handles short-circuit the upload.
  • A [notify::RecommendedWatcher] tracks every loaded file URL. On change the asset cache invalidates the affected entry, the request id of every entity referencing that path is bumped, and an AssetReloadRequested message fires. reload_changed_images is the consumer that re-enqueues the load; the runtime installs it for a hot-reload session. The watcher wakes a parked frame loop so the change is picked up without waiting for input.

Eviction is true LRU bounded by max_bytes (default 256 MiB). Insert / evict mutate a running bytes_used: usize in O(1); a debug_assert! reconciles the running counter against a full sweep at most once per second when debug assertions are on.

Re-exports§

pub use bundle::BundleError;
pub use bundle::LumenBundle;
pub use bundle::parse_lumen_uri;
pub use loader::AssetKind;
pub use loader::AssetLoader;
pub use loader::AssetLoaders;
pub use loader::LoadContext;
pub use loader::LoadedAsset;
pub use loader::asset_extension;
pub use loaders::ImageLoader;
pub use loaders::SvgLoader;
pub use source::AssetSource;
pub use source::BundleSource;
pub use source::SourceReader;

Modules§

bundle
.lpak resource bundle: a zip-like archive that ships an entire Lumen app’s assets (main.lmn, main.css, scripts, images, fonts) as a single file. Mirrors Qt’s qrc and GTK’s GResource.
loader
How a source path becomes a decoded asset.
loaders
The loaders the asset pipeline ships with.
source
Where an asset’s bytes come from before a loader sees them.

Structs§

AssetReloadRequested
Message fired when a watched asset file changes on disk. reload_changed_images reacts by stripping LoadedImage / LoadedSvg / ImageLoadFailed / Enqueued from every entity whose ImageSource matches path so the pipeline re-enqueues the load. The runtime installs that consumer only for a hot-reload session.
AssetServer
Background-thread plumbing and content cache for the asset pipeline.
AssetsPlugin
Plugin that installs AssetServer and registers spawn_pending_decodes, drain_completed_decodes, process_watch_events, and the image/SVG extract fns.
BackgroundImage
Marks an element whose ImageSource is its background (bg: url(...)) rather than its content. The image loads and caches like any other source; it paints behind the element’s content, clipped to its box, and never sizes the element.
Enqueued
Marker component on entities whose decode has been enqueued; excluded from the spawn_pending_decodes query.
ExtractedImageBlob
Render-world sidecar carrying a pre-built peniko::Blob for an extracted image. Queried alongside ExtractedImage by the renderer so the Blob reaches the painter unchanged, preserving its upload-cache identity.
ExtractedSvg
One SVG to draw this frame. Defined in lumen-assets (not lumen-core) because the payload carries the parsed usvg tree.
Handle
Strong, content-addressed handle to a decoded asset.
ImageData
Decoded image payload in RGBA8 with top-left origin.
ImageLoadFailed
Attached to the entity when its image fails to decode. Carries the typed LoadErrorKind and a human-readable detail string.
ImageSource
Source path for an image asset, spawned by <image src="..."> in markup. Replaced by LoadedImage (or ImageLoadFailed) once the asset plugin finishes decoding.
LoadedImage
Strong handle to a decoded image, attached as a component once <image src="..."> resolves. Implements Deref<Target = ImageData> so field access (img.width, img.blob) flows through to the inner payload.
LoadedSvg
Strong handle to a decoded SVG, with Deref<Target = SvgData> enabling field access (svg.intrinsic, svg.tree).
PixBytes
Newtype wrapper holding an Arc<[u8]> and implementing AsRef<[u8]> so it can be passed to peniko::Blob::new, which requires Arc<T: ?Sized + AsRef<[u8]> + Send + Sync>.
RequestId
Monotonic per-entity asset request id. Attached to every entity carrying an ImageSource. Every ScriptCommand::SetSrc runs through AssetServer::bump_request_id which increments this counter; in-flight decode jobs carrying an older id are discarded on completion.
SvgData
Parsed SVG payload produced once at decode time and shared per-frame via Handle<SvgData> clones.

Enums§

LoadErrorKind
Typed asset load-failure category.

Constants§

DEFAULT_MAX_BYTES
Default max bytes held across the image + SVG content caches (256 MiB). Override with AssetServer::with_max_bytes.

Traits§

AssetSize
Implemented by asset payload types so the cache can budget memory.

Functions§

drain_completed_decodes
Drains completed decodes from the result channel.
extract_loaded_images
Extracts every (Transform, LoadedImage) entity into a paired ExtractedImage + ExtractedImageBlob in the render world. Clones the Blob (Arc-cheap) so the renderer’s upload-cache identity is preserved across frames.
extract_loaded_svgs
Extracts every (Transform, LoadedSvg) entity into an ExtractedSvg in the render world via keyed upsert. Despawns prior-frame render entries whose source entity no longer matches.
keep_frame_loop_awake_for_assets
Keeps the frame loop scheduled while an element is still waiting on the content it named.
process_watch_events
Drains filesystem-watch events and invalidates the cache for every changed path.
register_asset_loader
Registers an AssetLoader from a plugin’s build, installing the AssetServer first if this plugin runs before AssetsPlugin.
reload_changed_images
Re-enqueues the load for every element showing a file that changed on disk.
resolve_source_path
The path an authored asset reference loads from: a lumen:// URI as written, anything else resolved against the app directory.
spawn_pending_decodes
Consults the content cache for each ImageSource entity lacking a LoadedImage, LoadedSvg, ImageLoadFailed, or Enqueued. Cache hits attach the cached component synchronously; misses enqueue one decode job and append the entity (with its current request_id) to the fan-out list.
stamp_image_natural_size
D6: stamp the decoded bitmap’s intrinsic size onto lumen_core::components::ImageComponent as soon as a LoadedImage lands on the entity (cache hit or decode completion - both surface as Added/Changed<LoadedImage>).