Skip to main content

fission_core/
lib.rs

1//! # fission-core
2//!
3//! The runtime, widget system, and action/reducer architecture for the Fission UI
4//! framework.
5//!
6//! `fission-core` provides:
7//!
8//! - A **declarative widget tree** built from composable primitives ([`Widget`]).
9//! - A **unidirectional data-flow** pipeline: [`Action`] -> [`Runtime::dispatch`] -> reducer
10//!   -> mutated [`GlobalState`].
11//! - An **effect system** for async side-effects ([`Effect`], [`RuntimeEffect`]).
12//! - Built-in widgets: [`ui::Button`], [`ui::Text`], [`ui::TextInput`],
13//!   [`ui::Container`], [`ui::Row`], [`ui::Column`], [`ui::Scroll`],
14//!   [`ui::ZStack`], [`ui::Grid`], [`ui::LazyColumn`], and more.
15//!
16//! ## Getting started
17//!
18//! ```rust,ignore
19//! use fission_core::*;
20//! use fission_core::ui::*;
21//!
22//! // Define application state
23//! #[derive(Debug, Default)]
24//! struct MyState { value: String }
25//! impl GlobalState for MyState {}
26//!
27//! // Build a widget tree value
28//! struct MyWidget;
29//! impl From<MyWidget> for Widget {
30//!     fn from(_: MyWidget) -> Widget {
31//!         let (_, view) = fission_core::build::current::<MyState>();
32//!         Text::new(&*view.state().value).into()
33//!     }
34//! }
35//! ```
36
37use anyhow::Result;
38use lazy_static::lazy_static;
39use std::any::TypeId;
40use std::collections::HashMap;
41
42extern crate self as fission_core;
43
44pub mod action;
45pub mod async_runtime;
46pub mod build;
47mod build_context;
48pub mod capability; // New
49pub mod context; // New
50pub mod diff;
51pub mod effect; // New
52pub mod env;
53pub mod event;
54pub mod hit_test;
55pub mod input;
56pub(crate) mod lowering;
57pub mod media;
58pub mod motion;
59pub mod platform;
60pub mod platform_barcode;
61pub mod platform_biometric;
62pub mod platform_bluetooth;
63pub mod platform_camera;
64pub mod platform_clipboard;
65pub mod platform_geolocation;
66pub mod platform_haptics;
67pub mod platform_microphone;
68pub mod platform_nfc;
69pub mod platform_passkey;
70pub mod platform_volume;
71pub mod platform_wifi;
72pub mod registry;
73pub mod runtime;
74pub mod scoped_action_handlers;
75pub mod scrollbar;
76pub mod state;
77pub mod time;
78pub mod ui;
79
80pub mod view;
81
82#[doc(hidden)]
83/// Framework integration boundary for first-party shells, renderers, test
84/// harnesses, and generated widget implementations.
85///
86/// This module is not part of the application authoring API. Application code
87/// should construct `Widget` values from widget structs and components instead
88/// of calling lowering helpers directly.
89pub mod internal {
90    pub use crate::build_context::BuildCtx;
91    pub use crate::lowering::{
92        build_layout_tree, wrap_zstack_child, InternalIrBuilder, InternalLoweringCx,
93    };
94    use crate::Widget;
95    use fission_ir::WidgetId;
96
97    pub fn custom_render_widget(node: InternalRenderNode) -> Widget {
98        Widget::custom(node)
99    }
100
101    pub fn lower_widget(widget: &Widget, cx: &mut InternalLoweringCx) -> WidgetId {
102        widget.lower(cx)
103    }
104
105    pub fn lower_widget_to_ir(widget: &Widget) -> fission_ir::CoreIR {
106        let env = crate::Env::default();
107        let runtime_state = crate::RuntimeState::default();
108        let mut cx = InternalLoweringCx::new(&env, &runtime_state, None, None);
109        widget.lower(&mut cx);
110        cx.ir
111    }
112
113    pub fn widget_kind_name(widget: &Widget) -> &'static str {
114        widget.kind_name()
115    }
116
117    pub fn widget_as_row(widget: &Widget) -> Option<&crate::ui::Row> {
118        widget.as_row()
119    }
120
121    pub fn widget_as_column(widget: &Widget) -> Option<&crate::ui::Column> {
122        widget.as_column()
123    }
124
125    pub fn widget_as_container(widget: &Widget) -> Option<&crate::ui::Container> {
126        widget.as_container()
127    }
128
129    pub fn widget_as_scroll(widget: &Widget) -> Option<&crate::ui::Scroll> {
130        widget.as_scroll()
131    }
132
133    pub fn widget_as_rich_text(widget: &Widget) -> Option<&crate::ui::RichText> {
134        widget.as_rich_text()
135    }
136
137    pub fn widget_as_text(widget: &Widget) -> Option<&crate::ui::Text> {
138        widget.as_text()
139    }
140
141    pub fn widget_as_text_input(widget: &Widget) -> Option<&crate::ui::TextInput> {
142        widget.as_text_input()
143    }
144
145    pub fn widget_as_button(widget: &Widget) -> Option<&crate::ui::Button> {
146        widget.as_button()
147    }
148
149    pub fn widget_as_gesture_detector(widget: &Widget) -> Option<&crate::ui::GestureDetector> {
150        widget.as_gesture_detector()
151    }
152
153    pub fn widget_as_zstack(widget: &Widget) -> Option<&crate::ui::ZStack> {
154        widget.as_zstack()
155    }
156
157    pub use crate::ui::custom_render::{
158        downcast_render_object, CustomEventResult, CustomHitResult, CustomRender,
159        CustomRenderObject,
160    };
161    pub use crate::ui::node::{CustomWidget, InternalRenderNode};
162    pub use crate::ui::traits::{InternalLower, InternalLowerer};
163}
164
165pub mod public {
166    pub mod action {
167        pub use crate::action::*;
168    }
169    pub mod env {
170        pub use crate::env::*;
171    }
172    pub mod event {
173        pub use crate::event::*;
174    }
175    pub mod hit_test {
176        pub use crate::hit_test::*;
177    }
178    pub mod registry {
179        pub use crate::registry::*;
180    }
181    pub mod scoped_action_handlers {
182        pub use crate::scoped_action_handlers::*;
183    }
184    pub mod ui {
185        pub use crate::ui::widgets::*;
186        pub use crate::ui::Widget;
187
188        pub mod widgets {
189            pub use crate::ui::widgets::*;
190        }
191    }
192    pub mod view {
193        pub use crate::view::*;
194    }
195
196    pub use crate::action::{Action, ActionEnvelope, ActionId, ActionScopeId, GlobalState};
197    pub use crate::async_runtime::{
198        BoxFuture, JobCtx, JobRef, JobSpec, ResourceExecutionContext, ServiceBindings, ServiceCtx,
199        ServiceRunner, ServiceSlot, ServiceSpec, ServiceType,
200    };
201    pub use crate::capability::{
202        CapabilityCtx, CapabilityInvocationPayload, CapabilityType, OpenUrlCapability,
203        OpenUrlRequest, OperationCapability, PickOpenFilesCapability, PickOpenFilesError,
204        PickOpenFilesRequest, PickOpenFilesResult, PickedFile, OPEN_URL, PICK_OPEN_FILES,
205    };
206    pub use crate::context::{
207        BarcodeScannerEffects, BiometricEffects, BluetoothEffects, CameraEffects, ClipboardEffects,
208        Effects, GeolocationEffects, HapticEffects, MicrophoneEffects, NfcEffects,
209        NotificationEffects, PasskeyEffects, ReducerContext, VolumeEffects, WifiEffects,
210    }; // New
211    pub use crate::effect::{
212        ActionInput, Effect, EffectEnvelope, RuntimeEffect, ScrollAlignment, ScrollAxis,
213        ScrollBehavior, ScrollIntoViewRequest,
214    };
215    pub use crate::env::{
216        Clipboard, Env, ImeHandler, InteractionStateMap, RuntimeState, ScrollStateMap, WindowEnv,
217        WindowTitle,
218    };
219    pub use crate::runtime::Runtime;
220    pub use crate::state::{LocalStateKey, LocalStateStore, StateField};
221
222    pub use crate::build::{BuildCtxHandle, ViewHandle};
223    pub use crate::event::{
224        InputEvent, KeyCode, KeyEvent, LifecycleEvent, PointerButton, PointerEvent,
225    };
226    pub use crate::motion::*;
227    pub use crate::platform::{
228        CancelAllNotificationsCapability, CancelNotificationCapability, CancelNotificationRequest,
229        DeepLink, DeepLinkConfig, DeepLinkReceived, DeepLinkSource,
230        GetNotificationSettingsCapability, NotificationActionButton, NotificationError,
231        NotificationId, NotificationPermission, NotificationPermissionRequest, NotificationReceipt,
232        NotificationRequest, NotificationResponse, NotificationResponseReceived,
233        NotificationSchedule, NotificationSettings, NotificationSound, PushPlatform,
234        PushRegistration, PushRegistrationRequest, RegisterPushNotificationsCapability,
235        RequestNotificationPermissionCapability, ScheduleNotificationCapability,
236        SetBadgeCountCapability, SetBadgeCountRequest, ShowNotificationCapability,
237        UnregisterPushNotificationsCapability, CANCEL_ALL_NOTIFICATIONS, CANCEL_NOTIFICATION,
238        GET_NOTIFICATION_SETTINGS, REGISTER_PUSH_NOTIFICATIONS, REQUEST_NOTIFICATION_PERMISSION,
239        SCHEDULE_NOTIFICATION, SET_BADGE_COUNT, SHOW_NOTIFICATION, UNREGISTER_PUSH_NOTIFICATIONS,
240    };
241    pub use crate::platform_barcode::{
242        BarcodeFormat, BarcodeImageDecodeRequest, BarcodePoint, BarcodeScanRequest,
243        BarcodeScanResult, BarcodeScanResults, BarcodeScannerError, CancelBarcodeScanCapability,
244        DecodeBarcodeImageCapability, ScanBarcodeCapability, CANCEL_BARCODE_SCAN,
245        DECODE_BARCODE_IMAGE, SCAN_BARCODE,
246    };
247    pub use crate::platform_biometric::{
248        AuthenticateBiometricCapability, BiometricAuthenticateRequest, BiometricAuthenticateResult,
249        BiometricAvailability, BiometricError, BiometricKind, BiometricStrength,
250        CancelBiometricAuthenticationCapability, GetBiometricAvailabilityCapability,
251        AUTHENTICATE_BIOMETRIC, CANCEL_BIOMETRIC_AUTHENTICATION, GET_BIOMETRIC_AVAILABILITY,
252    };
253    pub use crate::platform_bluetooth::{
254        BluetoothAdvertiseReceipt, BluetoothAdvertiseRequest, BluetoothAvailability,
255        BluetoothConnectRequest, BluetoothConnection, BluetoothDevice, BluetoothDisconnectRequest,
256        BluetoothError, BluetoothMode, BluetoothPermission, BluetoothPermissionRequest,
257        BluetoothReadRequest, BluetoothReadResult, BluetoothScanRequest, BluetoothScanResult,
258        BluetoothStopAdvertiseRequest, BluetoothWriteRequest, ConnectBluetoothDeviceCapability,
259        DisconnectBluetoothDeviceCapability, GetBluetoothAvailabilityCapability,
260        ReadBluetoothCharacteristicCapability, RequestBluetoothPermissionCapability,
261        ScanBluetoothDevicesCapability, StartBluetoothAdvertisingCapability,
262        StopBluetoothAdvertisingCapability, WriteBluetoothCharacteristicCapability,
263        CONNECT_BLUETOOTH_DEVICE, DISCONNECT_BLUETOOTH_DEVICE, GET_BLUETOOTH_AVAILABILITY,
264        READ_BLUETOOTH_CHARACTERISTIC, REQUEST_BLUETOOTH_PERMISSION, SCAN_BLUETOOTH_DEVICES,
265        START_BLUETOOTH_ADVERTISING, STOP_BLUETOOTH_ADVERTISING, WRITE_BLUETOOTH_CHARACTERISTIC,
266    };
267    pub use crate::platform_camera::{
268        CameraAvailability, CameraCapture, CameraCaptureRequest, CameraDevice, CameraError,
269        CameraFacing, CameraFlashMode, CameraFlashlightRequest, CameraImageFormat,
270        CameraPermission, CameraPermissionRequest, CameraResolution, CancelCameraCaptureCapability,
271        CapturePhotoCapability, GetCameraAvailabilityCapability, RequestCameraPermissionCapability,
272        SetCameraFlashlightCapability, CANCEL_CAMERA_CAPTURE, CAPTURE_PHOTO,
273        GET_CAMERA_AVAILABILITY, REQUEST_CAMERA_PERMISSION, SET_CAMERA_FLASHLIGHT,
274    };
275    pub use crate::platform_clipboard::{
276        ClearClipboardCapability, ClipboardContent, ClipboardError, ClipboardItem, ClipboardText,
277        ClipboardWriteTextRequest, ReadClipboardContentCapability, ReadClipboardTextCapability,
278        WriteClipboardContentCapability, WriteClipboardTextCapability, CLEAR_CLIPBOARD,
279        READ_CLIPBOARD_CONTENT, READ_CLIPBOARD_TEXT, WRITE_CLIPBOARD_CONTENT, WRITE_CLIPBOARD_TEXT,
280    };
281    pub use crate::platform_geolocation::{
282        GeolocationError, GeolocationPermission, GeolocationPermissionRequest, GeolocationPosition,
283        GeolocationPositionRequest, GetCurrentPositionCapability,
284        GetGeolocationPermissionCapability, RequestGeolocationPermissionCapability,
285        GET_CURRENT_POSITION, GET_GEOLOCATION_PERMISSION, REQUEST_GEOLOCATION_PERMISSION,
286    };
287    pub use crate::platform_haptics::{
288        HapticError, HapticImpactCapability, HapticImpactRequest, HapticImpactStyle,
289        HapticNotificationCapability, HapticNotificationKind, HapticNotificationRequest,
290        HapticPatternCapability, HapticPatternRequest, HapticPatternStep,
291        HapticSelectionCapability, HAPTIC_IMPACT, HAPTIC_NOTIFICATION, HAPTIC_PATTERN,
292        HAPTIC_SELECTION,
293    };
294    pub use crate::platform_microphone::{
295        AudioSampleFormat, CancelMicrophoneCaptureCapability, CaptureMicrophoneAudioCapability,
296        GetMicrophoneAvailabilityCapability, MicrophoneAvailability, MicrophoneCapture,
297        MicrophoneCaptureRequest, MicrophoneDevice, MicrophoneError, MicrophonePermission,
298        MicrophonePermissionRequest, RequestMicrophonePermissionCapability,
299        CANCEL_MICROPHONE_CAPTURE, CAPTURE_MICROPHONE_AUDIO, GET_MICROPHONE_AVAILABILITY,
300        REQUEST_MICROPHONE_PERMISSION,
301    };
302    pub use crate::platform_nfc::{
303        CancelNfcSessionCapability, EmulateNfcTagCapability, GetNfcAvailabilityCapability,
304        NfcAvailability, NfcEmulationRequest, NfcError, NfcRecord, NfcRecordTypeNameFormat,
305        NfcScanRequest, NfcSessionReceipt, NfcTag, NfcTagDiscovered, NfcTechnology,
306        NfcWriteRequest, ScanNfcTagCapability, WriteNfcTagCapability, CANCEL_NFC_SESSION,
307        EMULATE_NFC_TAG, GET_NFC_AVAILABILITY, SCAN_NFC_TAG, WRITE_NFC_TAG,
308    };
309    pub use crate::platform_passkey::{
310        AuthenticatePasskeyCapability, CancelPasskeyOperationCapability,
311        GetPasskeyAvailabilityCapability, PasskeyAlgorithm, PasskeyAttestationConveyance,
312        PasskeyAuthenticationRequest, PasskeyAuthenticationResult, PasskeyAuthenticatorAttachment,
313        PasskeyAuthenticatorSelection, PasskeyAvailability, PasskeyCredentialDescriptor,
314        PasskeyError, PasskeyMediation, PasskeyRegistrationRequest, PasskeyRegistrationResult,
315        PasskeyRelyingParty, PasskeyResidentKeyRequirement, PasskeyTransport, PasskeyUser,
316        PasskeyUserVerification, RegisterPasskeyCapability, AUTHENTICATE_PASSKEY,
317        CANCEL_PASSKEY_OPERATION, GET_PASSKEY_AVAILABILITY, REGISTER_PASSKEY,
318    };
319    pub use crate::platform_volume::{
320        AdjustVolumeLevelCapability, GetVolumeLevelCapability, SetVolumeLevelCapability,
321        VolumeAdjustDirection, VolumeAdjustRequest, VolumeError, VolumeLevel, VolumeSetRequest,
322        VolumeStream, ADJUST_VOLUME_LEVEL, GET_VOLUME_LEVEL, SET_VOLUME_LEVEL,
323    };
324    pub use crate::platform_wifi::{
325        ConnectWifiNetworkCapability, DisconnectWifiNetworkCapability,
326        GetWifiAvailabilityCapability, RequestWifiPermissionCapability, ScanWifiNetworksCapability,
327        WifiAvailability, WifiConnectRequest, WifiConnection, WifiDisconnectRequest, WifiError,
328        WifiNetwork, WifiPermission, WifiPermissionRequest, WifiScanRequest, WifiScanResult,
329        WifiSecurity, CONNECT_WIFI_NETWORK, DISCONNECT_WIFI_NETWORK, GET_WIFI_AVAILABILITY,
330        REQUEST_WIFI_PERMISSION, SCAN_WIFI_NETWORKS,
331    };
332    pub use crate::registry::{
333        ActionRegistry, Handler, JobResource, PortalLayer, ResourceKey, ResourcePolicy,
334        ResourceRegistry, RuntimeResourceDeclaration, RuntimeResourceKind, ServiceResource,
335        TimerResource, VideoRegistration,
336    };
337    pub use crate::time::{Clock, CurrentTime};
338    pub use crate::ui::{
339        provider, ActionScope, BadgeTone, Button, ButtonHierarchy, ButtonMotion, CardPattern,
340        Column, ComponentSize, ComponentState, CustomWidget, Provider, Row, Text, Widget,
341        WidgetIdExt,
342    };
343    pub use crate::view::{ComputedView, FissionViewField, Selector, ValueView, View};
344    pub use crate::{reduce, reduce_with, widgets, with_reducer};
345    pub use fission_ir::op;
346    pub use fission_ir::{EmbedKind, FocusPolicy, Op, Role, Semantics, WidgetId};
347    pub use fission_layout::{
348        BoxConstraints, FlexDirection, LayoutEngine, LayoutOp, LayoutPoint, LayoutRect, LayoutSize,
349        LayoutSnapshot, LayoutUnit, TextMeasurer,
350    };
351}
352
353#[cfg(test)]
354mod tests;
355
356pub use action::{Action, ActionEnvelope, ActionId, ActionScopeId, GlobalState, ShellRouteChanged};
357pub use async_runtime::{
358    BoxFuture, JobCtx, JobRef, JobSpec, ResourceExecutionContext, ServiceBindings, ServiceCtx,
359    ServiceRunner, ServiceSlot, ServiceSpec, ServiceType,
360};
361pub use capability::{
362    CapabilityCtx, CapabilityInvocationPayload, CapabilityType, OpenUrlCapability, OpenUrlRequest,
363    OperationCapability, PickOpenFilesCapability, PickOpenFilesError, PickOpenFilesRequest,
364    PickOpenFilesResult, PickedFile, OPEN_URL, PICK_OPEN_FILES,
365};
366pub use context::{
367    BarcodeScannerEffects, BiometricEffects, BluetoothEffects, CameraEffects, ClipboardEffects,
368    Effects, GeolocationEffects, HapticEffects, MicrophoneEffects, NfcEffects, NotificationEffects,
369    PasskeyEffects, ReducerContext, VolumeEffects, WifiEffects,
370}; // New
371pub use effect::{
372    ActionInput, Effect, EffectEnvelope, RuntimeEffect, ScrollAlignment, ScrollAxis,
373    ScrollBehavior, ScrollIntoViewRequest,
374};
375pub use env::{
376    Clipboard, Env, ImeHandler, InteractionStateMap, RouteLocation, RuntimeState, ScrollStateMap,
377    WindowEnv, WindowTitle,
378};
379pub use motion::*;
380pub use runtime::Runtime;
381pub use state::{LocalStateKey, LocalStateStore, StateField};
382
383pub use build::{BuildCtxHandle, ViewHandle};
384pub use event::{InputEvent, KeyCode, KeyEvent, LifecycleEvent, PointerButton, PointerEvent};
385pub use fission_ir::op;
386pub use fission_ir::{EmbedKind, FocusPolicy, Op, Role, Semantics, WidgetId};
387pub use fission_layout::{
388    BoxConstraints, FlexDirection, LayoutEngine, LayoutOp, LayoutPoint, LayoutRect, LayoutSize,
389    LayoutSnapshot, LayoutUnit, TextMeasurer,
390};
391pub use platform::{
392    CancelAllNotificationsCapability, CancelNotificationCapability, CancelNotificationRequest,
393    DeepLink, DeepLinkConfig, DeepLinkReceived, DeepLinkSource, GetNotificationSettingsCapability,
394    NotificationActionButton, NotificationError, NotificationId, NotificationPermission,
395    NotificationPermissionRequest, NotificationReceipt, NotificationRequest, NotificationResponse,
396    NotificationResponseReceived, NotificationSchedule, NotificationSettings, NotificationSound,
397    PushPlatform, PushRegistration, PushRegistrationRequest, RegisterPushNotificationsCapability,
398    RequestNotificationPermissionCapability, ScheduleNotificationCapability,
399    SetBadgeCountCapability, SetBadgeCountRequest, ShowNotificationCapability,
400    UnregisterPushNotificationsCapability, CANCEL_ALL_NOTIFICATIONS, CANCEL_NOTIFICATION,
401    GET_NOTIFICATION_SETTINGS, REGISTER_PUSH_NOTIFICATIONS, REQUEST_NOTIFICATION_PERMISSION,
402    SCHEDULE_NOTIFICATION, SET_BADGE_COUNT, SHOW_NOTIFICATION, UNREGISTER_PUSH_NOTIFICATIONS,
403};
404pub use platform_barcode::{
405    BarcodeFormat, BarcodeImageDecodeRequest, BarcodePoint, BarcodeScanRequest, BarcodeScanResult,
406    BarcodeScanResults, BarcodeScannerError, CancelBarcodeScanCapability,
407    DecodeBarcodeImageCapability, ScanBarcodeCapability, CANCEL_BARCODE_SCAN, DECODE_BARCODE_IMAGE,
408    SCAN_BARCODE,
409};
410pub use platform_biometric::{
411    AuthenticateBiometricCapability, BiometricAuthenticateRequest, BiometricAuthenticateResult,
412    BiometricAvailability, BiometricError, BiometricKind, BiometricStrength,
413    CancelBiometricAuthenticationCapability, GetBiometricAvailabilityCapability,
414    AUTHENTICATE_BIOMETRIC, CANCEL_BIOMETRIC_AUTHENTICATION, GET_BIOMETRIC_AVAILABILITY,
415};
416pub use platform_bluetooth::{
417    BluetoothAdvertiseReceipt, BluetoothAdvertiseRequest, BluetoothAvailability,
418    BluetoothConnectRequest, BluetoothConnection, BluetoothDevice, BluetoothDisconnectRequest,
419    BluetoothError, BluetoothMode, BluetoothPermission, BluetoothPermissionRequest,
420    BluetoothReadRequest, BluetoothReadResult, BluetoothScanRequest, BluetoothScanResult,
421    BluetoothStopAdvertiseRequest, BluetoothWriteRequest, ConnectBluetoothDeviceCapability,
422    DisconnectBluetoothDeviceCapability, GetBluetoothAvailabilityCapability,
423    ReadBluetoothCharacteristicCapability, RequestBluetoothPermissionCapability,
424    ScanBluetoothDevicesCapability, StartBluetoothAdvertisingCapability,
425    StopBluetoothAdvertisingCapability, WriteBluetoothCharacteristicCapability,
426    CONNECT_BLUETOOTH_DEVICE, DISCONNECT_BLUETOOTH_DEVICE, GET_BLUETOOTH_AVAILABILITY,
427    READ_BLUETOOTH_CHARACTERISTIC, REQUEST_BLUETOOTH_PERMISSION, SCAN_BLUETOOTH_DEVICES,
428    START_BLUETOOTH_ADVERTISING, STOP_BLUETOOTH_ADVERTISING, WRITE_BLUETOOTH_CHARACTERISTIC,
429};
430pub use platform_camera::{
431    CameraAvailability, CameraCapture, CameraCaptureRequest, CameraDevice, CameraError,
432    CameraFacing, CameraFlashMode, CameraFlashlightRequest, CameraImageFormat, CameraPermission,
433    CameraPermissionRequest, CameraResolution, CancelCameraCaptureCapability,
434    CapturePhotoCapability, GetCameraAvailabilityCapability, RequestCameraPermissionCapability,
435    SetCameraFlashlightCapability, CANCEL_CAMERA_CAPTURE, CAPTURE_PHOTO, GET_CAMERA_AVAILABILITY,
436    REQUEST_CAMERA_PERMISSION, SET_CAMERA_FLASHLIGHT,
437};
438pub use platform_clipboard::{
439    ClearClipboardCapability, ClipboardContent, ClipboardError, ClipboardItem, ClipboardText,
440    ClipboardWriteTextRequest, ReadClipboardContentCapability, ReadClipboardTextCapability,
441    WriteClipboardContentCapability, WriteClipboardTextCapability, CLEAR_CLIPBOARD,
442    READ_CLIPBOARD_CONTENT, READ_CLIPBOARD_TEXT, WRITE_CLIPBOARD_CONTENT, WRITE_CLIPBOARD_TEXT,
443};
444pub use platform_geolocation::{
445    GeolocationError, GeolocationPermission, GeolocationPermissionRequest, GeolocationPosition,
446    GeolocationPositionRequest, GetCurrentPositionCapability, GetGeolocationPermissionCapability,
447    RequestGeolocationPermissionCapability, GET_CURRENT_POSITION, GET_GEOLOCATION_PERMISSION,
448    REQUEST_GEOLOCATION_PERMISSION,
449};
450pub use platform_haptics::{
451    HapticError, HapticImpactCapability, HapticImpactRequest, HapticImpactStyle,
452    HapticNotificationCapability, HapticNotificationKind, HapticNotificationRequest,
453    HapticPatternCapability, HapticPatternRequest, HapticPatternStep, HapticSelectionCapability,
454    HAPTIC_IMPACT, HAPTIC_NOTIFICATION, HAPTIC_PATTERN, HAPTIC_SELECTION,
455};
456pub use platform_microphone::{
457    AudioSampleFormat, CancelMicrophoneCaptureCapability, CaptureMicrophoneAudioCapability,
458    GetMicrophoneAvailabilityCapability, MicrophoneAvailability, MicrophoneCapture,
459    MicrophoneCaptureRequest, MicrophoneDevice, MicrophoneError, MicrophonePermission,
460    MicrophonePermissionRequest, RequestMicrophonePermissionCapability, CANCEL_MICROPHONE_CAPTURE,
461    CAPTURE_MICROPHONE_AUDIO, GET_MICROPHONE_AVAILABILITY, REQUEST_MICROPHONE_PERMISSION,
462};
463pub use platform_nfc::{
464    CancelNfcSessionCapability, EmulateNfcTagCapability, GetNfcAvailabilityCapability,
465    NfcAvailability, NfcEmulationRequest, NfcError, NfcRecord, NfcRecordTypeNameFormat,
466    NfcScanRequest, NfcSessionReceipt, NfcTag, NfcTagDiscovered, NfcTechnology, NfcWriteRequest,
467    ScanNfcTagCapability, WriteNfcTagCapability, CANCEL_NFC_SESSION, EMULATE_NFC_TAG,
468    GET_NFC_AVAILABILITY, SCAN_NFC_TAG, WRITE_NFC_TAG,
469};
470pub use platform_passkey::{
471    AuthenticatePasskeyCapability, CancelPasskeyOperationCapability,
472    GetPasskeyAvailabilityCapability, PasskeyAlgorithm, PasskeyAttestationConveyance,
473    PasskeyAuthenticationRequest, PasskeyAuthenticationResult, PasskeyAuthenticatorAttachment,
474    PasskeyAuthenticatorSelection, PasskeyAvailability, PasskeyCredentialDescriptor, PasskeyError,
475    PasskeyMediation, PasskeyRegistrationRequest, PasskeyRegistrationResult, PasskeyRelyingParty,
476    PasskeyResidentKeyRequirement, PasskeyTransport, PasskeyUser, PasskeyUserVerification,
477    RegisterPasskeyCapability, AUTHENTICATE_PASSKEY, CANCEL_PASSKEY_OPERATION,
478    GET_PASSKEY_AVAILABILITY, REGISTER_PASSKEY,
479};
480pub use platform_volume::{
481    AdjustVolumeLevelCapability, GetVolumeLevelCapability, SetVolumeLevelCapability,
482    VolumeAdjustDirection, VolumeAdjustRequest, VolumeError, VolumeLevel, VolumeSetRequest,
483    VolumeStream, ADJUST_VOLUME_LEVEL, GET_VOLUME_LEVEL, SET_VOLUME_LEVEL,
484};
485pub use platform_wifi::{
486    ConnectWifiNetworkCapability, DisconnectWifiNetworkCapability, GetWifiAvailabilityCapability,
487    RequestWifiPermissionCapability, ScanWifiNetworksCapability, WifiAvailability,
488    WifiConnectRequest, WifiConnection, WifiDisconnectRequest, WifiError, WifiNetwork,
489    WifiPermission, WifiPermissionRequest, WifiScanRequest, WifiScanResult, WifiSecurity,
490    CONNECT_WIFI_NETWORK, DISCONNECT_WIFI_NETWORK, GET_WIFI_AVAILABILITY, REQUEST_WIFI_PERMISSION,
491    SCAN_WIFI_NETWORKS,
492};
493pub use registry::{
494    ActionRegistry, Handler, JobResource, PortalLayer, ResourceKey, ResourcePolicy,
495    ResourceRegistry, RuntimeResourceDeclaration, RuntimeResourceKind, ServiceResource,
496    TimerResource, VideoRegistration,
497};
498pub use time::{Clock, CurrentTime};
499pub use ui::{
500    provider, ActionScope, BadgeTone, Button, ButtonHierarchy, ButtonMotion, CardPattern, Column,
501    ComponentSize, ComponentState, CustomWidget, Provider, Row, Text, Widget, WidgetIdExt,
502};
503pub use view::{ComputedView, FissionViewField, Selector, ValueView, View};
504
505/// Coerces a reducer function item or non-capturing closure to the handler
506/// function-pointer type Rust can infer from the surrounding `ctx.bind(...)`
507/// call.
508///
509/// ```rust,ignore
510/// use fission::prelude::*;
511///
512/// let on_press = with_reducer!(ctx, Increment, on_increment);
513/// ```
514#[macro_export]
515macro_rules! reduce_with {
516    ($handler:expr $(,)?) => {
517        $handler as $crate::Handler<_, _>
518    };
519}
520
521/// Short alias for [`reduce_with!`].
522#[macro_export]
523macro_rules! reduce {
524    ($handler:expr $(,)?) => {
525        $crate::reduce_with!($handler)
526    };
527}
528
529/// Builds a `Vec<Widget>` from widget expressions without repeated `.into()` calls.
530///
531/// Dynamic children may still be produced with normal iterators and
532/// `collect::<Vec<Widget>>()`; this macro is only syntax sugar for
533/// literal child lists.
534#[macro_export]
535macro_rules! widgets {
536    ($($widget:expr),* $(,)?) => {
537        {
538            let mut widgets = ::std::vec::Vec::<$crate::Widget>::new();
539            $(
540                widgets.push($crate::Widget::from($widget));
541            )*
542            widgets
543        }
544    };
545}
546
547/// Binds an action to a reducer in one expression.
548///
549/// ```rust,ignore
550/// use fission::prelude::*;
551///
552/// let on_press = with_reducer!(ctx, Increment, on_increment);
553/// ```
554#[macro_export]
555macro_rules! with_reducer {
556    ($ctx:expr, $action:expr, $handler:expr $(,)?) => {
557        $ctx.bind($action, $crate::reduce_with!($handler))
558    };
559}
560
561/// A frame-tick action that advances the runtime clock by a delta.
562///
563/// The platform shell dispatches `Tick` once per frame so that animations,
564/// timers, and other time-dependent logic can progress.
565///
566/// # Example
567///
568/// ```rust,ignore
569/// // Advance the runtime by 16 ms (~60 fps)
570/// runtime.tick(16)?;
571/// ```
572#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
573pub struct Tick {
574    /// Delta time in milliseconds since the last tick.
575    pub dt: CurrentTime,
576}
577
578impl Action for Tick {
579    fn static_id() -> ActionId {
580        *TICK_ACTION_ID
581    }
582}
583
584lazy_static! {
585    pub static ref TICK_ACTION_ID: ActionId = ActionId::from_name("fission_core::Tick");
586}
587
588/// An action that sets the runtime clock to an absolute timestamp.
589///
590/// Unlike [`Tick`] which advances by a delta, `AdvanceTo` jumps directly to
591/// the given time. Useful for testing and deterministic replay.
592///
593/// # Example
594///
595/// ```rust,ignore
596/// let envelope: ActionEnvelope = AdvanceTo { time: 5000 }.into();
597/// runtime.dispatch(envelope, WidgetId::from_u128(0))?;
598/// ```
599#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
600pub struct AdvanceTo {
601    /// The absolute time (in milliseconds) to set the clock to.
602    pub time: CurrentTime,
603}
604
605impl Action for AdvanceTo {
606    fn static_id() -> ActionId {
607        *ADVANCE_TO_ACTION_ID
608    }
609}
610
611lazy_static! {
612    pub static ref ADVANCE_TO_ACTION_ID: ActionId = ActionId::from_name("fission_core::AdvanceTo");
613}
614
615/// A type-erased reducer function stored in the [`Runtime`].
616///
617/// `BoxedReducer` is the internal representation used by the runtime to invoke
618/// reducers without knowing the concrete `GlobalState` or `Action` types.
619pub(crate) type BoxedReducer = Box<
620    dyn FnMut(
621            &mut HashMap<TypeId, Box<dyn GlobalState>>,
622            &ActionEnvelope,
623            WidgetId,
624            &mut Vec<EffectEnvelope>,
625            &ActionInput,
626        ) -> Result<()>
627        + Send
628        + Sync,
629>;