intrepid_core/
frame.rs

1mod frame_outbox;
2
3use bytes::Bytes;
4use serde::{Deserialize, Serialize};
5use tower::BoxError;
6
7pub use frame_outbox::FrameOutbox;
8
9/// An addressed frame.
10#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
11pub struct MessageFrame {
12    /// The address of the frame.
13    pub uri: String,
14    /// The frame contents.
15    pub data: Bytes,
16    /// The frame metadata.
17    pub meta: Bytes,
18}
19
20/// A frame that can be processed by an action.
21#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
22pub enum Frame {
23    /// A unit frame, with nothing in it.
24    #[default]
25    Unit,
26    /// An error frame.
27    Error(Bytes),
28    /// An unaddressed chunk of bytes.
29    Anonymous(Bytes),
30    /// An addressed frame.
31    Message(MessageFrame),
32}
33
34impl Frame {
35    /// Create a new frame from a given set of bytes.
36    pub fn new(bytes: impl Into<Bytes>) -> Self {
37        let bytes = bytes.into();
38
39        if bytes.is_empty() {
40            Frame::Unit
41        } else {
42            Frame::Anonymous(bytes)
43        }
44    }
45
46    /// Create a message frame.
47    pub fn message(uri: impl AsRef<str>, data: impl Into<Frame>, meta: impl Into<Frame>) -> Self {
48        Frame::Message(MessageFrame {
49            uri: uri.as_ref().into(),
50            data: data.into().into_bytes(),
51            meta: meta.into().into_bytes(),
52        })
53    }
54
55    /// The length of the frame in bytes.
56    ///
57    pub fn len(&self) -> usize {
58        match self {
59            Frame::Unit => 0,
60            Frame::Error(data)
61            | Frame::Anonymous(data)
62            | Frame::Message(MessageFrame { data, .. }) => data.len(),
63        }
64    }
65
66    /// Check if the frame is empty.
67    pub fn is_empty(&self) -> bool {
68        self.len() == 0
69    }
70
71    /// Get a reference to the frame as a slice of bytes.
72    pub fn as_bytes(&self) -> &[u8] {
73        match self {
74            Frame::Unit => &[],
75            Frame::Error(data)
76            | Frame::Anonymous(data)
77            | Frame::Message(MessageFrame { data, .. }) => data.as_ref(),
78        }
79    }
80
81    /// Convert the frame's body into a vector of bytes.
82    ///
83    pub fn into_bytes(self) -> Bytes {
84        match self {
85            Frame::Unit => Bytes::new(),
86            Frame::Error(data)
87            | Frame::Anonymous(data)
88            | Frame::Message(MessageFrame { data, .. }) => data,
89        }
90    }
91}
92
93impl AsRef<[u8]> for Frame {
94    fn as_ref(&self) -> &[u8] {
95        self.as_bytes()
96    }
97}
98
99impl From<Vec<u8>> for Frame {
100    fn from(value: Vec<u8>) -> Self {
101        Bytes::from(value).into()
102    }
103}
104
105impl<T> From<Vec<T>> for Frame
106where
107    T: Into<Frame>,
108{
109    fn from(value: Vec<T>) -> Self {
110        let mut bytes: Vec<u8> = vec![];
111
112        for value in value {
113            bytes.extend_from_slice(value.into().as_ref());
114        }
115
116        Bytes::from(bytes).into()
117    }
118}
119
120impl From<()> for Frame {
121    fn from(_: ()) -> Self {
122        Frame::default()
123    }
124}
125
126impl From<Bytes> for Frame {
127    fn from(bytes: Bytes) -> Self {
128        Frame::new(bytes)
129    }
130}
131
132impl From<Frame> for Bytes {
133    fn from(frame: Frame) -> Bytes {
134        frame.into_bytes()
135    }
136}
137
138impl From<Frame> for String {
139    fn from(value: Frame) -> Self {
140        String::from_utf8_lossy(value.as_ref()).into_owned()
141    }
142}
143
144impl From<String> for Frame {
145    fn from(value: String) -> Self {
146        Frame::new(value)
147    }
148}
149
150impl<T> From<Option<T>> for Frame
151where
152    T: Into<Frame>,
153{
154    fn from(option: Option<T>) -> Self {
155        match option {
156            Some(value) => value.into(),
157            None => Frame::default(),
158        }
159    }
160}
161
162impl<T, E> From<Result<T, E>> for Frame
163where
164    T: Into<Frame>,
165    E: Into<Frame>,
166{
167    fn from(result: Result<T, E>) -> Self {
168        match result {
169            Ok(value) => value.into(),
170            Err(error) => error.into(),
171        }
172    }
173}
174
175impl From<BoxError> for Frame {
176    fn from(error: BoxError) -> Self {
177        error.to_string().into()
178    }
179}