jellyflow_core/core/model/
binding.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::core::ids::{EdgeId, GroupId, NodeId, PortId, StickyNoteId};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Binding {
9 pub subject: BindingEndpoint,
11 pub target: BindingEndpoint,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
15 pub kind: Option<String>,
16 #[serde(default, skip_serializing_if = "Value::is_null")]
18 pub meta: Value,
19}
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23#[serde(tag = "kind", rename_all = "snake_case")]
24pub enum BindingEndpoint {
25 GraphLocal { target: GraphLocalBindingTarget },
27 Source { anchor: SourceAnchor },
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
33#[serde(tag = "kind", rename_all = "snake_case")]
34pub enum GraphLocalBindingTarget {
35 Graph,
36 Node { id: NodeId },
37 Port { id: PortId },
38 Edge { id: EdgeId },
39 Group { id: GroupId },
40 StickyNote { id: StickyNoteId },
41}
42
43#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45pub struct SourceAnchor {
46 pub source_id: String,
48 #[serde(default)]
50 pub payload: Value,
51}
52
53impl Binding {
54 pub fn new(subject: BindingEndpoint, target: BindingEndpoint) -> Self {
55 Self {
56 subject,
57 target,
58 kind: None,
59 meta: Value::Null,
60 }
61 }
62
63 pub fn graph_local_to_source(
64 subject: GraphLocalBindingTarget,
65 source_id: impl Into<String>,
66 payload: Value,
67 ) -> Self {
68 Self::new(
69 BindingEndpoint::graph_local(subject),
70 BindingEndpoint::source_payload(source_id, payload),
71 )
72 }
73
74 pub fn node_to_source(node: NodeId, source_id: impl Into<String>, payload: Value) -> Self {
75 Self::graph_local_to_source(GraphLocalBindingTarget::node(node), source_id, payload)
76 }
77
78 pub fn with_kind(mut self, kind: impl Into<String>) -> Self {
79 self.kind = Some(kind.into());
80 self
81 }
82
83 pub fn with_meta(mut self, meta: Value) -> Self {
84 self.meta = meta;
85 self
86 }
87}
88
89impl BindingEndpoint {
90 pub fn graph_local(target: GraphLocalBindingTarget) -> Self {
91 Self::GraphLocal { target }
92 }
93
94 pub fn graph() -> Self {
95 Self::graph_local(GraphLocalBindingTarget::Graph)
96 }
97
98 pub fn node(id: NodeId) -> Self {
99 Self::graph_local(GraphLocalBindingTarget::node(id))
100 }
101
102 pub fn port(id: PortId) -> Self {
103 Self::graph_local(GraphLocalBindingTarget::port(id))
104 }
105
106 pub fn edge(id: EdgeId) -> Self {
107 Self::graph_local(GraphLocalBindingTarget::edge(id))
108 }
109
110 pub fn group(id: GroupId) -> Self {
111 Self::graph_local(GraphLocalBindingTarget::group(id))
112 }
113
114 pub fn sticky_note(id: StickyNoteId) -> Self {
115 Self::graph_local(GraphLocalBindingTarget::sticky_note(id))
116 }
117
118 pub fn source(anchor: SourceAnchor) -> Self {
119 Self::Source { anchor }
120 }
121
122 pub fn source_payload(source_id: impl Into<String>, payload: Value) -> Self {
123 Self::source(SourceAnchor::new(source_id, payload))
124 }
125
126 pub fn graph_local_target(&self) -> Option<GraphLocalBindingTarget> {
127 match self {
128 Self::GraphLocal { target } => Some(*target),
129 Self::Source { .. } => None,
130 }
131 }
132}
133
134impl GraphLocalBindingTarget {
135 pub fn node(id: NodeId) -> Self {
136 Self::Node { id }
137 }
138
139 pub fn port(id: PortId) -> Self {
140 Self::Port { id }
141 }
142
143 pub fn edge(id: EdgeId) -> Self {
144 Self::Edge { id }
145 }
146
147 pub fn group(id: GroupId) -> Self {
148 Self::Group { id }
149 }
150
151 pub fn sticky_note(id: StickyNoteId) -> Self {
152 Self::StickyNote { id }
153 }
154}
155
156impl SourceAnchor {
157 pub fn new(source_id: impl Into<String>, payload: Value) -> Self {
158 Self {
159 source_id: source_id.into(),
160 payload,
161 }
162 }
163}