Skip to main content

plexor_core/
payload.rs

1// Copyright 2025 Alecks Gates
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use crate::codec::{Codec, CodecName};
8use crate::logging::TraceContext;
9use crate::neuron::Neuron;
10use std::sync::Arc;
11use uuid::Uuid;
12
13#[derive(Debug)]
14pub struct Payload<T, C> {
15    pub value: Arc<T>,
16    pub neuron: Arc<dyn Neuron<T, C> + Send + Sync>,
17    pub trace: TraceContext,
18}
19
20impl<T, C> Payload<T, C> {
21    pub fn from_parts(
22        value: Arc<T>,
23        neuron: Arc<dyn Neuron<T, C> + Send + Sync>,
24        trace: TraceContext,
25    ) -> Self {
26        Self {
27            value,
28            neuron,
29            trace,
30        }
31    }
32
33    /// Helper to create a new Payload with default tracing fields (new span_id, no parent_id).
34    /// Used when initiating a new signal.
35    pub fn with_correlation(
36        value: T,
37        neuron: Arc<dyn Neuron<T, C> + Send + Sync>,
38        correlation_id: Option<Uuid>,
39    ) -> Arc<Self>
40    where
41        T: Send + Sync + 'static,
42        C: Codec<T> + CodecName + Send + Sync + 'static,
43    {
44        let correlation = correlation_id.unwrap_or_else(Uuid::now_v7);
45        // New trace: span_id is lower 64 bits of correlation_id
46        let span_id = correlation.as_u128() as u64;
47
48        Arc::new(Payload::from_parts(
49            Arc::new(value),
50            neuron,
51            TraceContext::from_parts(correlation, span_id, None),
52        ))
53    }
54
55    /// Simplified creation method for new signals.
56    /// automatically generates correlation_id and other tracing fields.
57    pub fn new(value: T, neuron: Arc<dyn Neuron<T, C> + Send + Sync>) -> Arc<Self>
58    where
59        T: Send + Sync + 'static,
60        C: Codec<T> + CodecName + Send + Sync + 'static,
61    {
62        Self::with_correlation(value, neuron, None)
63    }
64
65    pub fn builder() -> PayloadBuilder<T, C> {
66        PayloadBuilder::default()
67    }
68
69    pub fn correlation_id(&self) -> Uuid {
70        self.trace.correlation_id
71    }
72
73    pub fn span_id(&self) -> u64 {
74        self.trace.span_id
75    }
76
77    pub fn parent_id(&self) -> Option<u64> {
78        self.trace.parent_id
79    }
80}
81
82pub struct PayloadBuilder<T, C> {
83    value: Option<T>,
84    correlation_id: Option<Uuid>,
85    neuron: Option<Arc<dyn Neuron<T, C> + Send + Sync>>,
86    span_id: Option<u64>,
87    parent_id: Option<u64>,
88}
89
90impl<T, C> Default for PayloadBuilder<T, C> {
91    fn default() -> Self {
92        Self {
93            value: None,
94            correlation_id: None,
95            neuron: None,
96            span_id: None,
97            parent_id: None,
98        }
99    }
100}
101
102impl<T, C> PayloadBuilder<T, C> {
103    pub fn value(mut self, value: T) -> Self {
104        self.value = Some(value);
105        self
106    }
107
108    pub fn correlation_id(mut self, id: Uuid) -> Self {
109        self.correlation_id = Some(id);
110        self
111    }
112
113    pub fn neuron(mut self, neuron: Arc<dyn Neuron<T, C> + Send + Sync>) -> Self {
114        self.neuron = Some(neuron);
115        self
116    }
117
118    pub fn span_id(mut self, id: u64) -> Self {
119        self.span_id = Some(id);
120        self
121    }
122
123    pub fn parent_id(mut self, id: u64) -> Self {
124        self.parent_id = Some(id);
125        self
126    }
127
128    pub fn build(self) -> Result<Arc<Payload<T, C>>, String>
129    where
130        T: Send + Sync + 'static,
131        C: Codec<T> + CodecName + Send + Sync + 'static,
132    {
133        let value = self.value.ok_or("Value is required")?;
134        let neuron = self.neuron.ok_or("Neuron is required")?;
135        let correlation = self.correlation_id.unwrap_or_else(Uuid::now_v7);
136
137        let span = self.span_id.unwrap_or_else(|| correlation.as_u128() as u64);
138
139        Ok(Arc::new(Payload {
140            value: Arc::new(value),
141            neuron,
142            trace: TraceContext::from_parts(correlation, span, self.parent_id),
143        }))
144    }
145}
146
147#[derive(Debug)]
148pub struct PayloadRaw<T, C> {
149    pub value: Arc<Vec<u8>>,
150    pub neuron: Option<Arc<dyn Neuron<T, C> + Send + Sync>>,
151    pub trace: TraceContext,
152}
153
154impl<T, C> PayloadRaw<T, C> {
155    pub fn from_parts(
156        value: Arc<Vec<u8>>,
157        neuron: Option<Arc<dyn Neuron<T, C> + Send + Sync>>,
158        trace: TraceContext,
159    ) -> Self {
160        Self {
161            value,
162            neuron,
163            trace,
164        }
165    }
166
167    /// Helper to create a new PayloadRaw with default tracing fields (new span_id, no parent_id).
168    /// Used when initiating a new signal where payload is already raw bytes.
169    pub fn with_correlation(
170        value: Vec<u8>,
171        neuron: Option<Arc<dyn Neuron<T, C> + Send + Sync>>,
172        correlation_id: Option<Uuid>,
173    ) -> Arc<Self>
174    where
175        T: Send + Sync + 'static,
176        C: Codec<T> + CodecName + Send + Sync + 'static,
177    {
178        let correlation = correlation_id.unwrap_or_else(Uuid::now_v7);
179        let span_id = correlation.as_u128() as u64;
180
181        Arc::new(PayloadRaw::from_parts(
182            Arc::new(value),
183            neuron,
184            TraceContext::from_parts(correlation, span_id, None),
185        ))
186    }
187
188    pub fn new(value: Vec<u8>, neuron: Option<Arc<dyn Neuron<T, C> + Send + Sync>>) -> Arc<Self>
189    where
190        T: Send + Sync + 'static,
191        C: Codec<T> + CodecName + Send + Sync + 'static,
192    {
193        Self::with_correlation(value, neuron, None)
194    }
195
196    pub fn correlation_id(&self) -> Uuid {
197        self.trace.correlation_id
198    }
199
200    pub fn span_id(&self) -> u64 {
201        self.trace.span_id
202    }
203
204    pub fn parent_id(&self) -> Option<u64> {
205        self.trace.parent_id
206    }
207}