serde_hkx/bytes/de/parser/
type_kind.rs
1use crate::{lib::*, tri};
3
4use super::BytesStream;
5use havok_types::*;
6use winnow::binary::{self, Endianness};
7use winnow::combinator::{alt, seq, terminated};
8use winnow::error::{ContextError, StrContext, StrContextValue};
9use winnow::token::take_until;
10use winnow::{ModalResult, Parser};
11
12#[inline]
18pub fn boolean(input: &mut BytesStream<'_>) -> ModalResult<bool> {
19 alt((1.value(true), 0.value(false)))
20 .context(StrContext::Label("bool(u8)"))
21 .context(StrContext::Expected(StrContextValue::Description(
22 "`1` or `0`",
23 )))
24 .parse_next(input)
25}
26
27#[inline]
32pub fn real<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, f32, ContextError> {
33 binary::f32(endian)
34 .context(StrContext::Label("real(f32)"))
35 .context(StrContext::Expected(StrContextValue::Description(
36 "Real(e.g. `00 00 80 3f`(0.1))",
37 )))
38}
39
40pub fn vector4<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, Vector4, ContextError> {
45 seq!(Vector4 {
46 x: real(endian).context(StrContext::Label("x")),
47 y: real(endian).context(StrContext::Label("y")),
48 z: real(endian).context(StrContext::Label("z")),
49 w: real(endian).context(StrContext::Label("w")),
50 })
51 .context(StrContext::Label("Vector4"))
52}
53
54#[inline]
56pub fn quaternion<'a>(
57 endian: Endianness,
58) -> impl Parser<BytesStream<'a>, Quaternion, ContextError> {
59 move |input: &mut &'a [u8]| {
60 let Vector4 { x, y, z, w } = tri!(vector4(endian).parse_next(input));
61 Ok(Quaternion { x, y, z, scaler: w })
62 }
63}
64
65pub fn matrix3<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, Matrix3, ContextError> {
66 seq!(Matrix3 {
67 x: vector4(endian).context(StrContext::Label("x")),
68 y: vector4(endian).context(StrContext::Label("y")),
69 z: vector4(endian).context(StrContext::Label("z")),
70 })
71 .context(StrContext::Label("Matrix3"))
72}
73
74pub fn rotation<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, Rotation, ContextError> {
75 seq!(Rotation {
76 x: vector4(endian).context(StrContext::Label("x")),
77 y: vector4(endian).context(StrContext::Label("y")),
78 z: vector4(endian).context(StrContext::Label("z")),
79 })
80 .context(StrContext::Label("Rotation"))
81}
82
83pub fn qstransform<'a>(
84 endian: Endianness,
85) -> impl Parser<BytesStream<'a>, QsTransform, ContextError> {
86 seq!(QsTransform {
87 transition: vector4(endian).context(StrContext::Label("transition")),
88 quaternion: quaternion(endian).context(StrContext::Label("quaternion")),
89 scale: vector4(endian).context(StrContext::Label("scale")),
90 })
91 .context(StrContext::Label("QsTransform"))
92}
93
94pub fn matrix4<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, Matrix4, ContextError> {
95 seq!(Matrix4 {
96 x: vector4(endian).context(StrContext::Label("x")),
97 y: vector4(endian).context(StrContext::Label("y")),
98 z: vector4(endian).context(StrContext::Label("z")),
99 w: vector4(endian).context(StrContext::Label("w")),
100 })
101 .context(StrContext::Label("Matrix4"))
102}
103
104pub fn transform<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, Transform, ContextError> {
105 seq!(Transform {
106 rotation: rotation(endian).context(StrContext::Label("rotation")),
107 transition: vector4(endian).context(StrContext::Label("transition")),
108 })
109 .context(StrContext::Label("Transform"))
110}
111
112pub fn half<'a>(endian: Endianness) -> impl Parser<BytesStream<'a>, f16, ContextError> {
118 move |bytes: &mut BytesStream<'a>| {
119 let (b0, b1) = tri!(
120 seq! {
121 binary::u8,
122 binary::u8,
123 }
124 .context(StrContext::Label("half(f16)"))
125 .context(StrContext::Expected(StrContextValue::Description(
126 "half(f16)",
127 )))
128 .parse_next(bytes)
129 );
130
131 Ok(match endian {
132 Endianness::Little => f16::from_le_bytes([b0, b1]),
133 Endianness::Big => f16::from_be_bytes([b0, b1]),
134 Endianness::Native => {
135 if cfg!(target_endian = "big") {
136 f16::from_be_bytes([b0, b1])
137 } else {
138 #[allow(clippy::tuple_array_conversions)]
139 f16::from_le_bytes([b0, b1]) }
141 }
142 })
143 }
144}
145
146pub fn string<'a>(input: &mut BytesStream<'a>) -> ModalResult<&'a str> {
151 terminated(take_until(0.., b'\0'), b'\0')
152 .try_map(|bytes| core::str::from_utf8(bytes))
153 .context(StrContext::Label("string"))
154 .context(StrContext::Expected(StrContextValue::Description(
155 "Valid ASCII string literal",
156 )))
157 .parse_next(input)
158}
159
160pub fn array_meta<'a>(
165 is_x86: bool,
166 endian: Endianness,
167) -> impl Parser<BytesStream<'a>, (usize, i32), ContextError> {
168 move |bytes: &mut BytesStream<'a>| {
169 if is_x86 {
170 tri!(
171 binary::u32(endian)
172 .verify(|uint| *uint == 0)
173 .map(|uint| uint as u64)
174 .context(StrContext::Expected(StrContextValue::Description(
175 "Skip x86 ptr size(0 fill 4bytes)",
176 )))
177 .parse_next(bytes)
178 )
179 } else {
180 tri!(
181 binary::u64(endian)
182 .verify(|ulong| *ulong == 0)
183 .context(StrContext::Expected(StrContextValue::Description(
184 "Skip x64 ptr size(0 fill 8bytes)",
185 )))
186 .parse_next(bytes)
187 )
188 };
189
190 seq! {
191 binary::i32(endian)
192 .map(|size| size as usize)
193 .context(StrContext::Expected(
194 StrContextValue::Description("size(i32)")
195 )),
196 binary::i32(endian)
197 .verify(|cap| (cap & (1 << 31)) != 0) .context(
199 StrContext::Expected(StrContextValue::Description("capacity&flags(i32: e.g. 00 00 00 80)"))
200 )
201 }
202 .parse_next(bytes)
203 }
204}
205
206#[cfg(test)]
209mod tests {
210 use super::*;
211 use pretty_assertions::assert_eq;
212 use zerocopy::IntoBytes as _;
213
214 #[test]
215 fn test_boolean() {
216 assert_eq!(boolean.parse(&[1]), Ok(true));
217 assert_eq!(boolean.parse(&[0]), Ok(false));
218 assert!(boolean.parse(b"yes").is_err());
219 }
220
221 #[test]
222 fn test_vector4() {
223 assert_eq!(
224 vector4(Endianness::Little).parse([-0.0_f32, 0.0, -0.0, 1.0].as_bytes()),
225 Ok(Vector4::new(-0.0, 0.0, -0.0, 1.0))
226 );
227 }
228
229 #[test]
230 fn test_matrix3() {
231 assert_eq!(
232 matrix3(Endianness::Little).parse(
233 [
234 0.0_f32, 0.0, 0.0, 0.0, -0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, ]
238 .as_bytes()
239 ),
240 Ok(Matrix3 {
241 x: Vector4::default(),
242 y: Vector4 {
243 x: -0.0,
244 y: 0.0,
245 z: 1.0,
246 w: 0.0
247 },
248 z: Vector4 {
249 x: 1.0,
250 y: 1.0,
251 z: 0.0,
252 w: 0.0
253 }
254 })
255 );
256 }
257
258 #[test]
259 fn test_half() {
260 assert_eq!(
261 half(Endianness::Little).parse(&[0x80, 0x3f]),
262 Ok(f16::from_f32(1.0))
263 );
264 assert_eq!(
265 half(Endianness::Big).parse(&[0x3f, 0x80]),
266 Ok(f16::from_f32(1.0))
267 );
268 }
269
270 #[test]
271 fn test_string() {
272 assert_eq!(string.parse(b"example\0"), Ok("example"));
273 assert!(string.parse(b"example").is_err());
274 }
275}