Skip to main content

futuresdr_types/
pmt.rs

1use dyn_clone::DynClone;
2use num_complex::Complex32;
3use serde::Deserialize;
4use serde::Serialize;
5use std::any::Any;
6use std::collections::HashMap;
7use std::fmt;
8use thiserror::Error;
9
10/// Trait object support for type-erased in-process PMT payloads.
11///
12/// Any clonable, sendable, sync, `'static` type implements this trait
13/// automatically and can be stored in [`Pmt::Any`]. `Pmt::Any` is not serialized
14/// and is intended for message paths that stay inside one process.
15pub trait PmtAny: Any + DynClone + Send + Sync + 'static {
16    /// Cast to [`Any`](std::any::Any)
17    fn as_any(&self) -> &dyn Any;
18    /// Cast to mutable [`Any`](std::any::Any)
19    fn as_any_mut(&mut self) -> &mut dyn Any;
20    /// Consume `self`, converting to a `Box<dyn Any>`
21    fn to_any(self: Box<Self>) -> Box<dyn Any>;
22}
23dyn_clone::clone_trait_object!(PmtAny);
24
25impl<T: Any + DynClone + Send + Sync + 'static> PmtAny for T {
26    fn as_any(&self) -> &dyn Any {
27        self
28    }
29    fn as_any_mut(&mut self) -> &mut dyn Any {
30        self
31    }
32    fn to_any(self: Box<Self>) -> Box<dyn Any> {
33        self
34    }
35}
36
37impl fmt::Debug for Box<dyn PmtAny> {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(f, "Box<dyn Any>")
40    }
41}
42
43impl dyn PmtAny {
44    /// Determine if this `PmtAny` has the given concrete type.
45    ///
46    /// A value of `true` implies `downcast_ref`, `downcast_mut` and `take` will return `Some`.
47    pub fn is<T: PmtAny>(&self) -> bool {
48        self.as_any().is::<T>()
49    }
50    /// Try to cast the [`Pmt::Any`] to the given type.
51    pub fn downcast_ref<T: PmtAny>(&self) -> Option<&T> {
52        (*self).as_any().downcast_ref::<T>()
53    }
54    /// Try to cast the [`Pmt::Any`] to the given type mutably.
55    pub fn downcast_mut<T: PmtAny>(&mut self) -> Option<&mut T> {
56        (*self).as_any_mut().downcast_mut::<T>()
57    }
58    /// Consuming `self`, try to take ownership of the value as the given type.
59    pub fn take<T: PmtAny>(self: Box<Self>) -> Option<Box<T>> {
60        self.to_any().downcast::<T>().ok()
61    }
62}
63
64/// Polymorphic message type used by FutureSDR message ports.
65///
66/// PMTs are the input and output values for message handlers and runtime
67/// control calls. Most variants serialize normally; [`Pmt::Any`] is skipped
68/// during serialization and is intended only for in-process values.
69///
70/// String parsing accepts a few short forms such as `Ok`, `Null`, `true`, and
71/// `false`, plus serde-compatible enum JSON such as `{ "U32": 123 }` and the
72/// compact `U32: 123` syntax used by simple UIs.
73///
74/// ```
75/// use futuresdr_types::{Pmt, PmtKind};
76///
77/// let pmt = Pmt::Usize(7);
78/// assert_eq!(pmt.kind(), PmtKind::Usize);
79/// assert_eq!(usize::try_from(pmt)?, 7);
80/// # Ok::<(), futuresdr_types::PmtConversionError>(())
81/// ```
82#[non_exhaustive]
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum Pmt {
85    /// Successful operation without additional payload.
86    Ok,
87    /// Invalid value.
88    ///
89    /// Mainly used as the return type in message handlers when the parameter is
90    /// outside the allowed range.
91    InvalidValue,
92    /// Absence of a value.
93    ///
94    /// Used, for example, as the input type, when the message handler is mainly about the return
95    /// type.
96    Null,
97    /// UTF-8 string.
98    String(String),
99    /// Boolean.
100    Bool(bool),
101    /// Native-sized unsigned integer.
102    Usize(usize),
103    /// Native-sized signed integer.
104    Isize(isize),
105    /// 32-bit unsigned integer.
106    U32(u32),
107    /// 64-bit unsigned integer.
108    U64(u64),
109    /// 32-bit float.
110    F32(f32),
111    /// 64-bit float.
112    F64(f64),
113    /// Vector of 32-bit complex floats.
114    VecCF32(Vec<Complex32>),
115    /// Vector of 32-bit floats.
116    VecF32(Vec<f32>),
117    /// Vector of 64-bit unsigned integers.
118    VecU64(Vec<u64>),
119    /// Binary data blob.
120    Blob(Vec<u8>),
121    /// Vector of PMT values.
122    VecPmt(Vec<Pmt>),
123    /// Runtime message used to signal that a connected block finished.
124    Finished,
125    /// Map from string keys to PMT values.
126    MapStrPmt(HashMap<String, Pmt>),
127    /// Type-erased in-process payload.
128    ///
129    /// Wrap anything that implements [`Any`](std::any::Any) in a Pmt. Use
130    /// `downcast_ref/mut()` to extract.
131    #[serde(skip)]
132    Any(Box<dyn PmtAny>),
133}
134
135impl Pmt {
136    /// Get the PMT variant kind without associated data.
137    pub fn kind(&self) -> PmtKind {
138        match self {
139            Pmt::Ok => PmtKind::Ok,
140            Pmt::InvalidValue => PmtKind::InvalidValue,
141            Pmt::Null => PmtKind::Null,
142            Pmt::String(_) => PmtKind::String,
143            Pmt::Bool(_) => PmtKind::Bool,
144            Pmt::Usize(_) => PmtKind::Usize,
145            Pmt::Isize(_) => PmtKind::Isize,
146            Pmt::U32(_) => PmtKind::U32,
147            Pmt::U64(_) => PmtKind::U64,
148            Pmt::F32(_) => PmtKind::F32,
149            Pmt::F64(_) => PmtKind::F64,
150            Pmt::VecCF32(_) => PmtKind::VecCF32,
151            Pmt::VecF32(_) => PmtKind::VecF32,
152            Pmt::VecU64(_) => PmtKind::VecU64,
153            Pmt::Blob(_) => PmtKind::Blob,
154            Pmt::VecPmt(_) => PmtKind::VecPmt,
155            Pmt::Finished => PmtKind::Finished,
156            Pmt::MapStrPmt(_) => PmtKind::MapStrPmt,
157            Pmt::Any(_) => PmtKind::Any,
158        }
159    }
160}
161
162impl fmt::Display for Pmt {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        match self {
165            Pmt::Ok => write!(f, "Ok"),
166            Pmt::InvalidValue => write!(f, "InvalidValue"),
167            Pmt::Null => write!(f, "Null"),
168            Pmt::String(v) => write!(f, "{v}"),
169            Pmt::Bool(v) => write!(f, "{v}"),
170            Pmt::Usize(v) => write!(f, "{v}"),
171            Pmt::Isize(v) => write!(f, "{v}"),
172            Pmt::U32(v) => write!(f, "{v}"),
173            Pmt::U64(v) => write!(f, "{v}"),
174            Pmt::F32(v) => write!(f, "{v}"),
175            Pmt::F64(v) => write!(f, "{v}"),
176            Pmt::VecCF32(v) => write!(f, "{v:?}"),
177            Pmt::VecF32(v) => write!(f, "{v:?}"),
178            Pmt::VecU64(v) => write!(f, "{v:?}"),
179            Pmt::Blob(v) => write!(f, "{v:?}"),
180            Pmt::VecPmt(v) => write!(f, "{v:?}"),
181            Pmt::Finished => write!(f, "Finished"),
182            Pmt::MapStrPmt(v) => write!(f, "{v:?}"),
183            Pmt::Any(v) => write!(f, "{v:?}"),
184        }
185    }
186}
187
188impl PartialEq for Pmt {
189    fn eq(&self, other: &Self) -> bool {
190        match (self, other) {
191            (Pmt::Ok, Pmt::Ok) => true,
192            (Pmt::InvalidValue, Pmt::InvalidValue) => true,
193            (Pmt::Null, Pmt::Null) => true,
194            (Pmt::String(x), Pmt::String(y)) => x == y,
195            (Pmt::Bool(x), Pmt::Bool(y)) => x == y,
196            (Pmt::Usize(x), Pmt::Usize(y)) => x == y,
197            (Pmt::Isize(x), Pmt::Isize(y)) => x == y,
198            (Pmt::U32(x), Pmt::U32(y)) => x == y,
199            (Pmt::U64(x), Pmt::U64(y)) => x == y,
200            (Pmt::F32(x), Pmt::F32(y)) => x == y,
201            (Pmt::F64(x), Pmt::F64(y)) => x == y,
202            (Pmt::VecF32(x), Pmt::VecF32(y)) => x == y,
203            (Pmt::VecU64(x), Pmt::VecU64(y)) => x == y,
204            (Pmt::VecCF32(x), Pmt::VecCF32(y)) => x == y,
205            (Pmt::Blob(x), Pmt::Blob(y)) => x == y,
206            (Pmt::VecPmt(x), Pmt::VecPmt(y)) => x == y,
207            (Pmt::Finished, Pmt::Finished) => true,
208            (Pmt::MapStrPmt(x), Pmt::MapStrPmt(y)) => x == y,
209            _ => false,
210        }
211    }
212}
213
214impl std::str::FromStr for Pmt {
215    type Err = PmtConversionError;
216
217    fn from_str(s: &str) -> Result<Self, Self::Err> {
218        match s {
219            "Ok" | "ok" => return Ok(Pmt::Ok),
220            "Null" | "null" => return Ok(Pmt::Null),
221            "true" => return Ok(Pmt::Bool(true)),
222            "false" => return Ok(Pmt::Bool(false)),
223            "InvalidValue" | "invalidvalue" => return Ok(Pmt::InvalidValue),
224            "Finished" | "finished" => return Ok(Pmt::Finished),
225            _ => (),
226        }
227
228        if let Ok(p) = serde_json::from_str(s) {
229            return Ok(p);
230        }
231
232        if let Some((a, b)) = s.split_once(':') {
233            let s = format!("{{ \"{a}\": {b}}}");
234            if let Ok(p) = serde_json::from_str(&s) {
235                return Ok(p);
236            }
237        }
238        Err(PmtConversionError)
239    }
240}
241
242impl Pmt {
243    /// Create a [`Pmt`] by parsing a string into a specific [`PmtKind`].
244    ///
245    /// Only scalar kinds that have a straightforward textual representation are
246    /// supported here. Use [`std::str::FromStr`] for full PMT JSON parsing.
247    pub fn from_string(s: &str, t: &PmtKind) -> Option<Pmt> {
248        match t {
249            PmtKind::U32 => {
250                if let Ok(v) = s.parse::<u32>() {
251                    Some(Pmt::U32(v))
252                } else {
253                    None
254                }
255            }
256            PmtKind::U64 => {
257                if let Ok(v) = s.parse::<u64>() {
258                    Some(Pmt::U64(v))
259                } else {
260                    None
261                }
262            }
263            PmtKind::F32 => {
264                if let Ok(v) = s.parse::<f32>() {
265                    Some(Pmt::F32(v))
266                } else {
267                    None
268                }
269            }
270            PmtKind::F64 => {
271                if let Ok(v) = s.parse::<f64>() {
272                    Some(Pmt::F64(v))
273                } else {
274                    None
275                }
276            }
277            PmtKind::String => Some(Pmt::String(s.to_string())),
278            _ => None,
279        }
280    }
281}
282
283/// PMT conversion error.
284///
285/// This error is returned when parsing or `TryFrom<Pmt>` conversion cannot
286/// produce the requested target type without changing the PMT kind.
287#[derive(Debug, Clone, Error, PartialEq)]
288#[error("PMT conversion error")]
289pub struct PmtConversionError;
290
291impl TryFrom<&Pmt> for f64 {
292    type Error = PmtConversionError;
293
294    fn try_from(value: &Pmt) -> Result<f64, Self::Error> {
295        match value {
296            Pmt::F32(f) => Ok(*f as f64),
297            Pmt::F64(f) => Ok(*f),
298            Pmt::U32(f) => Ok(*f as f64),
299            Pmt::U64(f) => Ok(*f as f64),
300            _ => Err(PmtConversionError),
301        }
302    }
303}
304
305impl TryFrom<Pmt> for f64 {
306    type Error = PmtConversionError;
307
308    fn try_from(value: Pmt) -> Result<f64, Self::Error> {
309        (&value).try_into()
310    }
311}
312
313impl TryFrom<&Pmt> for usize {
314    type Error = PmtConversionError;
315
316    fn try_from(value: &Pmt) -> Result<usize, Self::Error> {
317        match value {
318            Pmt::Usize(f) => Ok(*f),
319            _ => Err(PmtConversionError),
320        }
321    }
322}
323
324impl TryFrom<Pmt> for usize {
325    type Error = PmtConversionError;
326
327    fn try_from(value: Pmt) -> Result<usize, Self::Error> {
328        (&value).try_into()
329    }
330}
331
332impl TryFrom<&Pmt> for isize {
333    type Error = PmtConversionError;
334
335    fn try_from(value: &Pmt) -> Result<isize, Self::Error> {
336        match value {
337            Pmt::Isize(f) => Ok(*f),
338            _ => Err(PmtConversionError),
339        }
340    }
341}
342
343impl TryFrom<Pmt> for isize {
344    type Error = PmtConversionError;
345
346    fn try_from(value: Pmt) -> Result<isize, Self::Error> {
347        (&value).try_into()
348    }
349}
350
351impl TryFrom<&Pmt> for u64 {
352    type Error = PmtConversionError;
353
354    fn try_from(value: &Pmt) -> Result<u64, Self::Error> {
355        match value {
356            Pmt::U32(v) => Ok(*v as u64),
357            Pmt::U64(v) => Ok(*v),
358            Pmt::Usize(v) => Ok(*v as u64),
359            _ => Err(PmtConversionError),
360        }
361    }
362}
363
364impl TryFrom<Pmt> for u64 {
365    type Error = PmtConversionError;
366
367    fn try_from(value: Pmt) -> Result<u64, Self::Error> {
368        (&value).try_into()
369    }
370}
371
372impl TryFrom<&Pmt> for bool {
373    type Error = PmtConversionError;
374
375    fn try_from(value: &Pmt) -> Result<bool, Self::Error> {
376        match value {
377            Pmt::Bool(b) => Ok(*b),
378            _ => Err(PmtConversionError),
379        }
380    }
381}
382
383impl TryFrom<Pmt> for bool {
384    type Error = PmtConversionError;
385
386    fn try_from(value: Pmt) -> Result<bool, Self::Error> {
387        (&value).try_into()
388    }
389}
390
391impl TryFrom<Pmt> for Vec<f32> {
392    type Error = PmtConversionError;
393
394    fn try_from(value: Pmt) -> Result<Vec<f32>, Self::Error> {
395        match value {
396            Pmt::VecF32(v) => Ok(v),
397            _ => Err(PmtConversionError),
398        }
399    }
400}
401
402impl TryFrom<Pmt> for Vec<Complex32> {
403    type Error = PmtConversionError;
404
405    fn try_from(value: Pmt) -> Result<Vec<Complex32>, Self::Error> {
406        match value {
407            Pmt::VecCF32(v) => Ok(v),
408            _ => Err(PmtConversionError),
409        }
410    }
411}
412
413impl TryFrom<Pmt> for Vec<u64> {
414    type Error = PmtConversionError;
415
416    fn try_from(value: Pmt) -> Result<Vec<u64>, Self::Error> {
417        match value {
418            Pmt::VecU64(v) => Ok(v),
419            _ => Err(PmtConversionError),
420        }
421    }
422}
423
424impl From<()> for Pmt {
425    fn from(_: ()) -> Self {
426        Pmt::Null
427    }
428}
429
430impl From<bool> for Pmt {
431    fn from(b: bool) -> Self {
432        Pmt::Bool(b)
433    }
434}
435
436impl From<f32> for Pmt {
437    fn from(f: f32) -> Self {
438        Pmt::F32(f)
439    }
440}
441
442impl From<f64> for Pmt {
443    fn from(f: f64) -> Self {
444        Pmt::F64(f)
445    }
446}
447
448impl From<u32> for Pmt {
449    fn from(f: u32) -> Self {
450        Pmt::U32(f)
451    }
452}
453
454impl From<u64> for Pmt {
455    fn from(f: u64) -> Self {
456        Pmt::U64(f)
457    }
458}
459
460impl From<usize> for Pmt {
461    fn from(f: usize) -> Self {
462        Pmt::Usize(f)
463    }
464}
465
466impl From<isize> for Pmt {
467    fn from(f: isize) -> Self {
468        Pmt::Isize(f)
469    }
470}
471
472impl From<Vec<f32>> for Pmt {
473    fn from(v: Vec<f32>) -> Self {
474        Pmt::VecF32(v)
475    }
476}
477
478impl From<Vec<u64>> for Pmt {
479    fn from(v: Vec<u64>) -> Self {
480        Pmt::VecU64(v)
481    }
482}
483
484impl From<Vec<Complex32>> for Pmt {
485    fn from(v: Vec<Complex32>) -> Self {
486        Pmt::VecCF32(v)
487    }
488}
489
490/// PMT variant tags without associated values.
491///
492/// Useful for bindings to other languages that do not support Rust's broad enum features.
493#[non_exhaustive]
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495pub enum PmtKind {
496    /// Ok
497    Ok,
498    /// Invalid value
499    InvalidValue,
500    /// Null
501    Null,
502    /// String
503    String,
504    /// Bool
505    Bool,
506    /// Usize
507    Usize,
508    /// Isize
509    Isize,
510    /// U32
511    U32,
512    /// U64
513    U64,
514    /// F32
515    F32,
516    /// F64
517    F64,
518    /// VecCF32
519    VecCF32,
520    /// VecF32
521    VecF32,
522    /// VecU64
523    VecU64,
524    /// Blob
525    Blob,
526    /// Vec Pmt
527    VecPmt,
528    /// Finished
529    Finished,
530    /// Map String -> Pmt
531    MapStrPmt,
532    /// Any
533    Any,
534}
535
536impl From<Pmt> for PmtKind {
537    fn from(value: Pmt) -> Self {
538        value.kind()
539    }
540}
541
542impl From<&Pmt> for PmtKind {
543    fn from(value: &Pmt) -> Self {
544        value.kind()
545    }
546}
547
548impl fmt::Display for PmtKind {
549    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550        match self {
551            PmtKind::Ok => write!(f, "Ok"),
552            PmtKind::InvalidValue => write!(f, "InvalidValue"),
553            PmtKind::Null => write!(f, "Null"),
554            PmtKind::String => write!(f, "String"),
555            PmtKind::Bool => write!(f, "Bool"),
556            PmtKind::Usize => write!(f, "Usize"),
557            PmtKind::Isize => write!(f, "isize"),
558            PmtKind::U32 => write!(f, "U32"),
559            PmtKind::U64 => write!(f, "U64"),
560            PmtKind::F32 => write!(f, "F32"),
561            PmtKind::F64 => write!(f, "F64"),
562            PmtKind::VecCF32 => write!(f, "VecCF32"),
563            PmtKind::VecF32 => write!(f, "VecF32"),
564            PmtKind::VecU64 => write!(f, "VecU64"),
565            PmtKind::Blob => write!(f, "Blob"),
566            PmtKind::VecPmt => write!(f, "VecPmt"),
567            PmtKind::Finished => write!(f, "Finished"),
568            PmtKind::MapStrPmt => write!(f, "MapStrPmt"),
569            PmtKind::Any => write!(f, "Any"),
570        }
571    }
572}
573
574impl std::str::FromStr for PmtKind {
575    type Err = PmtConversionError;
576
577    fn from_str(s: &str) -> Result<Self, Self::Err> {
578        match s {
579            "Ok" => return Ok(PmtKind::Ok),
580            "InvalidValue" => return Ok(PmtKind::InvalidValue),
581            "Null" => return Ok(PmtKind::Null),
582            "String" => return Ok(PmtKind::String),
583            "Bool" => return Ok(PmtKind::Bool),
584            "Usize" => return Ok(PmtKind::Usize),
585            "Isize" | "isize" => return Ok(PmtKind::Isize),
586            "U32" => return Ok(PmtKind::U32),
587            "U64" => return Ok(PmtKind::U64),
588            "F32" => return Ok(PmtKind::F32),
589            "F64" => return Ok(PmtKind::F64),
590            "VecF32" => return Ok(PmtKind::VecF32),
591            "VecU64" => return Ok(PmtKind::VecU64),
592            "Blob" => return Ok(PmtKind::Blob),
593            "VecPmt" => return Ok(PmtKind::VecPmt),
594            "Finished" => return Ok(PmtKind::Finished),
595            "MapStrPmt" => return Ok(PmtKind::MapStrPmt),
596            "Any" => return Ok(PmtKind::Any),
597            _ => (),
598        }
599        Err(PmtConversionError)
600    }
601}
602
603#[cfg(test)]
604mod test {
605    use super::*;
606
607    #[test]
608    fn pmt() {
609        let p = Pmt::Null;
610        assert_eq!(p.to_string(), "Null");
611        let p = Pmt::String("foo".to_string());
612        assert_eq!(p.to_string(), "foo");
613    }
614
615    #[test]
616    fn pmt_parse_json() {
617        let s = "{ \"U32\": 123 }";
618        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::U32(123)));
619        let s = "{ \"Bool\": true }";
620        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Bool(true)));
621        let s = "Bool: true";
622        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Bool(true)));
623        let s = "U32: 123";
624        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::U32(123)));
625        let s = "F64: 123";
626        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::F64(123.0)));
627        let s = "Blob: [1,2,3]";
628        assert_eq!(s.parse::<Pmt>(), Ok(Pmt::Blob(vec![1, 2, 3])));
629    }
630
631    #[test]
632    fn pmt_serde() {
633        let p = Pmt::Null;
634        let mut s = flexbuffers::FlexbufferSerializer::new();
635        p.serialize(&mut s).unwrap();
636
637        let r = flexbuffers::Reader::get_root(s.view()).unwrap();
638        let p2 = Pmt::deserialize(r).unwrap();
639
640        assert_eq!(p, p2);
641    }
642
643    #[allow(clippy::many_single_char_names)]
644    #[test]
645    fn pmt_eq() {
646        let a = Pmt::Null;
647        let b = Pmt::U32(123);
648        assert_ne!(a, b);
649
650        let c = Pmt::Null;
651        let d = Pmt::U32(12);
652        let e = Pmt::U32(123);
653        assert_eq!(a, c);
654        assert_eq!(b, e);
655        assert_ne!(b, d);
656
657        let f1 = Pmt::F32(0.1);
658        let f2 = Pmt::F32(0.1);
659        let f3 = Pmt::F32(0.2);
660        assert_eq!(f1, f2);
661        assert_ne!(f1, f3);
662
663        let fv1 = Pmt::VecF32(vec![1.0, 2.0, 3.0]);
664        let fv2 = Pmt::VecF32(vec![1.0, 2.0, 3.0]);
665        assert_eq!(fv1, fv2);
666
667        let cfv1 = Pmt::VecCF32(vec![Complex32::new(1.0, 2.0), Complex32::new(3.0, 4.0)]);
668        let cfv2 = Pmt::VecCF32(vec![Complex32::new(1.0, 2.0), Complex32::new(3.0, 4.0)]);
669        assert_eq!(cfv1, cfv2);
670    }
671
672    #[test]
673    fn vec_pmt() {
674        let vpmt = Pmt::VecPmt(vec![Pmt::U32(1), Pmt::U32(2)]);
675
676        if let Pmt::VecPmt(v) = vpmt {
677            assert_eq!(v[0], Pmt::U32(1));
678            assert_eq!(v[1], Pmt::U32(2));
679        } else {
680            panic!("Not a Pmt::VecPmt");
681        }
682    }
683
684    #[test]
685    fn map_str_pmt() {
686        let u32val = 42;
687        let f64val = 6.02214076e23;
688
689        let msp = Pmt::MapStrPmt(HashMap::from([
690            ("str".to_owned(), Pmt::String("a string".to_owned())),
691            (
692                "submap".to_owned(),
693                Pmt::MapStrPmt(HashMap::from([
694                    ("U32".to_owned(), Pmt::U32(u32val)),
695                    ("F64".to_owned(), Pmt::F64(f64val)),
696                ])),
697            ),
698        ]));
699
700        if let Pmt::MapStrPmt(m) = msp {
701            if let Some(Pmt::MapStrPmt(sm)) = m.get("submap") {
702                assert_eq!(sm.get("U32"), Some(&Pmt::U32(u32val)));
703                assert_eq!(sm.get("F64"), Some(&Pmt::F64(f64val)));
704            } else {
705                panic!("Could not get submap");
706            }
707        } else {
708            panic!("Not a Pmt::MapStrPmt");
709        }
710    }
711
712    #[test]
713    fn from_into() {
714        let e = 42usize;
715        let p = Pmt::from(e);
716        assert_eq!(p, Pmt::Usize(e));
717        assert_eq!((&p).try_into(), Ok(e));
718
719        let e = 42isize;
720        let p = Pmt::from(e);
721        assert_eq!(p, Pmt::Isize(e));
722        assert_eq!((&p).try_into(), Ok(e));
723
724        let e = 42u32;
725        let p = Pmt::from(e);
726        assert_eq!(p, Pmt::U32(e));
727        // Lossy conversion unsupported
728        // assert_eq!(p.try_into(), Ok(e));
729
730        let e = 42u64;
731        let p = Pmt::from(e);
732        assert_eq!(p, Pmt::U64(e));
733        assert_eq!((&p).try_into(), Ok(e));
734
735        let e = 42f64;
736        let p = Pmt::from(e);
737        assert_eq!(p, Pmt::F64(e));
738        assert_eq!(p.try_into(), Ok(e));
739
740        let e = 42f32;
741        let p = Pmt::from(e);
742        assert_eq!(p, Pmt::F32(e));
743        // Lossy conversion unsupported
744        //assert_eq!(p.try_into(), Ok(e));
745
746        let e = true;
747        let p = Pmt::from(e);
748        assert_eq!(p, Pmt::Bool(e));
749        assert_eq!((&p).try_into(), Ok(e));
750
751        let e = vec![1.0, 2.0, 3.0];
752        let p = Pmt::from(e.clone());
753        assert_eq!(p, Pmt::VecF32(e.clone()));
754        assert_eq!(p.try_into(), Ok(e));
755
756        let e = vec![1, 2, 3];
757        let p = Pmt::from(e.clone());
758        assert_eq!(p, Pmt::VecU64(e.clone()));
759        assert_eq!(p.try_into(), Ok(e));
760
761        let e = vec![Complex32::new(1.0, 2.0), Complex32::new(3.0, 4.0)];
762        let p = Pmt::from(e.clone());
763        assert_eq!(p, Pmt::VecCF32(e.clone()));
764        assert_eq!(p.try_into(), Ok(e));
765    }
766
767    #[test]
768    fn pmt_kind() {
769        let p = Pmt::U32(42);
770        assert_eq!(PmtKind::U32, p.kind());
771        assert_eq!(PmtKind::U32, p.into());
772
773        let p = Pmt::F64(42.0);
774        assert_eq!(PmtKind::F64, p.kind());
775        assert_eq!(PmtKind::F64, p.into());
776
777        let p = Pmt::VecF32(vec![]);
778        assert_eq!(PmtKind::VecF32, p.kind());
779        assert_eq!(PmtKind::VecF32, p.into());
780
781        let p = Pmt::VecU64(vec![]);
782        assert_eq!(PmtKind::VecU64, p.kind());
783        assert_eq!(PmtKind::VecU64, (&p).into());
784
785        let p = Pmt::VecCF32(vec![]);
786        assert_eq!(PmtKind::VecCF32, p.kind());
787        assert_eq!(PmtKind::VecCF32, (&p).into());
788    }
789
790    #[test]
791    fn take_any() {
792        let p = Pmt::Any(Box::new(vec![1u8]));
793
794        let Pmt::Any(p_any) = p else { unreachable!() };
795        assert!(p_any.is::<Vec<u8>>());
796
797        let v = p_any.take::<Vec<u8>>().unwrap();
798        assert_eq!(v[0], 1u8)
799    }
800}