lnmp_spatial/
decoder.rs

1use crate::error::SpatialError;
2use crate::types::*;
3use bytes::Buf;
4
5pub fn decode_spatial(buf: &mut &[u8]) -> Result<SpatialValue, SpatialError> {
6    if buf.remaining() < 1 {
7        return Err(SpatialError::DecodeError(
8            "Insufficient data for SpatialType".into(),
9        ));
10    }
11
12    let type_id = buf.get_u8();
13
14    match type_id {
15        0x01 => {
16            // Position2D
17            if buf.remaining() < 8 {
18                return Err(SpatialError::DecodeError(
19                    "Insufficient data for Position2D".into(),
20                ));
21            }
22            let x = buf.get_f32();
23            let y = buf.get_f32();
24            Ok(SpatialValue::S1(Position2D { x, y }))
25        }
26        0x02 => {
27            // Position3D
28            if buf.remaining() < 12 {
29                return Err(SpatialError::DecodeError(
30                    "Insufficient data for Position3D".into(),
31                ));
32            }
33            let x = buf.get_f32();
34            let y = buf.get_f32();
35            let z = buf.get_f32();
36            Ok(SpatialValue::S2(Position3D { x, y, z }))
37        }
38        0x03 => {
39            // Rotation
40            if buf.remaining() < 12 {
41                return Err(SpatialError::DecodeError(
42                    "Insufficient data for Rotation".into(),
43                ));
44            }
45            let pitch = buf.get_f32();
46            let yaw = buf.get_f32();
47            let roll = buf.get_f32();
48            Ok(SpatialValue::S3(Rotation { pitch, yaw, roll }))
49        }
50        0x04 => {
51            // Velocity
52            if buf.remaining() < 12 {
53                return Err(SpatialError::DecodeError(
54                    "Insufficient data for Velocity".into(),
55                ));
56            }
57            let vx = buf.get_f32();
58            let vy = buf.get_f32();
59            let vz = buf.get_f32();
60            Ok(SpatialValue::S4(Velocity { vx, vy, vz }))
61        }
62        0x05 => {
63            // Acceleration
64            if buf.remaining() < 12 {
65                return Err(SpatialError::DecodeError(
66                    "Insufficient data for Acceleration".into(),
67                ));
68            }
69            let ax = buf.get_f32();
70            let ay = buf.get_f32();
71            let az = buf.get_f32();
72            Ok(SpatialValue::S5(Acceleration { ax, ay, az }))
73        }
74        0x06 => {
75            // BoundingBox
76            if buf.remaining() < 24 {
77                return Err(SpatialError::DecodeError(
78                    "Insufficient data for BoundingBox".into(),
79                ));
80            }
81            let min_x = buf.get_f32();
82            let min_y = buf.get_f32();
83            let min_z = buf.get_f32();
84            let max_x = buf.get_f32();
85            let max_y = buf.get_f32();
86            let max_z = buf.get_f32();
87            Ok(SpatialValue::S6(BoundingBox {
88                min_x,
89                min_y,
90                min_z,
91                max_x,
92                max_y,
93                max_z,
94            }))
95        }
96        0x07 => {
97            // Quaternion
98            if buf.remaining() < 16 {
99                return Err(SpatialError::DecodeError(
100                    "Insufficient data for Quaternion".into(),
101                ));
102            }
103            let qx = buf.get_f32();
104            let qy = buf.get_f32();
105            let qz = buf.get_f32();
106            let qw = buf.get_f32();
107            Ok(SpatialValue::S7(Quaternion { qx, qy, qz, qw }))
108        }
109        0x08 => {
110            // Path
111            if buf.remaining() < 4 {
112                return Err(SpatialError::DecodeError(
113                    "Insufficient data for Path length".into(),
114                ));
115            }
116            let len = buf.get_u32() as usize;
117            if buf.remaining() < len * 12 {
118                return Err(SpatialError::DecodeError(
119                    "Insufficient data for Path points".into(),
120                ));
121            }
122            let mut points = Vec::with_capacity(len);
123            for _ in 0..len {
124                let x = buf.get_f32();
125                let y = buf.get_f32();
126                let z = buf.get_f32();
127                points.push(Position3D { x, y, z });
128            }
129            Ok(SpatialValue::S8(Path { points }))
130        }
131        0x09 => {
132            // Transform
133            if buf.remaining() < 36 {
134                return Err(SpatialError::DecodeError(
135                    "Insufficient data for Transform".into(),
136                ));
137            }
138            let px = buf.get_f32();
139            let py = buf.get_f32();
140            let pz = buf.get_f32();
141            let rp = buf.get_f32();
142            let ry = buf.get_f32();
143            let rr = buf.get_f32();
144            let sx = buf.get_f32();
145            let sy = buf.get_f32();
146            let sz = buf.get_f32();
147            Ok(SpatialValue::S9(Transform {
148                position: Position3D {
149                    x: px,
150                    y: py,
151                    z: pz,
152                },
153                rotation: Rotation {
154                    pitch: rp,
155                    yaw: ry,
156                    roll: rr,
157                },
158                scale: Position3D {
159                    x: sx,
160                    y: sy,
161                    z: sz,
162                },
163            }))
164        }
165        0x10 | 0x0A => {
166            // SpatialState (0x0A in types.rs, checking hex)
167            if buf.remaining() < 1 {
168                return Err(SpatialError::DecodeError(
169                    "Insufficient data for SpatialState mask".into(),
170                ));
171            }
172            let mask = buf.get_u8();
173
174            let position = if mask & 0x01 != 0 {
175                if buf.remaining() < 12 {
176                    return Err(SpatialError::DecodeError(
177                        "Insufficient data for SpatialState Position".into(),
178                    ));
179                }
180                Some(Position3D {
181                    x: buf.get_f32(),
182                    y: buf.get_f32(),
183                    z: buf.get_f32(),
184                })
185            } else {
186                None
187            };
188
189            let rotation = if mask & 0x02 != 0 {
190                if buf.remaining() < 12 {
191                    return Err(SpatialError::DecodeError(
192                        "Insufficient data for SpatialState Rotation".into(),
193                    ));
194                }
195                Some(Rotation {
196                    pitch: buf.get_f32(),
197                    yaw: buf.get_f32(),
198                    roll: buf.get_f32(),
199                })
200            } else {
201                None
202            };
203
204            let velocity = if mask & 0x04 != 0 {
205                if buf.remaining() < 12 {
206                    return Err(SpatialError::DecodeError(
207                        "Insufficient data for SpatialState Velocity".into(),
208                    ));
209                }
210                Some(Velocity {
211                    vx: buf.get_f32(),
212                    vy: buf.get_f32(),
213                    vz: buf.get_f32(),
214                })
215            } else {
216                None
217            };
218
219            let acceleration = if mask & 0x08 != 0 {
220                if buf.remaining() < 12 {
221                    return Err(SpatialError::DecodeError(
222                        "Insufficient data for SpatialState Acceleration".into(),
223                    ));
224                }
225                Some(Acceleration {
226                    ax: buf.get_f32(),
227                    ay: buf.get_f32(),
228                    az: buf.get_f32(),
229                })
230            } else {
231                None
232            };
233
234            Ok(SpatialValue::S10(SpatialState {
235                position,
236                rotation,
237                velocity,
238                acceleration,
239            }))
240        }
241        0x0B => {
242            // PositionDelta
243            if buf.remaining() < 12 {
244                return Err(SpatialError::DecodeError(
245                    "Insufficient data for PositionDelta".into(),
246                ));
247            }
248            let dx = buf.get_f32();
249            let dy = buf.get_f32();
250            let dz = buf.get_f32();
251            Ok(SpatialValue::S11(PositionDelta { dx, dy, dz }))
252        }
253        0x0C => {
254            // RotationDelta
255            if buf.remaining() < 12 {
256                return Err(SpatialError::DecodeError(
257                    "Insufficient data for RotationDelta".into(),
258                ));
259            }
260            let d_pitch = buf.get_f32();
261            let d_yaw = buf.get_f32();
262            let d_roll = buf.get_f32();
263            Ok(SpatialValue::S12(RotationDelta {
264                d_pitch,
265                d_yaw,
266                d_roll,
267            }))
268        }
269        0x0D => {
270            // SpatialDelta
271            if buf.remaining() < 1 {
272                return Err(SpatialError::DecodeError(
273                    "Insufficient data for SpatialDelta type".into(),
274                ));
275            }
276            let delta_type = buf.get_u8();
277            match delta_type {
278                0x01 => {
279                    // Position
280                    if buf.remaining() < 12 {
281                        return Err(SpatialError::DecodeError(
282                            "Insufficient data for SpatialDelta::Position".into(),
283                        ));
284                    }
285                    Ok(SpatialValue::S13(SpatialDelta::Position(PositionDelta {
286                        dx: buf.get_f32(),
287                        dy: buf.get_f32(),
288                        dz: buf.get_f32(),
289                    })))
290                }
291                0x02 => {
292                    // Rotation
293                    if buf.remaining() < 12 {
294                        return Err(SpatialError::DecodeError(
295                            "Insufficient data for SpatialDelta::Rotation".into(),
296                        ));
297                    }
298                    Ok(SpatialValue::S13(SpatialDelta::Rotation(RotationDelta {
299                        d_pitch: buf.get_f32(),
300                        d_yaw: buf.get_f32(),
301                        d_roll: buf.get_f32(),
302                    })))
303                }
304                0x03 => {
305                    // State
306                    if buf.remaining() < 1 {
307                        return Err(SpatialError::DecodeError(
308                            "Insufficient data for SpatialDelta::State mask".into(),
309                        ));
310                    }
311                    let mask = buf.get_u8();
312
313                    let position = if mask & 0x01 != 0 {
314                        if buf.remaining() < 12 {
315                            return Err(SpatialError::DecodeError(
316                                "Insufficient data for SpatialDelta Position".into(),
317                            ));
318                        }
319                        Some(PositionDelta {
320                            dx: buf.get_f32(),
321                            dy: buf.get_f32(),
322                            dz: buf.get_f32(),
323                        })
324                    } else {
325                        None
326                    };
327
328                    let rotation = if mask & 0x02 != 0 {
329                        if buf.remaining() < 12 {
330                            return Err(SpatialError::DecodeError(
331                                "Insufficient data for SpatialDelta Rotation".into(),
332                            ));
333                        }
334                        Some(RotationDelta {
335                            d_pitch: buf.get_f32(),
336                            d_yaw: buf.get_f32(),
337                            d_roll: buf.get_f32(),
338                        })
339                    } else {
340                        None
341                    };
342
343                    let velocity = if mask & 0x04 != 0 {
344                        if buf.remaining() < 12 {
345                            return Err(SpatialError::DecodeError(
346                                "Insufficient data for SpatialDelta Velocity".into(),
347                            ));
348                        }
349                        Some(Velocity {
350                            vx: buf.get_f32(),
351                            vy: buf.get_f32(),
352                            vz: buf.get_f32(),
353                        })
354                    } else {
355                        None
356                    };
357
358                    let acceleration = if mask & 0x08 != 0 {
359                        if buf.remaining() < 12 {
360                            return Err(SpatialError::DecodeError(
361                                "Insufficient data for SpatialDelta Acceleration".into(),
362                            ));
363                        }
364                        Some(Acceleration {
365                            ax: buf.get_f32(),
366                            ay: buf.get_f32(),
367                            az: buf.get_f32(),
368                        })
369                    } else {
370                        None
371                    };
372
373                    Ok(SpatialValue::S13(SpatialDelta::State {
374                        position,
375                        rotation,
376                        velocity,
377                        acceleration,
378                    }))
379                }
380                _ => Err(SpatialError::DecodeError(format!(
381                    "Unknown SpatialDelta type: {}",
382                    delta_type
383                ))),
384            }
385        }
386        _ => Err(SpatialError::UnknownType(type_id)),
387    }
388}