1#![cfg_attr(not(feature = "std"), no_std)]
23#[cfg(not(feature = "std"))]
24extern crate alloc;
25
26use bincode::de::{BorrowDecoder, Decoder};
27use bincode::enc::Encoder;
28use bincode::error::{DecodeError, EncodeError};
29use bincode::{BorrowDecode, Decode as dDecode, Decode, Encode, Encode as dEncode};
30use compact_str::CompactString;
31#[cfg(not(feature = "std"))]
32use core::error::Error as CoreError;
33use cu29_clock::{PartialCuTimeRange, Tov};
34use serde::{Deserialize, Serialize};
35
36#[cfg(feature = "std")]
37use std::fmt::{Debug, Display, Formatter};
38
39#[cfg(not(feature = "std"))]
40use alloc::string::{String, ToString};
41#[cfg(not(feature = "std"))]
42use alloc::vec::Vec;
43#[cfg(not(feature = "std"))]
44use core::fmt::{Debug, Display, Formatter};
45#[cfg(feature = "std")]
46use std::error::Error;
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct CuError {
51 message: String,
52 cause: Option<String>,
53}
54
55impl Display for CuError {
56 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
57 let context_str = match &self.cause {
58 Some(c) => c.to_string(),
59 None => "None".to_string(),
60 };
61 write!(f, "{}\n context:{}", self.message, context_str)?;
62 Ok(())
63 }
64}
65
66#[cfg(not(feature = "std"))]
67impl CoreError for CuError {}
68
69#[cfg(feature = "std")]
70impl Error for CuError {}
71
72impl From<&str> for CuError {
73 fn from(s: &str) -> CuError {
74 CuError {
75 message: s.to_string(),
76 cause: None,
77 }
78 }
79}
80
81impl From<String> for CuError {
82 fn from(s: String) -> CuError {
83 CuError {
84 message: s,
85 cause: None,
86 }
87 }
88}
89
90impl CuError {
91 pub fn new_with_cause(message: &str, cause: impl Display) -> CuError {
92 CuError {
93 message: message.to_string(),
94 cause: Some(cause.to_string()),
95 }
96 }
97
98 pub fn add_cause(mut self, context: &str) -> CuError {
99 self.cause = Some(context.into());
100 self
101 }
102}
103
104pub type CuResult<T> = Result<T, CuError>;
106
107pub trait WriteStream<E: Encode>: Debug + Send + Sync {
109 fn log(&mut self, obj: &E) -> CuResult<()>;
110 fn flush(&mut self) -> CuResult<()> {
111 Ok(())
112 }
113}
114
115#[derive(dEncode, dDecode, Copy, Clone, Debug, PartialEq)]
117pub enum UnifiedLogType {
118 Empty, StructuredLogLine, CopperList, FrozenTasks, LastEntry, }
124pub trait Metadata: Default + Debug + Clone + Encode + Decode<()> + Serialize {}
126
127impl Metadata for () {}
128
129pub trait CuMsgMetadataTrait {
131 fn process_time(&self) -> PartialCuTimeRange;
133
134 fn status_txt(&self) -> &CuCompactString;
136}
137
138pub trait ErasedCuStampedData {
140 fn payload(&self) -> Option<&dyn erased_serde::Serialize>;
141 fn tov(&self) -> Tov;
142 fn metadata(&self) -> &dyn CuMsgMetadataTrait;
143}
144
145pub trait ErasedCuStampedDataSet {
148 fn cumsgs(&self) -> Vec<&dyn ErasedCuStampedData>;
149}
150
151pub trait MatchingTasks {
153 fn get_all_task_ids() -> &'static [&'static str];
154}
155
156pub trait CopperListTuple:
158 bincode::Encode
159 + bincode::Decode<()>
160 + Debug
161 + Serialize
162 + ErasedCuStampedDataSet
163 + MatchingTasks
164 + Default
165{
166} impl<T> CopperListTuple for T where
170 T: bincode::Encode
171 + bincode::Decode<()>
172 + Debug
173 + Serialize
174 + ErasedCuStampedDataSet
175 + MatchingTasks
176 + Default
177{
178}
179
180pub const COMPACT_STRING_CAPACITY: usize = size_of::<String>();
184
185#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
186pub struct CuCompactString(pub CompactString);
187
188impl Encode for CuCompactString {
189 fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
190 let CuCompactString(ref compact_string) = self;
191 let bytes = &compact_string.as_bytes();
192 bytes.encode(encoder)
193 }
194}
195
196impl Debug for CuCompactString {
197 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
198 if self.0.is_empty() {
199 return write!(f, "CuCompactString(Empty)");
200 }
201 write!(f, "CuCompactString({})", self.0)
202 }
203}
204
205impl<Context> Decode<Context> for CuCompactString {
206 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
207 let bytes = <Vec<u8> as Decode<D::Context>>::decode(decoder)?; let compact_string =
209 CompactString::from_utf8(bytes).map_err(|e| DecodeError::Utf8 { inner: e })?;
210 Ok(CuCompactString(compact_string))
211 }
212}
213
214impl<'de, Context> BorrowDecode<'de, Context> for CuCompactString {
215 fn borrow_decode<D: BorrowDecoder<'de>>(decoder: &mut D) -> Result<Self, DecodeError> {
216 CuCompactString::decode(decoder)
217 }
218}
219
220#[cfg(feature = "defmt")]
221impl defmt::Format for CuError {
222 fn format(&self, f: defmt::Formatter) {
223 match &self.cause {
224 Some(c) => defmt::write!(
225 f,
226 "CuError {{ message: {}, cause: {} }}",
227 defmt::Display2Format(&self.message),
228 defmt::Display2Format(c),
229 ),
230 None => defmt::write!(
231 f,
232 "CuError {{ message: {}, cause: None }}",
233 defmt::Display2Format(&self.message),
234 ),
235 }
236 }
237}
238
239#[cfg(feature = "defmt")]
240impl defmt::Format for CuCompactString {
241 fn format(&self, f: defmt::Formatter) {
242 if self.0.is_empty() {
243 defmt::write!(f, "CuCompactString(Empty)");
244 } else {
245 defmt::write!(f, "CuCompactString({})", defmt::Display2Format(&self.0));
246 }
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use crate::CuCompactString;
253 use bincode::{config, decode_from_slice, encode_to_vec};
254 use compact_str::CompactString;
255
256 #[test]
257 fn test_cucompactstr_encode_decode_empty() {
258 let cstr = CuCompactString(CompactString::from(""));
259 let config = config::standard();
260 let encoded = encode_to_vec(&cstr, config).expect("Encoding failed");
261 assert_eq!(encoded.len(), 1); let (decoded, _): (CuCompactString, usize) =
263 decode_from_slice(&encoded, config).expect("Decoding failed");
264 assert_eq!(cstr.0, decoded.0);
265 }
266
267 #[test]
268 fn test_cucompactstr_encode_decode_small() {
269 let cstr = CuCompactString(CompactString::from("test"));
270 let config = config::standard();
271 let encoded = encode_to_vec(&cstr, config).expect("Encoding failed");
272 assert_eq!(encoded.len(), 5); let (decoded, _): (CuCompactString, usize) =
274 decode_from_slice(&encoded, config).expect("Decoding failed");
275 assert_eq!(cstr.0, decoded.0);
276 }
277}