Skip to main content

xdg_thumbnail/
lib.rs

1// SPDX-FileCopyrightText: 2026 KIM Hyunjae
2// SPDX-License-Identifier: MPL-2.0
3
4//! Freedesktop thumbnail cache primitives.
5//!
6//! The library exposes typed helpers for resolving the personal thumbnail cache, constructing
7//! canonical original identities, validating existing thumbnails, and atomically installing
8//! caller-rendered thumbnail PNGs.
9//!
10//! ```no_run
11//! use xdg_thumbnail::{
12//!     PersonalCacheRoot, PersonalThumbnailLookup, ReadablePersonalOriginalIdentity, ThumbnailSize,
13//! };
14//!
15//! fn main() -> xdg_thumbnail::Result<()> {
16//!     let root = PersonalCacheRoot::resolve_from_env()?;
17//!     let original = ReadablePersonalOriginalIdentity::from_local_path("/home/alice/Pictures/photo.png")?;
18//!
19//!     match root.lookup_thumbnail_png_bytes(&original, ThumbnailSize::Normal)? {
20//!         PersonalThumbnailLookup::Valid(entry) => {
21//!             let _png_bytes = entry.png_bytes();
22//!         }
23//!         PersonalThumbnailLookup::Missing | PersonalThumbnailLookup::Invalid(_) => {}
24//!     }
25//!
26//!     Ok(())
27//! }
28//! ```
29//!
30//! Owned request types make it straightforward to wrap blocking filesystem work in an async
31//! runtime without adding a runtime dependency to this crate. Request constructors perform no
32//! filesystem I/O, but local original identity construction does, so build local identities inside
33//! the same blocking adapter.
34//!
35//! ```no_run
36//! use xdg_thumbnail::{
37//!     PersonalCacheRoot, PersonalThumbnailInstallRequest, ReadablePersonalOriginalIdentity, ThumbnailSize,
38//! };
39//!
40//! fn spawn_blocking<F, R>(operation: F) -> R
41//! where
42//!     F: FnOnce() -> R + Send + 'static,
43//!     R: Send + 'static,
44//! {
45//!     operation()
46//! }
47//!
48//! fn render_thumbnail_png() -> Vec<u8> {
49//!     unimplemented!("return PNG bytes produced by the caller's renderer")
50//! }
51//!
52//! fn main() -> xdg_thumbnail::Result<()> {
53//!     let root = PersonalCacheRoot::resolve_from_env()?;
54//!     let rendered_png = render_thumbnail_png();
55//!
56//!     let installed = spawn_blocking(move || {
57//!         let original =
58//!             ReadablePersonalOriginalIdentity::from_local_path("/home/alice/Pictures/photo.png")?;
59//!         let request = PersonalThumbnailInstallRequest::new(
60//!             root,
61//!             original,
62//!             ThumbnailSize::Normal,
63//!             rendered_png,
64//!         );
65//!         request.install_png_bytes()
66//!     })?;
67//!     let _path = installed.path();
68//!
69//!     Ok(())
70//! }
71//! ```
72
73#[cfg(not(unix))]
74compile_error!(
75    "xdg-thumbnail supports Unix-like targets only because thumbnail identity and cache safety depend on Unix path bytes, metadata, and permissions"
76);
77
78#[cfg(unix)]
79mod cache;
80#[cfg(unix)]
81mod error;
82#[cfg(unix)]
83mod identity;
84#[cfg(unix)]
85mod inspection;
86#[cfg(unix)]
87mod namespace;
88#[cfg(unix)]
89mod png;
90#[cfg(unix)]
91mod uri;
92
93#[cfg(unix)]
94pub use cache::{
95    DisplayThumbnailRgba8LookupEntry, DisplayThumbnailRgba8LookupEntryParts,
96    FailureEntryInspectionRequest, FailureEntryInspectionRequestParts, FailureEntryWriteRequest,
97    FailureEntryWriteRequestParts, InstalledThumbnailPath, InstalledThumbnailPngBytes,
98    InstalledThumbnailPngBytesParts, MaterializedThumbnailPath, MaterializedThumbnailPathParts,
99    MaterializedThumbnailPngBytes, MaterializedThumbnailPngBytesParts, PersonalCacheRoot,
100    PersonalThumbnailInspectionRequest, PersonalThumbnailInspectionRequestParts,
101    PersonalThumbnailInstallRequest, PersonalThumbnailInstallRequestParts, PersonalThumbnailLookup,
102    PersonalThumbnailLookupRequest, PersonalThumbnailLookupRequestParts,
103    PersonalThumbnailMaterializationRequest, PersonalThumbnailMaterializationRequestParts,
104    PersonalThumbnailRawInstallRequest, PersonalThumbnailRawInstallRequestParts,
105    SharedCacheEntryInspection, SharedCacheEntryInspectionParts, SharedCacheEntryOutcome,
106    SharedOriginalFacts, SharedOriginalMetadata, SharedThumbnailInspectionRequest,
107    SharedThumbnailInspectionRequestParts, SharedThumbnailLookup, SharedThumbnailLookupRequest,
108    SharedThumbnailLookupRequestParts, SharedThumbnailMetadataPolicy,
109    SharedToPersonalThumbnailMaterializationRequest,
110    SharedToPersonalThumbnailMaterializationRequestParts, ThumbnailPathLookupEntry,
111    ThumbnailPathLookupEntryParts, ThumbnailPngBytesLookupEntry, ThumbnailPngBytesLookupEntryParts,
112    ThumbnailRgba8LookupEntry, ThumbnailRgba8LookupEntryParts,
113};
114#[cfg(unix)]
115pub use error::{
116    CacheDirectoryProblem, CachePathProblem, CacheRootProblem, Result, ThumbnailError,
117};
118#[cfg(unix)]
119pub use identity::{
120    PersonalOriginalIdentity, ReadablePersonalOriginalIdentity, SharedRepositoryContext,
121    UnixMtimeSeconds,
122};
123#[cfg(unix)]
124pub use inspection::{
125    AccessTimePreservation, CacheEntryHandle, CacheEntryInspection, CacheEntryInspectionOutcome,
126    CacheEntryInspectionParts, NonstandardEntryPolicy, OriginalUriIdentity, ThumbnailTimestamps,
127};
128#[cfg(unix)]
129pub use namespace::{CacheNamespace, FailureNamespace, ThumbnailSize};
130#[cfg(unix)]
131pub use png::{
132    CacheEntryProblem, OwnedRawThumbnailImage, OwnedRawThumbnailImageParts, ParsedThumbnailPng,
133    ParsedThumbnailPngParts, PersonalValidationOutcome, RawThumbnailImage, RawThumbnailPixelFormat,
134    SharedValidationOutcome, ThumbnailMetadata, ThumbnailMetadataKey, ThumbnailMetadataProblem,
135    ThumbnailMetadataProblemKind, ThumbnailPngBitDepth, ThumbnailPngColorType,
136    validate_personal_failure_entry, validate_personal_thumbnail, validate_shared_thumbnail,
137};
138#[cfg(unix)]
139pub use uri::{PersonalOriginalUri, SharedRelativeOriginalUri};
140
141#[cfg(unix)]
142pub(crate) use png::{
143    decode_validated_thumbnail_png_to_rgba8, downscaled_validated_thumbnail_png_to_rgba8,
144    encode_rgba_png, metadata_problem, normalized_personal_thumbnail_from_cache_png,
145    normalized_personal_thumbnail_png, normalized_personal_thumbnail_raw_png, push_problem,
146    thumbnail_metadata_pairs, validate_mime_type,
147};