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