omf/omf1/
model.rs

1use std::fmt::Display;
2
3use serde::Deserialize;
4
5use super::{Omf1Error, objects::*};
6
7/// Converts a `&Model` into either a reference to the individual item, or into
8/// a subset enum.
9///
10/// This is used by `Omf1Root::get` to check variants on load.
11pub trait FromModel {
12    type Output<'a>;
13
14    fn from_model(model: &Model) -> Result<Self::Output<'_>, Omf1Error>;
15}
16
17/// Creates enums and `FromModel` implementations for the UidModel objects in OMF v1.
18macro_rules! model {
19    ($( $variant:ident )*) => {
20        /// Contains an OMF v1 top-level object.
21        #[derive(Debug, Deserialize)]
22        #[serde(tag = "__class__")]
23        pub enum Model {
24            $( $variant($variant), )*
25        }
26
27        /// The types of object allowed at the top level of OMF v1.
28        #[derive(Debug)]
29        pub enum ModelType {
30            $( $variant, )*
31        }
32
33        impl Model {
34            /// Return the model type.
35            fn model_type(&self) -> ModelType {
36                match self {
37                    $( Self::$variant(_) => ModelType::$variant, )*
38                }
39            }
40        }
41
42        $(
43            impl FromModel for $variant {
44                type Output<'a> = &'a $variant;
45
46                fn from_model(model: &Model) -> Result<Self::Output<'_>, Omf1Error> {
47                    match model {
48                        Model::$variant(x) => Ok(x),
49                        _ => Err(Omf1Error::WrongType {
50                            found: model.model_type(),
51                            expected: &[ModelType::$variant],
52                        }),
53                    }
54                }
55            }
56        )*
57    };
58}
59
60/// Creates marker type, a subset of `Model`, and a `FromModel` implementation to tie them
61/// together.
62///
63/// This lets us have type-tagged keys for a subset of model types in the objects that
64/// `Omf1Root::get` can load and check automatically. The loading code can then match
65/// exhaustively without worrying about the incorrect types.
66macro_rules! model_subset {
67    ($model_name:ident $enum_name:ident { $( $variant:ident )* }) => {
68        #[derive(Debug)]
69        pub struct $model_name {}
70
71        #[derive(Debug, Clone, Copy)]
72        #[allow(clippy::enum_variant_names)]
73        pub enum $enum_name<'a> {
74            $( $variant(&'a $variant), )*
75        }
76
77        impl FromModel for $model_name {
78            type Output<'a> = $enum_name<'a>;
79
80            fn from_model(model: &Model) -> Result<Self::Output<'_>, Omf1Error> {
81                match model {
82                    $( Model::$variant(x) => Ok($enum_name::$variant(x)), )*
83                    _ => Err(Omf1Error::WrongType {
84                        found: model.model_type(),
85                        expected: &[$( ModelType::$variant ),*],
86                    }),
87                }
88            }
89        }
90    };
91}
92
93model! {
94    Project
95    PointSetElement
96    PointSetGeometry
97    LineSetElement
98    LineSetGeometry
99    SurfaceElement
100    SurfaceGeometry
101    SurfaceGridGeometry
102    VolumeElement
103    VolumeGridGeometry
104    ScalarColormap
105    DateTimeColormap
106    Legend
107    ScalarData
108    DateTimeData
109    Vector2Data
110    Vector3Data
111    ColorData
112    StringData
113    MappedData
114    ImageTexture
115    ScalarArray
116    Vector2Array
117    Vector3Array
118    Int2Array
119    Int3Array
120    StringArray
121    DateTimeArray
122    ColorArray
123}
124
125impl Display for ModelType {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        write!(f, "{self:?}")
128    }
129}
130
131model_subset! {
132    Elements ElementModel {
133        PointSetElement
134        LineSetElement
135        SurfaceElement
136        VolumeElement
137    }
138}
139
140model_subset! {
141    Data DataModel {
142        ScalarData
143        DateTimeData
144        Vector2Data
145        Vector3Data
146        ColorData
147        StringData
148        MappedData
149    }
150}
151
152model_subset! {
153    SurfaceGeometries SurfaceGeometryModel {
154        SurfaceGeometry
155        SurfaceGridGeometry
156    }
157}
158
159model_subset! {
160    LegendArrays LegendArrayModel {
161        ColorArray
162        DateTimeArray
163        StringArray
164        ScalarArray
165    }
166}
167
168model_subset! {
169    ColorArrays ColorArrayModel {
170        Int3Array
171        ColorArray
172    }
173}