Skip to main content

fission_ir/
widget_id.rs

1//! Widget-level identity, separate from IR node identity.
2//!
3//! A [`WidgetNodeId`] identifies a *widget* rather than an IR node. Widgets may
4//! compile to multiple IR nodes, but they share a single `WidgetNodeId`. This is
5//! used primarily by [`LayoutOp::Embed`](crate::op::LayoutOp::Embed) to reference
6//! a platform-native surface (video player, web view, etc.) that the framework
7//! does not render itself.
8
9use blake3;
10use serde::{Deserialize, Serialize};
11
12/// A 128-bit identity for a widget.
13///
14/// Like [`NodeId`](crate::NodeId), this is derived from a BLAKE3 hash, but it uses
15/// the `"widget:"` prefix so that widget IDs and node IDs never collide. Widget IDs
16/// are interconvertible with node IDs via `From` impls.
17///
18/// # Example
19///
20/// ```rust
21/// use fission_ir::WidgetNodeId;
22/// let wid = WidgetNodeId::explicit("video-player");
23/// ```
24#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Debug)]
25pub struct WidgetNodeId(u128);
26
27impl WidgetNodeId {
28    /// Creates a `WidgetNodeId` from a raw 128-bit value.
29    ///
30    /// Intended for internal use or deserialization.
31    pub const fn from_u128(val: u128) -> Self {
32        Self(val)
33    }
34
35    /// Returns the underlying 128-bit value.
36    pub fn as_u128(&self) -> u128 {
37        self.0
38    }
39
40    /// Creates a `WidgetNodeId` from a user-provided name string.
41    ///
42    /// The name is hashed with BLAKE3 (prefixed with `"widget:"`), producing a
43    /// deterministic ID. Use this to give stable identities to platform-embedded
44    /// widgets.
45    ///
46    /// # Example
47    ///
48    /// ```rust
49    /// use fission_ir::WidgetNodeId;
50    /// let a = WidgetNodeId::explicit("camera-preview");
51    /// let b = WidgetNodeId::explicit("camera-preview");
52    /// assert_eq!(a, b);
53    /// ```
54    pub fn explicit(name: &str) -> Self {
55        let mut hasher = blake3::Hasher::new();
56        hasher.update(b"widget:");
57        hasher.update(name.as_bytes());
58        let hash = hasher.finalize();
59        Self(u128::from_le_bytes(
60            hash.as_bytes()[0..16].try_into().unwrap(),
61        ))
62    }
63}
64
65impl From<crate::node_id::NodeId> for WidgetNodeId {
66    fn from(node: crate::node_id::NodeId) -> Self {
67        Self(node.as_u128())
68    }
69}
70
71impl From<WidgetNodeId> for crate::node_id::NodeId {
72    fn from(id: WidgetNodeId) -> Self {
73        crate::node_id::NodeId::from_u128(id.0)
74    }
75}