futuresdr_pmt/
lib.rs

1use dyn_clone::DynClone;
2use serde::{Deserialize, Serialize};
3use std::any::Any;
4use std::collections::HashMap;
5use std::fmt;
6
7mod description;
8pub use description::BlockDescription;
9pub use description::FlowgraphDescription;
10
11pub trait PmtAny: Any + DynClone + Send + Sync + 'static {
12    fn as_any(&self) -> &dyn Any;
13    fn as_any_mut(&mut self) -> &mut dyn Any;
14}
15dyn_clone::clone_trait_object!(PmtAny);
16
17impl<T: Any + DynClone + Send + Sync + 'static> PmtAny for T {
18    fn as_any(&self) -> &dyn Any {
19        self
20    }
21    fn as_any_mut(&mut self) -> &mut dyn Any {
22        self
23    }
24}
25
26impl fmt::Debug for Box<dyn PmtAny> {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        write!(f, "Box<dyn Any>")
29    }
30}
31
32impl dyn PmtAny {
33    pub fn downcast_ref<T: PmtAny>(&self) -> Option<&T> {
34        (*self).as_any().downcast_ref::<T>()
35    }
36    pub fn downcast_mut<T: PmtAny>(&mut self) -> Option<&mut T> {
37        (*self).as_any_mut().downcast_mut::<T>()
38    }
39}
40
41#[non_exhaustive]
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub enum Pmt {
44    Ok,
45    InvalidValue,
46    Null,
47    String(String),
48    Bool(bool),
49    Usize(usize),
50    U32(u32),
51    U64(u64),
52    F32(f32),
53    F64(f64),
54    VecF32(Vec<f32>),
55    VecU64(Vec<u64>),
56    Blob(Vec<u8>),
57    VecPmt(Vec<Pmt>),
58    Finished,
59    MapStrPmt(HashMap<String, Pmt>),
60    #[serde(skip)]
61    Any(Box<dyn PmtAny>),
62}
63
64impl PartialEq for Pmt {
65    fn eq(&self, other: &Self) -> bool {
66        match (self, other) {
67            (Pmt::Null, Pmt::Null) => true,
68            (Pmt::String(x), Pmt::String(y)) => x == y,
69            (Pmt::U32(x), Pmt::U32(y)) => x == y,
70            (Pmt::U64(x), Pmt::U64(y)) => x == y,
71            (Pmt::F32(x), Pmt::F32(y)) => x == y,
72            (Pmt::F64(x), Pmt::F64(y)) => x == y,
73            (Pmt::VecF32(x), Pmt::VecF32(y)) => x == y,
74            (Pmt::VecU64(x), Pmt::VecU64(y)) => x == y,
75            (Pmt::Blob(x), Pmt::Blob(y)) => x == y,
76            _ => false,
77        }
78    }
79}
80
81impl Pmt {
82    pub fn is_string(&self) -> bool {
83        matches!(self, Pmt::String(_))
84    }
85
86    pub fn to_string(&self) -> Option<String> {
87        match &self {
88            Pmt::String(s) => Some(s.clone()),
89            _ => None,
90        }
91    }
92
93    pub fn from_string(s: &str, t: &PmtKind) -> Option<Pmt> {
94        match t {
95            PmtKind::U32 => {
96                if let Ok(v) = s.parse::<u32>() {
97                    Some(Pmt::U32(v))
98                } else {
99                    None
100                }
101            }
102            PmtKind::U64 => {
103                if let Ok(v) = s.parse::<u64>() {
104                    Some(Pmt::U64(v))
105                } else {
106                    None
107                }
108            }
109            PmtKind::F32 => {
110                if let Ok(v) = s.parse::<f32>() {
111                    Some(Pmt::F32(v))
112                } else {
113                    None
114                }
115            }
116            PmtKind::F64 => {
117                if let Ok(v) = s.parse::<f64>() {
118                    Some(Pmt::F64(v))
119                } else {
120                    None
121                }
122            }
123            PmtKind::String => Some(Pmt::String(s.to_string())),
124            _ => None,
125        }
126    }
127}
128
129#[derive(Debug, Clone)]
130pub struct PmtConversionError;
131
132impl fmt::Display for PmtConversionError {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        write!(f, "PmtConversionError")
135    }
136}
137
138impl std::error::Error for PmtConversionError {}
139
140impl TryInto<f64> for Pmt {
141    type Error = PmtConversionError;
142
143    fn try_into(self) -> Result<f64, Self::Error> {
144        match self {
145            Pmt::F32(f) => Ok(f as f64),
146            Pmt::F64(f) => Ok(f),
147            Pmt::U32(f) => Ok(f as f64),
148            Pmt::U64(f) => Ok(f as f64),
149            _ => Err(PmtConversionError),
150        }
151    }
152}
153
154impl TryInto<usize> for Pmt {
155    type Error = PmtConversionError;
156
157    fn try_into(self) -> Result<usize, Self::Error> {
158        match self {
159            Pmt::Usize(f) => Ok(f),
160            _ => Err(PmtConversionError),
161        }
162    }
163}
164
165#[non_exhaustive]
166#[derive(Clone, PartialEq, Eq)]
167pub enum PmtKind {
168    Ok,
169    InvalidValue,
170    Null,
171    String,
172    Bool,
173    Usize,
174    U32,
175    U64,
176    F32,
177    F64,
178    VecF32,
179    VecU64,
180    Blob,
181    VecPmt,
182    Finished,
183    MapStrPmt,
184    Any,
185}
186
187#[cfg(test)]
188mod test {
189    use super::*;
190
191    #[test]
192    fn pmt() {
193        let p = Pmt::Null;
194        assert!(!p.is_string());
195        assert_eq!(p.to_string(), None);
196        let p = Pmt::String("foo".to_owned());
197        assert!(p.is_string());
198        assert_eq!(p.to_string(), Some("foo".to_owned()));
199    }
200
201    #[test]
202    fn pmt_serde() {
203        let p = Pmt::Null;
204        let mut s = flexbuffers::FlexbufferSerializer::new();
205        p.serialize(&mut s).unwrap();
206
207        let r = flexbuffers::Reader::get_root(s.view()).unwrap();
208        let p2 = Pmt::deserialize(r).unwrap();
209
210        assert_eq!(p, p2);
211    }
212
213    #[allow(clippy::many_single_char_names)]
214    #[test]
215    fn pmt_eq() {
216        let a = Pmt::Null;
217        let b = Pmt::U32(123);
218        assert_ne!(a, b);
219
220        let c = Pmt::Null;
221        let d = Pmt::U32(12);
222        let e = Pmt::U32(123);
223        assert_eq!(a, c);
224        assert_eq!(b, e);
225        assert_ne!(b, d);
226
227        let f1 = Pmt::F32(0.1);
228        let f2 = Pmt::F32(0.1);
229        let f3 = Pmt::F32(0.2);
230        assert_eq!(f1, f2);
231        assert_ne!(f1, f3);
232    }
233
234    #[test]
235    fn vec_pmt() {
236        let vpmt = Pmt::VecPmt(vec![Pmt::U32(1), Pmt::U32(2)]);
237
238        if let Pmt::VecPmt(v) = vpmt {
239            assert_eq!(v[0], Pmt::U32(1));
240            assert_eq!(v[1], Pmt::U32(2));
241        } else {
242            panic!("Not a Pmt::VecPmt");
243        }
244    }
245
246    #[test]
247    fn map_str_pmt() {
248        let u32val = 42;
249        let f64val = 6.02214076e23;
250
251        let msp = Pmt::MapStrPmt(HashMap::from([
252            ("str".to_owned(), Pmt::String("a string".to_owned())),
253            (
254                "submap".to_owned(),
255                Pmt::MapStrPmt(HashMap::from([
256                    ("U32".to_owned(), Pmt::U32(u32val)),
257                    ("F64".to_owned(), Pmt::F64(f64val)),
258                ])),
259            ),
260        ]));
261
262        if let Pmt::MapStrPmt(m) = msp {
263            if let Some(Pmt::MapStrPmt(sm)) = m.get("submap") {
264                assert_eq!(sm.get("U32"), Some(&Pmt::U32(u32val)));
265                assert_eq!(sm.get("F64"), Some(&Pmt::F64(f64val)));
266            } else {
267                panic!("Could not get submap");
268            }
269        } else {
270            panic!("Not a Pmt::MapStrPmt");
271        }
272    }
273}