futuresdr_types/
pmt.rs

1use dyn_clone::DynClone;
2use num_complex::Complex32;
3use serde::{Deserialize, Serialize};
4use std::any::Any;
5use std::collections::HashMap;
6use std::fmt;
7use thiserror::Error;
8
9/// PMT Any trait
10///
11/// This trait has to be implemented by types that should be used with [`Pmt::Any`].
12pub trait PmtAny: Any + DynClone + Send + Sync + 'static {
13    /// Cast to [`Any`](std::any::Any)
14    fn as_any(&self) -> &dyn Any;
15    /// Cast to mutable [`Any`](std::any::Any)
16    fn as_any_mut(&mut self) -> &mut dyn Any;
17}
18dyn_clone::clone_trait_object!(PmtAny);
19
20impl<T: Any + DynClone + Send + Sync + 'static> PmtAny for T {
21    fn as_any(&self) -> &dyn Any {
22        self
23    }
24    fn as_any_mut(&mut self) -> &mut dyn Any {
25        self
26    }
27}
28
29impl fmt::Debug for Box<dyn PmtAny> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        write!(f, "Box<dyn Any>")
32    }
33}
34
35impl dyn PmtAny {
36    /// Try to cast the [`Pmt::Any`] to the given type.
37    pub fn downcast_ref<T: PmtAny>(&self) -> Option<&T> {
38        (*self).as_any().downcast_ref::<T>()
39    }
40    /// Try to cast the [`Pmt::Any`] to the given type mutably.
41    pub fn downcast_mut<T: PmtAny>(&mut self) -> Option<&mut T> {
42        (*self).as_any_mut().downcast_mut::<T>()
43    }
44}
45
46/// PMT -- Polymorphic Type
47///
48/// PMTs are used as input and output for the FutureSDR message passing interface. At the moment,
49/// the `Any` type is ignored for de-/serialization.
50#[non_exhaustive]
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub enum Pmt {
53    /// Ok.
54    Ok,
55    /// Invalid value
56    ///
57    /// Mainly used as the return type in message handlers, when the parameter is outside the
58    /// allowed range.
59    InvalidValue,
60    /// Null
61    ///
62    /// Used, for example, as the input type, when the message handler is mainly about the return
63    /// type.
64    Null,
65    /// String
66    String(String),
67    /// Boolean
68    Bool(bool),
69    /// Usize
70    Usize(usize),
71    /// Isize
72    Isize(isize),
73    /// U32, 32-bit unsiged integer
74    U32(u32),
75    /// U64, 64-bit unsigned integer
76    U64(u64),
77    /// F32, 32-bit float
78    F32(f32),
79    /// F64, 64-bit float
80    F64(f64),
81    /// Vector of 32-bit complex floats.
82    VecCF32(Vec<Complex32>),
83    /// Vector of 32-bit floats.
84    VecF32(Vec<f32>),
85    /// Vector of 64-bit floats.
86    VecU64(Vec<u64>),
87    /// Binary data blob
88    Blob(Vec<u8>),
89    /// Vector of [`Pmts`](Pmt)
90    VecPmt(Vec<Pmt>),
91    /// Finished
92    ///
93    /// Runtime message, used to signal the handler that a connected block finished.
94    Finished,
95    /// Map (String -> Pmt)
96    MapStrPmt(HashMap<String, Pmt>),
97    /// Any type
98    ///
99    /// Wrap anything that implements [`Any`](std::any::Any) in a Pmt. Use
100    /// `downcast_ref/mut()` to extract.
101    #[serde(skip)]
102    Any(Box<dyn PmtAny>),
103}
104
105impl fmt::Display for Pmt {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            Pmt::Ok => write!(f, "Ok"),
109            Pmt::InvalidValue => write!(f, "InvalidValue"),
110            Pmt::Null => write!(f, "Null"),
111            Pmt::String(v) => write!(f, "{}", v),
112            Pmt::Bool(v) => write!(f, "{}", v),
113            Pmt::Usize(v) => write!(f, "{}", v),
114            Pmt::Isize(v) => write!(f, "{}", v),
115            Pmt::U32(v) => write!(f, "{}", v),
116            Pmt::U64(v) => write!(f, "{}", v),
117            Pmt::F32(v) => write!(f, "{}", v),
118            Pmt::F64(v) => write!(f, "{}", v),
119            Pmt::VecCF32(v) => write!(f, "{:?}", v),
120            Pmt::VecF32(v) => write!(f, "{:?}", v),
121            Pmt::VecU64(v) => write!(f, "{:?}", v),
122            Pmt::Blob(v) => write!(f, "{:?}", v),
123            Pmt::VecPmt(v) => write!(f, "{:?}", v),
124            Pmt::Finished => write!(f, "Finished"),
125            Pmt::MapStrPmt(v) => write!(f, "{:?}", v),
126            Pmt::Any(v) => write!(f, "{:?}", v),
127        }
128    }
129}
130
131impl PartialEq for Pmt {
132    fn eq(&self, other: &Self) -> bool {
133        match (self, other) {
134            (Pmt::Ok, Pmt::Ok) => true,
135            (Pmt::InvalidValue, Pmt::InvalidValue) => true,
136            (Pmt::Null, Pmt::Null) => true,
137            (Pmt::String(x), Pmt::String(y)) => x == y,
138            (Pmt::Bool(x), Pmt::Bool(y)) => x == y,
139            (Pmt::Usize(x), Pmt::Usize(y)) => x == y,
140            (Pmt::Isize(x), Pmt::Isize(y)) => x == y,
141            (Pmt::U32(x), Pmt::U32(y)) => x == y,
142            (Pmt::U64(x), Pmt::U64(y)) => x == y,
143            (Pmt::F32(x), Pmt::F32(y)) => x == y,
144            (Pmt::F64(x), Pmt::F64(y)) => x == y,
145            (Pmt::VecF32(x), Pmt::VecF32(y)) => x == y,
146            (Pmt::VecU64(x), Pmt::VecU64(y)) => x == y,
147            (Pmt::Blob(x), Pmt::Blob(y)) => x == y,
148            (Pmt::VecPmt(x), Pmt::VecPmt(y)) => x == y,
149            (Pmt::Finished, Pmt::Finished) => true,
150            (Pmt::MapStrPmt(x), Pmt::MapStrPmt(y)) => x == y,
151            _ => false,
152        }
153    }
154}
155
156impl std::str::FromStr for Pmt {
157    type Err = PmtConversionError;
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        match s {
161            "Ok" | "ok" => return Ok(Pmt::Ok),
162            "Null" | "null" => return Ok(Pmt::Null),
163            "true" => return Ok(Pmt::Bool(true)),
164            "false" => return Ok(Pmt::Bool(false)),
165            "InvalidValue" | "invalidvalue" => return Ok(Pmt::InvalidValue),
166            "Finished" | "finished" => return Ok(Pmt::Finished),
167            _ => (),
168        }
169
170        if let Ok(p) = serde_json::from_str(s) {
171            return Ok(p);
172        }
173
174        if let Some((a, b)) = s.split_once(':') {
175            let s = format!("{{ \"{}\": {}}}", a, b);
176            if let Ok(p) = serde_json::from_str(&s) {
177                return Ok(p);
178            }
179        }
180        Err(PmtConversionError)
181    }
182}
183
184impl Pmt {
185    /// Create a [`Pmt`] by parsing a string into a specific [`PmtKind`].
186    pub fn from_string(s: &str, t: &PmtKind) -> Option<Pmt> {
187        match t {
188            PmtKind::U32 => {
189                if let Ok(v) = s.parse::<u32>() {
190                    Some(Pmt::U32(v))
191                } else {
192                    None
193                }
194            }
195            PmtKind::U64 => {
196                if let Ok(v) = s.parse::<u64>() {
197                    Some(Pmt::U64(v))
198                } else {
199                    None
200                }
201            }
202            PmtKind::F32 => {
203                if let Ok(v) = s.parse::<f32>() {
204                    Some(Pmt::F32(v))
205                } else {
206                    None
207                }
208            }
209            PmtKind::F64 => {
210                if let Ok(v) = s.parse::<f64>() {
211                    Some(Pmt::F64(v))
212                } else {
213                    None
214                }
215            }
216            PmtKind::String => Some(Pmt::String(s.to_string())),
217            _ => None,
218        }
219    }
220}
221
222/// PMT conversion error.
223///
224/// This error is returned, if conversion to/from PMTs fail.
225#[derive(Debug, Clone, Error, PartialEq)]
226#[error("PMt conversion error")]
227pub struct PmtConversionError;
228
229impl TryInto<f64> for Pmt {
230    type Error = PmtConversionError;
231
232    fn try_into(self) -> Result<f64, Self::Error> {
233        match self {
234            Pmt::F32(f) => Ok(f as f64),
235            Pmt::F64(f) => Ok(f),
236            Pmt::U32(f) => Ok(f as f64),
237            Pmt::U64(f) => Ok(f as f64),
238            _ => Err(PmtConversionError),
239        }
240    }
241}
242
243impl TryInto<usize> for Pmt {
244    type Error = PmtConversionError;
245
246    fn try_into(self) -> Result<usize, Self::Error> {
247        match self {
248            Pmt::Usize(f) => Ok(f),
249            _ => Err(PmtConversionError),
250        }
251    }
252}
253
254impl TryInto<isize> for Pmt {
255    type Error = PmtConversionError;
256
257    fn try_into(self) -> Result<isize, Self::Error> {
258        match self {
259            Pmt::Isize(f) => Ok(f),
260            _ => Err(PmtConversionError),
261        }
262    }
263}
264
265impl TryInto<u64> for Pmt {
266    type Error = PmtConversionError;
267
268    fn try_into(self) -> Result<u64, Self::Error> {
269        match self {
270            Pmt::U32(v) => Ok(v as u64),
271            Pmt::U64(v) => Ok(v),
272            Pmt::Usize(v) => Ok(v as u64),
273            _ => Err(PmtConversionError),
274        }
275    }
276}
277
278/// PMT types that do not wrap values.
279///
280/// Usefull for bindings to other languages that do not support Rust's broad enum features.
281#[non_exhaustive]
282#[derive(Clone, PartialEq, Eq)]
283pub enum PmtKind {
284    /// Ok
285    Ok,
286    /// Invalid value
287    InvalidValue,
288    /// Null
289    Null,
290    /// String
291    String,
292    /// Bool
293    Bool,
294    /// Usize
295    Usize,
296    /// Isize
297    Isize,
298    /// U32
299    U32,
300    /// U64
301    U64,
302    /// F32
303    F32,
304    /// F64
305    F64,
306    /// VecCF32
307    VecCF32,
308    /// VecF32
309    VecF32,
310    /// VecU64
311    VecU64,
312    /// Blob
313    Blob,
314    /// Vec Pmt
315    VecPmt,
316    /// Finished
317    Finished,
318    /// Map String -> Pmt
319    MapStrPmt,
320    /// Any
321    Any,
322}
323
324impl fmt::Display for PmtKind {
325    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326        match self {
327            PmtKind::Ok => write!(f, "Ok"),
328            PmtKind::InvalidValue => write!(f, "InvalidValue"),
329            PmtKind::Null => write!(f, "Null"),
330            PmtKind::String => write!(f, "String"),
331            PmtKind::Bool => write!(f, "Bool"),
332            PmtKind::Usize => write!(f, "Usize"),
333            PmtKind::Isize => write!(f, "isize"),
334            PmtKind::U32 => write!(f, "U32"),
335            PmtKind::U64 => write!(f, "U64"),
336            PmtKind::F32 => write!(f, "F32"),
337            PmtKind::F64 => write!(f, "F64"),
338            PmtKind::VecCF32 => write!(f, "VecCF32"),
339            PmtKind::VecF32 => write!(f, "VecF32"),
340            PmtKind::VecU64 => write!(f, "VecU64"),
341            PmtKind::Blob => write!(f, "Blob"),
342            PmtKind::VecPmt => write!(f, "VecPmt"),
343            PmtKind::Finished => write!(f, "Finished"),
344            PmtKind::MapStrPmt => write!(f, "MapStrPmt"),
345            PmtKind::Any => write!(f, "Any"),
346        }
347    }
348}
349
350impl std::str::FromStr for PmtKind {
351    type Err = PmtConversionError;
352
353    fn from_str(s: &str) -> Result<Self, Self::Err> {
354        match s {
355            "Ok" => return Ok(PmtKind::Ok),
356            "InvalidValue" => return Ok(PmtKind::InvalidValue),
357            "Null" => return Ok(PmtKind::Null),
358            "String" => return Ok(PmtKind::String),
359            "Bool" => return Ok(PmtKind::Bool),
360            "Usize" => return Ok(PmtKind::Usize),
361            "Isize" => return Ok(PmtKind::Isize),
362            "U32" => return Ok(PmtKind::U32),
363            "U64" => return Ok(PmtKind::U64),
364            "F32" => return Ok(PmtKind::F32),
365            "F64" => return Ok(PmtKind::F64),
366            "VecF32" => return Ok(PmtKind::VecF32),
367            "VecU64" => return Ok(PmtKind::VecU64),
368            "Blob" => return Ok(PmtKind::Blob),
369            "VecPmt" => return Ok(PmtKind::VecPmt),
370            "Finished" => return Ok(PmtKind::Finished),
371            "MapStrPmt" => return Ok(PmtKind::MapStrPmt),
372            "Any" => return Ok(PmtKind::Any),
373            _ => (),
374        }
375        Err(PmtConversionError)
376    }
377}
378
379#[cfg(test)]
380mod test {
381    use super::*;
382
383    #[test]
384    fn pmt() {
385        let p = Pmt::Null;
386        assert_eq!(p.to_string(), "Null");
387        let p = Pmt::String("foo".to_string());
388        assert_eq!(p.to_string(), "foo");
389    }
390
391    #[test]
392    fn pmt_parse_json() {
393        let s = "{ \"U32\": 123 }";
394        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::U32(123)));
395        let s = "{ \"Bool\": true }";
396        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Bool(true)));
397        let s = "Bool: true";
398        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Bool(true)));
399        let s = "U32: 123";
400        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::U32(123)));
401        let s = "F64: 123";
402        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::F64(123.0)));
403        let s = "Blob: [1,2,3]";
404        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Blob(vec![1, 2, 3])));
405    }
406
407    #[test]
408    fn pmt_serde() {
409        let p = Pmt::Null;
410        let mut s = flexbuffers::FlexbufferSerializer::new();
411        p.serialize(&mut s).unwrap();
412
413        let r = flexbuffers::Reader::get_root(s.view()).unwrap();
414        let p2 = Pmt::deserialize(r).unwrap();
415
416        assert_eq!(p, p2);
417    }
418
419    #[allow(clippy::many_single_char_names)]
420    #[test]
421    fn pmt_eq() {
422        let a = Pmt::Null;
423        let b = Pmt::U32(123);
424        assert_ne!(a, b);
425
426        let c = Pmt::Null;
427        let d = Pmt::U32(12);
428        let e = Pmt::U32(123);
429        assert_eq!(a, c);
430        assert_eq!(b, e);
431        assert_ne!(b, d);
432
433        let f1 = Pmt::F32(0.1);
434        let f2 = Pmt::F32(0.1);
435        let f3 = Pmt::F32(0.2);
436        assert_eq!(f1, f2);
437        assert_ne!(f1, f3);
438    }
439
440    #[test]
441    fn vec_pmt() {
442        let vpmt = Pmt::VecPmt(vec![Pmt::U32(1), Pmt::U32(2)]);
443
444        if let Pmt::VecPmt(v) = vpmt {
445            assert_eq!(v[0], Pmt::U32(1));
446            assert_eq!(v[1], Pmt::U32(2));
447        } else {
448            panic!("Not a Pmt::VecPmt");
449        }
450    }
451
452    #[test]
453    fn map_str_pmt() {
454        let u32val = 42;
455        let f64val = 6.02214076e23;
456
457        let msp = Pmt::MapStrPmt(HashMap::from([
458            ("str".to_owned(), Pmt::String("a string".to_owned())),
459            (
460                "submap".to_owned(),
461                Pmt::MapStrPmt(HashMap::from([
462                    ("U32".to_owned(), Pmt::U32(u32val)),
463                    ("F64".to_owned(), Pmt::F64(f64val)),
464                ])),
465            ),
466        ]));
467
468        if let Pmt::MapStrPmt(m) = msp {
469            if let Some(Pmt::MapStrPmt(sm)) = m.get("submap") {
470                assert_eq!(sm.get("U32"), Some(&Pmt::U32(u32val)));
471                assert_eq!(sm.get("F64"), Some(&Pmt::F64(f64val)));
472            } else {
473                panic!("Could not get submap");
474            }
475        } else {
476            panic!("Not a Pmt::MapStrPmt");
477        }
478    }
479}