Skip to main content

fyrox_core/visitor/
pod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Data types that can be serialized as-is, by dumping the memory into a file.
22
23use crate::visitor::{
24    error::VisitError,
25    field::{Field, FieldKind},
26    Visit, VisitResult, Visitor,
27};
28
29const POD_TYPES: &[&str] = &[
30    "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64",
31];
32
33fn type_id_to_str(type_id: u8) -> &'static str {
34    POD_TYPES
35        .get(type_id as usize)
36        .copied()
37        .unwrap_or("Invalid Type")
38}
39
40/// Trait for datatypes that can be converted directly into bytes.
41/// This is required for the type to be used in the Vec of a [PodVecView].
42pub trait Pod: Copy {
43    /// A number which distinguishes each Pod type. Two distinct Pod types must not share the same `type_id` byte.
44    /// The `type_id` is stored with the data when a [PodVecView] is visited and used to confirm that the stored
45    /// data matches the expected type when reading. Otherwise garbage data could be read by interpreting an
46    /// array of i8 as an array of f32 or any other mismatched combination.
47    fn type_id() -> u8;
48}
49
50impl Pod for u8 {
51    fn type_id() -> u8 {
52        0
53    }
54}
55
56impl Pod for i8 {
57    fn type_id() -> u8 {
58        1
59    }
60}
61
62impl Pod for u16 {
63    fn type_id() -> u8 {
64        2
65    }
66}
67
68impl Pod for i16 {
69    fn type_id() -> u8 {
70        3
71    }
72}
73
74impl Pod for u32 {
75    fn type_id() -> u8 {
76        4
77    }
78}
79
80impl Pod for i32 {
81    fn type_id() -> u8 {
82        5
83    }
84}
85
86impl Pod for u64 {
87    fn type_id() -> u8 {
88        6
89    }
90}
91
92impl Pod for i64 {
93    fn type_id() -> u8 {
94        7
95    }
96}
97
98impl Pod for f32 {
99    fn type_id() -> u8 {
100        8
101    }
102}
103
104impl Pod for f64 {
105    fn type_id() -> u8 {
106        9
107    }
108}
109
110/// A [Visit] type for storing a whole Vec of [Pod] values as a single field within a Visitor.
111/// The Vec is reinterpreted as a Vec of bytes, with no consideration given for whether the bytes
112/// are in big-endian or little-endian order by using [std::ptr::copy_nonoverlapping].
113pub struct PodVecView<'a, T: Pod> {
114    type_id: u8,
115    vec: &'a mut Vec<T>,
116}
117
118impl<'a, T: Pod> PodVecView<'a, T> {
119    /// Creates a view from the given vector.
120    pub fn from_pod_vec(vec: &'a mut Vec<T>) -> Self {
121        Self {
122            type_id: T::type_id(),
123            vec,
124        }
125    }
126}
127
128impl<T: Pod> Visit for PodVecView<'_, T> {
129    #[allow(clippy::uninit_vec)]
130    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
131        if visitor.reading {
132            if let Some(field) = visitor.find_field(name) {
133                match &field.kind {
134                    FieldKind::PodArray {
135                        type_id,
136                        element_size,
137                        bytes,
138                    } => {
139                        if *type_id == self.type_id {
140                            let len = bytes.len() / *element_size as usize;
141                            let mut data = Vec::<T>::with_capacity(len);
142                            unsafe {
143                                data.set_len(len);
144                                std::ptr::copy_nonoverlapping(
145                                    bytes.as_ptr(),
146                                    data.as_mut_ptr() as *mut u8,
147                                    bytes.len(),
148                                );
149                            }
150                            *self.vec = data;
151                            Ok(())
152                        } else {
153                            Err(VisitError::TypeMismatch {
154                                expected: type_id_to_str(self.type_id),
155                                actual: type_id_to_str(*type_id),
156                            })
157                        }
158                    }
159                    _ => Err(VisitError::FieldTypeDoesNotMatch {
160                        expected: stringify!(FieldKind::PodArray),
161                        actual: format!("{:?}", field.kind),
162                    }),
163                }
164            } else {
165                Err(VisitError::field_does_not_exist(name, visitor))
166            }
167        } else if visitor.find_field(name).is_some() {
168            Err(VisitError::FieldAlreadyExists(name.to_owned()))
169        } else {
170            let node = visitor.current_node();
171            node.fields.push(Field::new(
172                name,
173                FieldKind::PodArray {
174                    type_id: T::type_id(),
175                    element_size: std::mem::size_of::<T>() as u32,
176                    bytes: unsafe {
177                        let mut data = self.vec.clone();
178                        let bytes = Vec::from_raw_parts(
179                            data.as_mut_ptr() as *mut u8,
180                            data.len() * std::mem::size_of::<T>(),
181                            data.capacity() * std::mem::size_of::<T>(),
182                        );
183                        std::mem::forget(data);
184                        bytes
185                    },
186                },
187            ));
188            Ok(())
189        }
190    }
191}
192
193#[cfg(test)]
194mod test {
195    use crate::visitor::pod::PodVecView;
196
197    #[test]
198    fn pod_vec_view_from_pod_vec() {
199        // Pod for u8
200        let mut v = Vec::<u8>::new();
201        let mut v2 = v.clone();
202        let p = PodVecView::from_pod_vec(&mut v);
203        assert_eq!(p.type_id, 0_u8);
204        assert_eq!(p.vec, &mut v2);
205
206        // Pod for i8
207        let mut v = Vec::<i8>::new();
208        let p = PodVecView::from_pod_vec(&mut v);
209        assert_eq!(p.type_id, 1_u8);
210
211        // Pod for u16
212        let mut v = Vec::<u16>::new();
213        let p = PodVecView::from_pod_vec(&mut v);
214        assert_eq!(p.type_id, 2_u8);
215
216        // Pod for i16
217        let mut v = Vec::<i16>::new();
218        let p = PodVecView::from_pod_vec(&mut v);
219        assert_eq!(p.type_id, 3_u8);
220
221        // Pod for u32
222        let mut v = Vec::<u32>::new();
223        let p = PodVecView::from_pod_vec(&mut v);
224        assert_eq!(p.type_id, 4_u8);
225
226        // Pod for i32
227        let mut v = Vec::<i32>::new();
228        let p = PodVecView::from_pod_vec(&mut v);
229        assert_eq!(p.type_id, 5_u8);
230
231        // Pod for u64
232        let mut v = Vec::<u64>::new();
233        let p = PodVecView::from_pod_vec(&mut v);
234        assert_eq!(p.type_id, 6_u8);
235
236        // Pod for i64
237        let mut v = Vec::<i64>::new();
238        let p = PodVecView::from_pod_vec(&mut v);
239        assert_eq!(p.type_id, 7_u8);
240
241        // Pod for f32
242        let mut v = Vec::<f32>::new();
243        let p = PodVecView::from_pod_vec(&mut v);
244        assert_eq!(p.type_id, 8_u8);
245
246        // Pod for f64
247        let mut v = Vec::<f64>::new();
248        let p = PodVecView::from_pod_vec(&mut v);
249        assert_eq!(p.type_id, 9_u8);
250    }
251}