1use crate::{sys::*, *};
2use derivative::Derivative;
3
4trait MetaDataEntryCast {
5 fn can_cast(&self) -> bool;
6 fn cast(&self) -> Russult<MetadataType>;
7}
8
9struct MetaDataEntryString<'a> {
10 data: &'a aiMetadataEntry,
11}
12
13struct MetaDataEntryBool<'a> {
14 data: &'a aiMetadataEntry,
15}
16
17struct MetaDataEntryFloat<'a> {
18 data: &'a aiMetadataEntry,
19}
20
21struct MetaDataEntryDouble<'a> {
22 data: &'a aiMetadataEntry,
23}
24
25struct MetaDataEntryInteger<'a> {
26 data: &'a aiMetadataEntry,
27}
28
29struct MetaDataEntryULong<'a> {
30 data: &'a aiMetadataEntry,
31}
32
33impl<'a> MetaDataEntryCast for MetaDataEntryULong<'a> {
34 fn can_cast(&self) -> bool {
35 self.data.mType == aiMetadataType_AI_UINT64
36 }
37
38 fn cast(&self) -> Russult<MetadataType> {
39 let raw = self.data.mData as *mut u64;
40
41 if let Some(result) = unsafe { raw.as_ref() } {
42 return Ok(MetadataType::ULong(*result));
43 }
44
45 Err(RussimpError::MetadataError(
46 "Cant convert to ulong".to_string(),
47 ))
48 }
49}
50
51impl<'a> MetaDataEntryCast for MetaDataEntryInteger<'a> {
52 fn can_cast(&self) -> bool {
53 self.data.mType == aiMetadataType_AI_INT32
54 }
55
56 fn cast(&self) -> Russult<MetadataType> {
57 let raw = self.data.mData as *mut i32;
58
59 if let Some(result) = unsafe { raw.as_ref() } {
60 return Ok(MetadataType::Int(*result));
61 }
62
63 Err(RussimpError::MetadataError(
64 "Cant convert to integer".to_string(),
65 ))
66 }
67}
68
69impl<'a> MetaDataEntryCast for MetaDataEntryBool<'a> {
70 fn can_cast(&self) -> bool {
71 self.data.mType == aiMetadataType_AI_BOOL
72 }
73
74 fn cast(&self) -> Russult<MetadataType> {
75 let raw = self.data.mData as *mut bool;
76
77 if let Some(result) = unsafe { raw.as_ref() } {
78 return Ok(MetadataType::Bool(*result));
79 }
80
81 Err(RussimpError::MetadataError(
82 "Cant convert to bool".to_string(),
83 ))
84 }
85}
86
87impl<'a> MetaDataEntryCast for MetaDataEntryDouble<'a> {
88 fn can_cast(&self) -> bool {
89 self.data.mType == aiMetadataType_AI_DOUBLE
90 }
91
92 fn cast(&self) -> Russult<MetadataType> {
93 let raw = self.data.mData as *mut f64;
94
95 if let Some(result) = unsafe { raw.as_ref() } {
96 return Ok(MetadataType::Double(*result));
97 }
98
99 Err(RussimpError::MetadataError(
100 "Cant convert to double".to_string(),
101 ))
102 }
103}
104
105impl<'a> MetaDataEntryCast for MetaDataEntryFloat<'a> {
106 fn can_cast(&self) -> bool {
107 self.data.mType == aiMetadataType_AI_FLOAT
108 }
109
110 fn cast(&self) -> Russult<MetadataType> {
111 let raw = self.data.mData as *mut f32;
112
113 if let Some(result) = unsafe { raw.as_ref() } {
114 return Ok(MetadataType::Float(*result));
115 }
116
117 Err(RussimpError::MetadataError(
118 "Cant convert to float".to_string(),
119 ))
120 }
121}
122
123impl<'a> MetaDataEntryCast for MetaDataEntryString<'a> {
124 fn can_cast(&self) -> bool {
125 self.data.mType == aiMetadataType_AI_AISTRING
126 }
127
128 fn cast(&self) -> Russult<MetadataType> {
129 let raw = self.data.mData as *const aiString;
130
131 if let Some(result) = unsafe { raw.as_ref() } {
132 Ok(MetadataType::String(result.into()))
133 } else {
134 Err(RussimpError::MetadataError(
135 "Cant convert to string".to_string(),
136 ))
137 }
138 }
139}
140
141struct MetaDataVector3d<'a> {
142 data: &'a aiMetadataEntry,
143}
144
145impl<'a> MetaDataEntryCast for MetaDataVector3d<'a> {
146 fn can_cast(&self) -> bool {
147 self.data.mType == aiMetadataType_AI_AIVECTOR3D
148 }
149
150 fn cast(&self) -> Russult<MetadataType> {
151 let vec: *const aiVector3D = self.data.mData as *const aiVector3D;
152 if let Some(content) = unsafe { vec.as_ref() } {
153 return Ok(MetadataType::Vector3d(content.into()));
154 }
155
156 Err(RussimpError::MetadataError("data is null".to_string()))
157 }
158}
159
160#[derive(Derivative)]
161#[derivative(Debug)]
162pub struct MetaData {
163 pub keys: Vec<String>,
164 pub values: Vec<MetaDataEntry>,
165}
166
167impl From<&aiMetadata> for MetaData {
168 fn from(meta_data: &aiMetadata) -> Self {
169 Self {
170 keys: utils::get_vec(meta_data.mKeys, meta_data.mNumProperties),
171 values: utils::get_vec(meta_data.mValues, meta_data.mNumProperties),
172 }
173 }
174}
175
176#[derive(Derivative, PartialEq)]
177#[derivative(Debug)]
178#[repr(u32)]
179pub enum MetadataType {
180 String(String),
181 Vector3d(Vector3D),
182 Bool(bool),
183 Float(f32),
184 Double(f64),
185 Int(i32),
186 ULong(u64),
187 }
190
191#[derive(Derivative)]
192#[derivative(Debug)]
193pub struct MetaDataEntry(pub Russult<MetadataType>);
194
195impl MetaDataEntry {
196 fn cast_data(data: &aiMetadataEntry) -> Russult<MetadataType> {
197 let casters: Vec<Box<dyn MetaDataEntryCast>> = vec![
198 Box::new(MetaDataVector3d { data }),
199 Box::new(MetaDataEntryString { data }),
200 Box::new(MetaDataEntryBool { data }),
201 Box::new(MetaDataEntryFloat { data }),
202 Box::new(MetaDataEntryDouble { data }),
203 Box::new(MetaDataEntryInteger { data }),
204 Box::new(MetaDataEntryULong { data }),
205 ];
206
207 for caster in casters {
208 if caster.can_cast() {
209 return caster.cast();
210 }
211 }
212
213 Err(RussimpError::MetadataError(
214 "could not find caster for metadata type".to_string(),
215 ))
216 }
217}
218
219impl From<&aiMetadataEntry> for MetaDataEntry {
220 fn from(data: &aiMetadataEntry) -> Self {
221 Self(Self::cast_data(data))
222 }
223}
224
225#[cfg(test)]
226mod test {
227 use crate::metadata::MetadataType;
228 use crate::utils;
229
230 #[test]
231 fn metadata_for_box() {
232 use crate::scene::{PostProcess, Scene};
233
234 let current_directory_buf = utils::get_model("models/BLEND/box.blend");
235
236 let scene = Scene::from_file(
237 current_directory_buf.as_str(),
238 vec![
239 PostProcess::CalculateTangentSpace,
240 PostProcess::Triangulate,
241 PostProcess::JoinIdenticalVertices,
242 PostProcess::SortByPrimitiveType,
243 ],
244 )
245 .unwrap();
246
247 let metadata = scene.metadata.unwrap();
248
249 assert_eq!(1, metadata.keys.len());
250 assert_eq!(1, metadata.values.len());
251
252 assert_eq!("SourceAsset_Format".to_string(), metadata.keys[0]);
253
254 assert_eq!(
255 metadata.values[0].0.as_ref().unwrap(),
256 &MetadataType::String("Blender 3D Importer (http://www.blender3d.org)".to_string())
257 );
258 }
259
260 #[test]
261 fn debug_metadata() {
262 use crate::scene::{PostProcess, Scene};
263
264 let current_directory_buf = utils::get_model("models/BLEND/box.blend");
265
266 let scene = Scene::from_file(
267 current_directory_buf.as_str(),
268 vec![
269 PostProcess::CalculateTangentSpace,
270 PostProcess::Triangulate,
271 PostProcess::JoinIdenticalVertices,
272 PostProcess::SortByPrimitiveType,
273 ],
274 )
275 .unwrap();
276
277 dbg!(&scene.metadata);
278 }
279}