Skip to main content

cranpose_services/
lib.rs

1//! Multiplatform service abstractions used by Cranpose applications.
2
3#![deny(unsafe_code)]
4
5#[cfg(test)]
6use cranpose_core::{location_key, Composition, MemoryApplier};
7
8pub mod app_info;
9pub mod app_update;
10pub mod async_io;
11pub mod audio;
12pub mod background;
13pub mod bundled_assets;
14pub mod camera;
15pub mod content;
16pub mod device_info;
17pub mod file_picker;
18#[cfg(not(target_arch = "wasm32"))]
19pub mod github_release_updater;
20pub mod haptics;
21pub mod host;
22pub mod host_surface;
23pub mod http;
24pub mod image_picker;
25pub mod incoming_share;
26pub mod launch_args;
27pub mod launcher;
28pub mod media;
29pub mod navigation;
30pub mod network_status;
31pub mod notifier;
32#[cfg(not(target_arch = "wasm32"))]
33pub mod peer;
34pub mod power;
35pub mod preferences;
36pub mod purchases;
37mod registry;
38pub mod share_sheet;
39pub mod theme;
40pub mod uri_handler;
41pub mod writable_folder;
42
43pub use app_info::{
44    app_info, build_version, clear_platform_app_info, set_platform_app_info, version_name, AppInfo,
45    AppInfoRef,
46};
47pub use app_update::{
48    app_update_capabilities, app_update_checks_supported, app_update_status, app_updates_supported,
49    check_for_app_update, clear_platform_app_updater, install_app_update,
50    observe_app_update_status, set_app_update_status, set_platform_app_updater, sha256_hex,
51    verify_package, AppUpdateCapabilities, AppUpdateError, AppUpdateObserver, AppUpdateStatus,
52    AppUpdater, AppUpdaterRef, DigestAlgorithm, DigestVerifier, GitHubReleaseUpdate, PackageDigest,
53    UpdatePackage,
54};
55pub use async_io::{ChunkChannel, ChunkNext, ChunkStream, Signal, SignalWait, MAX_PENDING_CHUNKS};
56pub use audio::{
57    clear_platform_audio, default_audio, local_audio, rememberSoundBank, set_platform_audio,
58    AudioBus, AudioClip, AudioError, AudioPlayer, AudioPlayerRef, NoopAudioPlayer, PlaybackParams,
59    ProvideAudio, SoundBank, SoundBankEntry, SoundBankFailure, SoundId, SoundSpec, VoiceId,
60};
61pub use background::{
62    acquire_background_work, background_active, background_activity,
63    clear_platform_background_activity, set_platform_background_activity, BackgroundActivity,
64    BackgroundActivityRef, BackgroundWorkLease,
65};
66pub use bundled_assets::{
67    bundled_assets, clear_platform_bundled_assets, set_platform_bundled_assets, BundledAssetError,
68    BundledAssetReader, BundledAssets, BundledAssetsRef, StreamingAssetReader,
69};
70#[cfg(not(target_arch = "wasm32"))]
71pub use bundled_assets::{
72    install_bundled_asset_set, BundledAssetEntry, BundledAssetInstallOutcome,
73    BundledAssetInstallSpec,
74};
75pub use camera::{
76    camera, camera_state, camera_supported, capture_camera_still, clear_platform_camera,
77    dropped_camera_frames, latest_camera_frame, observe_camera_frames, observe_camera_state,
78    observe_camera_stills, publish_camera_frame, publish_camera_state, publish_camera_still,
79    record_dropped_camera_frame, rememberCameraFrames, rememberCameraState, rememberCameraStills,
80    request_camera_still, set_platform_camera, start_camera, stop_camera, Camera, CameraError,
81    CameraFrame, CameraLens, CameraObserver, CameraRef, CameraState, CameraStill, FlashMode,
82    FrameFormat,
83};
84pub use content::{
85    clear_platform_content_resolver, collect_stream, drain_reader, folder_files, resolve_content,
86    set_platform_content_resolver, write_all, BytesContent, Content, ContentChannel, ContentEntry,
87    ContentError, ContentFolder, ContentFolderRef, ContentFuture, ContentHandle, ContentMetadata,
88    ContentReader, ContentReaderRef, ContentResolver, ContentResolverRef, ContentSink,
89    ContentSinkRef, ContentStream, ContentStreamRef, ReadyFolder, DEFAULT_CHUNK_LEN,
90};
91#[cfg(not(target_arch = "wasm32"))]
92pub use content::{file_content, file_folder, FileContent, FileFolder, FileSink};
93pub use content::{percent_decode, percent_decode_lossy};
94pub use device_info::{
95    clear_platform_device_info, device_info, release_free_memory, set_platform_device_info,
96    DeviceInfo, DeviceInfoRef,
97};
98pub use file_picker::{
99    clear_platform_file_picker, default_file_picker, local_file_picker, set_platform_file_picker,
100    FileFilter, FilePicker, FilePickerError, FilePickerOptions, FilePickerRef, PickerFuture,
101    ProvideFilePicker, RecoveredPick, SaveDocumentRequest,
102};
103#[cfg(not(target_arch = "wasm32"))]
104pub use github_release_updater::GitHubAppUpdater;
105pub use haptics::{
106    clear_platform_haptics, default_haptics, local_haptics, set_platform_haptics, HapticEffect,
107    HapticError, HapticFeedback, HapticPattern, Haptics, HapticsRef, ProvideHaptics,
108};
109pub use host::{
110    application_directories, application_id, background_app, clear_application_id,
111    clear_host_controller, current_lifecycle_state, dispatch_lifecycle, dispatch_lifecycle_state,
112    exit_app, host_controller, local_lifecycle_state, observe_lifecycle, register_durable_save,
113    rememberLifecycleEvents, rememberLifecycleState, set_application_id, set_host_controller,
114    set_keep_screen_on, DurableSaveEffect, DurableSaveOutcome, DurableSaveRegistration,
115    HostController, HostControllerRef, LifecycleEvent, LifecycleObserver, LifecycleState,
116    PlatformDirectories, PlatformDirectoryError, ProvideLifecycle, DEFAULT_DURABLE_SAVE_DEADLINE,
117};
118#[cfg(not(target_arch = "wasm32"))]
119pub use host::{durable_save_deadline, run_durable_saves};
120pub use host_surface::{
121    clear_platform_host_surface, host_surface, host_surface_size, observe_host_surface_size,
122    publish_host_surface_size, rememberHostSurfaceSize, request_host_surface_size,
123    set_platform_host_surface, HostSurface, HostSurfaceObserver, HostSurfaceRef, HostSurfaceSize,
124    ResizeRefused,
125};
126pub use http::{
127    default_http_client, local_http_client, map_ordered_concurrent, BytesBody, HttpBody,
128    HttpBodyRef, HttpClient, HttpClientRef, HttpControl, HttpError, HttpFuture, HttpMethod,
129    HttpProgress, HttpRequest, HttpResponse, ProgressHandler, StubAnswer, StubHttpClient,
130};
131pub use image_picker::{
132    clear_platform_image_picker, default_image_picker, local_image_picker,
133    set_platform_image_picker, ImagePicker, ImagePickerError, ImagePickerRef, ImageSource,
134    ProvideImagePicker, IMAGE_EXTENSIONS,
135};
136pub use incoming_share::{
137    clear_incoming_content, observe_incoming_content, publish_incoming_content,
138    rememberIncomingContent, IncomingContent, IncomingContentObserver, IncomingSource,
139};
140pub use launch_args::{
141    clear_platform_launch_args, isDebuggable, is_debuggable, launch_args,
142    launch_args_from_command_line, local_launch_args, set_platform_launch_args, LaunchArgValue,
143    LaunchArgs, LaunchArgsRef, ProvideLaunchArgs,
144};
145pub use launcher::{
146    clear_launcher_state, rememberOpenFileLauncher, rememberOpenFilesLauncher,
147    rememberOpenFolderLauncher, rememberSaveDocumentLauncher, rememberWritableFolderLauncher,
148    LauncherResult, OpenFileLauncher, OpenFilesLauncher, OpenFolderLauncher, SaveDocumentLauncher,
149    WritableFolderLauncher,
150};
151pub use media::{
152    audio_focus, clear_platform_media_player, current_media_item, dropped_media_samples,
153    latest_media_samples, media_capabilities, media_equalizer, media_equalizer_bands,
154    media_playback_supported, media_player, media_volume, observe_audio_focus,
155    observe_media_commands, observe_media_samples, observe_playback_progress,
156    observe_playback_state, octave_equalizer_bands, open_media, path_from_uri, pause_media,
157    play_media, playback_progress, playback_state, probe_media_duration, publish_audio_focus,
158    publish_media_command, publish_media_samples, publish_playback_progress,
159    publish_playback_state, record_dropped_media_samples, rememberAudioFocus,
160    rememberMediaCommands, rememberMediaSamples, rememberPlaybackProgress, rememberPlaybackState,
161    seek_media, seek_media_fraction, set_media_analysis_enabled, set_media_equalizer,
162    set_media_looping, set_media_metadata, set_media_speed, set_media_volume,
163    set_platform_media_player, stop_media, toggle_media, uri_for_path, AudioFocus, EqualizerBand,
164    EqualizerSettings, MediaArtwork, MediaCapabilities, MediaCommand, MediaError, MediaItem,
165    MediaMetadata, MediaObserver, MediaPlayer, MediaPlayerRef, MediaSamples, PlaybackProgress,
166    PlaybackState, DUCKED_GAIN, OCTAVE_BAND_CENTERS_HZ,
167};
168pub use navigation::{
169    back_interception_enabled, exit_requested, observe_back_requests, push_back_request,
170    request_exit, set_back_interception, take_back_requests, take_exit_request,
171    BackRequestObserver,
172};
173pub use network_status::{
174    clear_platform_network_monitor, network_monitor, network_status, set_platform_network_monitor,
175    NetworkMonitor, NetworkMonitorRef, NetworkStatus,
176};
177pub use notifier::{
178    clear_platform_notifier, default_notifier, local_notifier, push_notification_deeplink,
179    set_platform_notifier, take_notification_deeplink, Notifier, NotifierRef, NotifyRequest,
180    ProvideNotifier,
181};
182#[cfg(not(target_arch = "wasm32"))]
183pub use peer::{
184    content_length, fetch_range, fetch_to_writer, ByteSource, BytesSource, FetchResult, PeerError,
185    PeerServer, SourceResolver,
186};
187pub use power::{
188    clear_platform_power_monitor, observe_power_state, power_capabilities, power_monitor,
189    power_state, publish_power_state, rememberPowerState, set_platform_power_monitor,
190    BatteryStatus, PowerCapabilities, PowerMonitor, PowerMonitorRef, PowerObserverRegistration,
191    PowerReading, PowerState, ThermalState,
192};
193#[cfg(all(target_arch = "wasm32", feature = "preferences-web"))]
194pub use preferences::BrowserPreferences;
195#[cfg(not(target_arch = "wasm32"))]
196pub use preferences::FilePreferences;
197pub use preferences::{
198    clear_platform_preferences, preferences, rememberSaveable, set_platform_preferences,
199    MemoryPreferences, PreferencesError, PreferencesRef, PreferencesStore, Saver,
200};
201pub use purchases::{
202    clear_platform_purchases, note_store_news, observe_store_news, purchases,
203    rememberPurchaseEvents, rememberStoreState, set_platform_purchases, store_available,
204    store_state, Product, PurchaseEvent, Purchases, PurchasesRef, StoreObserver, StorePhase,
205    StoreState,
206};
207pub use share_sheet::{
208    clear_platform_share_sheet, default_share_sheet, local_share_sheet, set_platform_share_sheet,
209    ProvideShareSheet, ShareContent, ShareError, ShareSheet, ShareSheetRef,
210};
211pub use theme::{
212    clear_platform_system_theme, default_system_theme, isSystemInDarkTheme, local_system_theme,
213    set_platform_system_theme, ProvideSystemTheme, SystemTheme,
214};
215pub use uri_handler::{
216    clear_platform_uri_handler, default_uri_handler, local_uri_handler, set_platform_uri_handler,
217    ProvideUriHandler, UriHandler, UriHandlerError, UriHandlerRef,
218};
219pub use writable_folder::{
220    open_writable_folder, set_writable_folder_store_factory, FolderEntry, FolderError,
221    FolderReader, FolderWriter, WritableFolderStore, WritableFolderStoreRef,
222};
223
224/// Convenience alias used in unit tests.
225#[cfg(test)]
226pub(crate) type TestComposition = Composition<MemoryApplier>;
227
228/// A unique, empty directory under the workspace `target/test-output` for a
229/// test that needs real files. See [`cranpose_core::test_scratch_dir`].
230#[cfg(test)]
231pub(crate) fn test_scratch_dir(tag: &str) -> std::path::PathBuf {
232    cranpose_core::test_scratch_dir(env!("CARGO_MANIFEST_DIR"), tag)
233}
234
235/// Build a composition with a simple in-memory applier and run the provided closure once.
236#[cfg(test)]
237pub(crate) fn run_test_composition(build: impl FnMut()) -> TestComposition {
238    let mut composition = Composition::new(MemoryApplier::new());
239    composition
240        .render(location_key(file!(), line!(), column!()), build)
241        .expect("initial render succeeds");
242    composition
243}