1//! Binary parsing utils.
2//!
3//! This module should not be used directly, unless you're planning to parse
4//! some tables manually.
5
6use core::convert::{TryFrom, TryInto};
7use core::ops::Range;
8
9/// A trait for parsing raw binary data of fixed size.
10///
11/// This is a low-level, internal trait that should not be used directly.
12pub trait FromData: Sized {
13 /// Object's raw data size.
14 ///
15 /// Not always the same as `mem::size_of`.
16 const SIZE: usize;
17
18 /// Parses an object from a raw data.
19 fn parse(data: &[u8]) -> Option<Self>;
20}
21
22/// A trait for parsing raw binary data of variable size.
23///
24/// This is a low-level, internal trait that should not be used directly.
25pub trait FromSlice<'a>: Sized {
26 /// Parses an object from a raw data.
27 fn parse(data: &'a [u8]) -> Option<Self>;
28}
29
30impl FromData for () {
31 const SIZE: usize = 0;
32
33 #[inline]
34 fn parse(_: &[u8]) -> Option<Self> {
35 Some(())
36 }
37}
38
39impl FromData for u8 {
40 const SIZE: usize = 1;
41
42 #[inline]
43 fn parse(data: &[u8]) -> Option<Self> {
44 data.get(index:0).copied()
45 }
46}
47
48impl FromData for i8 {
49 const SIZE: usize = 1;
50
51 #[inline]
52 fn parse(data: &[u8]) -> Option<Self> {
53 data.get(index:0).copied().map(|n: u8| n as i8)
54 }
55}
56
57impl FromData for u16 {
58 const SIZE: usize = 2;
59
60 #[inline]
61 fn parse(data: &[u8]) -> Option<Self> {
62 data.try_into().ok().map(u16::from_be_bytes)
63 }
64}
65
66impl FromData for i16 {
67 const SIZE: usize = 2;
68
69 #[inline]
70 fn parse(data: &[u8]) -> Option<Self> {
71 data.try_into().ok().map(i16::from_be_bytes)
72 }
73}
74
75impl FromData for u32 {
76 const SIZE: usize = 4;
77
78 #[inline]
79 fn parse(data: &[u8]) -> Option<Self> {
80 data.try_into().ok().map(u32::from_be_bytes)
81 }
82}
83
84impl FromData for i32 {
85 const SIZE: usize = 4;
86
87 #[inline]
88 fn parse(data: &[u8]) -> Option<Self> {
89 data.try_into().ok().map(i32::from_be_bytes)
90 }
91}
92
93impl FromData for u64 {
94 const SIZE: usize = 8;
95
96 #[inline]
97 fn parse(data: &[u8]) -> Option<Self> {
98 data.try_into().ok().map(u64::from_be_bytes)
99 }
100}
101
102/// A u24 number.
103///
104/// Stored as u32, but encoded as 3 bytes in the font.
105///
106/// <https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types>
107#[derive(Clone, Copy, Debug)]
108pub struct U24(pub u32);
109
110impl FromData for U24 {
111 const SIZE: usize = 3;
112
113 #[inline]
114 fn parse(data: &[u8]) -> Option<Self> {
115 let data: [u8; 3] = data.try_into().ok()?;
116 Some(U24(u32::from_be_bytes([0, data[0], data[1], data[2]])))
117 }
118}
119
120/// A 16-bit signed fixed number with the low 14 bits of fraction (2.14).
121#[derive(Clone, Copy, Debug)]
122pub struct F2DOT14(pub i16);
123
124impl F2DOT14 {
125 /// Converts i16 to f32.
126 #[inline]
127 pub fn to_f32(self) -> f32 {
128 f32::from(self.0) / 16384.0
129 }
130}
131
132impl FromData for F2DOT14 {
133 const SIZE: usize = 2;
134
135 #[inline]
136 fn parse(data: &[u8]) -> Option<Self> {
137 i16::parse(data).map(F2DOT14)
138 }
139}
140
141/// A 32-bit signed fixed-point number (16.16).
142#[derive(Clone, Copy, Debug)]
143pub struct Fixed(pub f32);
144
145impl FromData for Fixed {
146 const SIZE: usize = 4;
147
148 #[inline]
149 fn parse(data: &[u8]) -> Option<Self> {
150 // TODO: is it safe to cast?
151 i32::parse(data).map(|n: i32| Fixed(n as f32 / 65536.0))
152 }
153}
154
155/// A safe u32 to usize casting.
156///
157/// Rust doesn't implement `From<u32> for usize`,
158/// because it has to support 16 bit targets.
159/// We don't, so we can allow this.
160pub trait NumFrom<T>: Sized {
161 /// Converts u32 into usize.
162 fn num_from(_: T) -> Self;
163}
164
165impl NumFrom<u32> for usize {
166 #[inline]
167 fn num_from(v: u32) -> Self {
168 #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
169 {
170 v as usize
171 }
172
173 // compilation error on 16 bit targets
174 }
175}
176
177impl NumFrom<char> for usize {
178 #[inline]
179 fn num_from(v: char) -> Self {
180 #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
181 {
182 v as usize
183 }
184
185 // compilation error on 16 bit targets
186 }
187}
188
189/// Just like TryFrom<N>, but for numeric types not supported by the Rust's std.
190pub trait TryNumFrom<T>: Sized {
191 /// Casts between numeric types.
192 fn try_num_from(_: T) -> Option<Self>;
193}
194
195impl TryNumFrom<f32> for u8 {
196 #[inline]
197 fn try_num_from(v: f32) -> Option<Self> {
198 i32::try_num_from(v).and_then(|v: i32| u8::try_from(v).ok())
199 }
200}
201
202impl TryNumFrom<f32> for i16 {
203 #[inline]
204 fn try_num_from(v: f32) -> Option<Self> {
205 i32::try_num_from(v).and_then(|v: i32| i16::try_from(v).ok())
206 }
207}
208
209impl TryNumFrom<f32> for u16 {
210 #[inline]
211 fn try_num_from(v: f32) -> Option<Self> {
212 i32::try_num_from(v).and_then(|v: i32| u16::try_from(v).ok())
213 }
214}
215
216#[allow(clippy::manual_range_contains)]
217impl TryNumFrom<f32> for i32 {
218 #[inline]
219 fn try_num_from(v: f32) -> Option<Self> {
220 // Based on https://github.com/rust-num/num-traits/blob/master/src/cast.rs
221
222 // Float as int truncates toward zero, so we want to allow values
223 // in the exclusive range `(MIN-1, MAX+1)`.
224
225 // We can't represent `MIN-1` exactly, but there's no fractional part
226 // at this magnitude, so we can just use a `MIN` inclusive boundary.
227 const MIN: f32 = core::i32::MIN as f32;
228 // We can't represent `MAX` exactly, but it will round up to exactly
229 // `MAX+1` (a power of two) when we cast it.
230 const MAX_P1: f32 = core::i32::MAX as f32;
231 if v >= MIN && v < MAX_P1 {
232 Some(v as i32)
233 } else {
234 None
235 }
236 }
237}
238
239/// A slice-like container that converts internal binary data only on access.
240///
241/// Array values are stored in a continuous data chunk.
242#[derive(Clone, Copy)]
243pub struct LazyArray16<'a, T> {
244 data: &'a [u8],
245 data_type: core::marker::PhantomData<T>,
246}
247
248impl<T> Default for LazyArray16<'_, T> {
249 #[inline]
250 fn default() -> Self {
251 LazyArray16 {
252 data: &[],
253 data_type: core::marker::PhantomData,
254 }
255 }
256}
257
258impl<'a, T: FromData> LazyArray16<'a, T> {
259 /// Creates a new `LazyArray`.
260 #[inline]
261 pub fn new(data: &'a [u8]) -> Self {
262 LazyArray16 {
263 data,
264 data_type: core::marker::PhantomData,
265 }
266 }
267
268 /// Returns a value at `index`.
269 #[inline]
270 pub fn get(&self, index: u16) -> Option<T> {
271 if index < self.len() {
272 let start = usize::from(index) * T::SIZE;
273 let end = start + T::SIZE;
274 self.data.get(start..end).and_then(T::parse)
275 } else {
276 None
277 }
278 }
279
280 /// Returns the last value.
281 #[inline]
282 pub fn last(&self) -> Option<T> {
283 if !self.is_empty() {
284 self.get(self.len() - 1)
285 } else {
286 None
287 }
288 }
289
290 /// Returns sub-array.
291 #[inline]
292 pub fn slice(&self, range: Range<u16>) -> Option<Self> {
293 let start = usize::from(range.start) * T::SIZE;
294 let end = usize::from(range.end) * T::SIZE;
295 Some(LazyArray16 {
296 data: self.data.get(start..end)?,
297 ..LazyArray16::default()
298 })
299 }
300
301 /// Returns array's length.
302 #[inline]
303 pub fn len(&self) -> u16 {
304 (self.data.len() / T::SIZE) as u16
305 }
306
307 /// Checks if array is empty.
308 #[inline]
309 pub fn is_empty(&self) -> bool {
310 self.len() == 0
311 }
312
313 /// Performs a binary search by specified `key`.
314 #[inline]
315 pub fn binary_search(&self, key: &T) -> Option<(u16, T)>
316 where
317 T: Ord,
318 {
319 self.binary_search_by(|p| p.cmp(key))
320 }
321
322 /// Performs a binary search using specified closure.
323 #[inline]
324 pub fn binary_search_by<F>(&self, mut f: F) -> Option<(u16, T)>
325 where
326 F: FnMut(&T) -> core::cmp::Ordering,
327 {
328 // Based on Rust std implementation.
329
330 use core::cmp::Ordering;
331
332 let mut size = self.len();
333 if size == 0 {
334 return None;
335 }
336
337 let mut base = 0;
338 while size > 1 {
339 let half = size / 2;
340 let mid = base + half;
341 // mid is always in [0, size), that means mid is >= 0 and < size.
342 // mid >= 0: by definition
343 // mid < size: mid = size / 2 + size / 4 + size / 8 ...
344 let cmp = f(&self.get(mid)?);
345 base = if cmp == Ordering::Greater { base } else { mid };
346 size -= half;
347 }
348
349 // base is always in [0, size) because base <= mid.
350 let value = self.get(base)?;
351 if f(&value) == Ordering::Equal {
352 Some((base, value))
353 } else {
354 None
355 }
356 }
357}
358
359impl<'a, T: FromData + core::fmt::Debug + Copy> core::fmt::Debug for LazyArray16<'a, T> {
360 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
361 f.debug_list().entries(self.into_iter()).finish()
362 }
363}
364
365impl<'a, T: FromData> IntoIterator for LazyArray16<'a, T> {
366 type Item = T;
367 type IntoIter = LazyArrayIter16<'a, T>;
368
369 #[inline]
370 fn into_iter(self) -> Self::IntoIter {
371 LazyArrayIter16 {
372 data: self,
373 index: 0,
374 }
375 }
376}
377
378/// An iterator over `LazyArray16`.
379#[derive(Clone, Copy)]
380#[allow(missing_debug_implementations)]
381pub struct LazyArrayIter16<'a, T> {
382 data: LazyArray16<'a, T>,
383 index: u16,
384}
385
386impl<T: FromData> Default for LazyArrayIter16<'_, T> {
387 #[inline]
388 fn default() -> Self {
389 LazyArrayIter16 {
390 data: LazyArray16::new(&[]),
391 index: 0,
392 }
393 }
394}
395
396impl<'a, T: FromData> Iterator for LazyArrayIter16<'a, T> {
397 type Item = T;
398
399 #[inline]
400 fn next(&mut self) -> Option<Self::Item> {
401 self.index += 1; // TODO: check
402 self.data.get(self.index - 1)
403 }
404
405 #[inline]
406 fn count(self) -> usize {
407 usize::from(self.data.len().saturating_sub(self.index))
408 }
409}
410
411/// A slice-like container that converts internal binary data only on access.
412///
413/// This is a low-level, internal structure that should not be used directly.
414#[derive(Clone, Copy)]
415pub struct LazyArray32<'a, T> {
416 data: &'a [u8],
417 data_type: core::marker::PhantomData<T>,
418}
419
420impl<T> Default for LazyArray32<'_, T> {
421 #[inline]
422 fn default() -> Self {
423 LazyArray32 {
424 data: &[],
425 data_type: core::marker::PhantomData,
426 }
427 }
428}
429
430impl<'a, T: FromData> LazyArray32<'a, T> {
431 /// Creates a new `LazyArray`.
432 #[inline]
433 pub fn new(data: &'a [u8]) -> Self {
434 LazyArray32 {
435 data,
436 data_type: core::marker::PhantomData,
437 }
438 }
439
440 /// Returns a value at `index`.
441 #[inline]
442 pub fn get(&self, index: u32) -> Option<T> {
443 if index < self.len() {
444 let start = usize::num_from(index) * T::SIZE;
445 let end = start + T::SIZE;
446 self.data.get(start..end).and_then(T::parse)
447 } else {
448 None
449 }
450 }
451
452 /// Returns array's length.
453 #[inline]
454 pub fn len(&self) -> u32 {
455 (self.data.len() / T::SIZE) as u32
456 }
457
458 /// Checks if the array is empty.
459 pub fn is_empty(&self) -> bool {
460 self.len() == 0
461 }
462
463 /// Performs a binary search by specified `key`.
464 #[inline]
465 pub fn binary_search(&self, key: &T) -> Option<(u32, T)>
466 where
467 T: Ord,
468 {
469 self.binary_search_by(|p| p.cmp(key))
470 }
471
472 /// Performs a binary search using specified closure.
473 #[inline]
474 pub fn binary_search_by<F>(&self, mut f: F) -> Option<(u32, T)>
475 where
476 F: FnMut(&T) -> core::cmp::Ordering,
477 {
478 // Based on Rust std implementation.
479
480 use core::cmp::Ordering;
481
482 let mut size = self.len();
483 if size == 0 {
484 return None;
485 }
486
487 let mut base = 0;
488 while size > 1 {
489 let half = size / 2;
490 let mid = base + half;
491 // mid is always in [0, size), that means mid is >= 0 and < size.
492 // mid >= 0: by definition
493 // mid < size: mid = size / 2 + size / 4 + size / 8 ...
494 let cmp = f(&self.get(mid)?);
495 base = if cmp == Ordering::Greater { base } else { mid };
496 size -= half;
497 }
498
499 // base is always in [0, size) because base <= mid.
500 let value = self.get(base)?;
501 if f(&value) == Ordering::Equal {
502 Some((base, value))
503 } else {
504 None
505 }
506 }
507}
508
509impl<'a, T: FromData + core::fmt::Debug + Copy> core::fmt::Debug for LazyArray32<'a, T> {
510 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
511 f.debug_list().entries(self.into_iter()).finish()
512 }
513}
514
515impl<'a, T: FromData> IntoIterator for LazyArray32<'a, T> {
516 type Item = T;
517 type IntoIter = LazyArrayIter32<'a, T>;
518
519 #[inline]
520 fn into_iter(self) -> Self::IntoIter {
521 LazyArrayIter32 {
522 data: self,
523 index: 0,
524 }
525 }
526}
527
528/// An iterator over `LazyArray32`.
529#[derive(Clone, Copy)]
530#[allow(missing_debug_implementations)]
531pub struct LazyArrayIter32<'a, T> {
532 data: LazyArray32<'a, T>,
533 index: u32,
534}
535
536impl<'a, T: FromData> Iterator for LazyArrayIter32<'a, T> {
537 type Item = T;
538
539 #[inline]
540 fn next(&mut self) -> Option<Self::Item> {
541 self.index += 1; // TODO: check
542 self.data.get(self.index - 1)
543 }
544
545 #[inline]
546 fn count(self) -> usize {
547 usize::num_from(self.data.len().saturating_sub(self.index))
548 }
549}
550
551/// A [`LazyArray16`]-like container, but data is accessed by offsets.
552///
553/// Unlike [`LazyArray16`], internal storage is not continuous.
554///
555/// Multiple offsets can point to the same data.
556#[derive(Clone, Copy)]
557pub struct LazyOffsetArray16<'a, T: FromSlice<'a>> {
558 data: &'a [u8],
559 // Zero offsets must be ignored, therefore we're using `Option<Offset16>`.
560 offsets: LazyArray16<'a, Option<Offset16>>,
561 data_type: core::marker::PhantomData<T>,
562}
563
564impl<'a, T: FromSlice<'a>> LazyOffsetArray16<'a, T> {
565 /// Creates a new `LazyOffsetArray16`.
566 #[allow(dead_code)]
567 pub fn new(data: &'a [u8], offsets: LazyArray16<'a, Option<Offset16>>) -> Self {
568 Self {
569 data,
570 offsets,
571 data_type: core::marker::PhantomData,
572 }
573 }
574
575 /// Parses `LazyOffsetArray16` from raw data.
576 #[allow(dead_code)]
577 pub fn parse(data: &'a [u8]) -> Option<Self> {
578 let mut s = Stream::new(data);
579 let count = s.read::<u16>()?;
580 let offsets = s.read_array16(count)?;
581 Some(Self {
582 data,
583 offsets,
584 data_type: core::marker::PhantomData,
585 })
586 }
587
588 /// Returns a value at `index`.
589 #[inline]
590 pub fn get(&self, index: u16) -> Option<T> {
591 let offset = self.offsets.get(index)??.to_usize();
592 self.data.get(offset..).and_then(T::parse)
593 }
594
595 /// Returns array's length.
596 #[inline]
597 pub fn len(&self) -> u16 {
598 self.offsets.len()
599 }
600
601 /// Checks if array is empty.
602 #[inline]
603 #[allow(dead_code)]
604 pub fn is_empty(&self) -> bool {
605 self.len() == 0
606 }
607}
608
609impl<'a, T: FromSlice<'a> + core::fmt::Debug + Copy> core::fmt::Debug for LazyOffsetArray16<'a, T> {
610 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
611 f.debug_list().entries(self.into_iter()).finish()
612 }
613}
614
615/// An iterator over [`LazyOffsetArray16`] values.
616#[derive(Clone, Copy)]
617#[allow(missing_debug_implementations)]
618pub struct LazyOffsetArrayIter16<'a, T: FromSlice<'a>> {
619 array: LazyOffsetArray16<'a, T>,
620 index: u16,
621}
622
623impl<'a, T: FromSlice<'a>> IntoIterator for LazyOffsetArray16<'a, T> {
624 type Item = T;
625 type IntoIter = LazyOffsetArrayIter16<'a, T>;
626
627 #[inline]
628 fn into_iter(self) -> Self::IntoIter {
629 LazyOffsetArrayIter16 {
630 array: self,
631 index: 0,
632 }
633 }
634}
635
636impl<'a, T: FromSlice<'a>> Iterator for LazyOffsetArrayIter16<'a, T> {
637 type Item = T;
638
639 fn next(&mut self) -> Option<Self::Item> {
640 if self.index < self.array.len() {
641 self.index += 1;
642 self.array.get(self.index - 1)
643 } else {
644 None
645 }
646 }
647
648 #[inline]
649 fn count(self) -> usize {
650 usize::from(self.array.len().saturating_sub(self.index))
651 }
652}
653
654/// A streaming binary parser.
655#[derive(Clone, Default, Debug)]
656pub struct Stream<'a> {
657 data: &'a [u8],
658 offset: usize,
659}
660
661impl<'a> Stream<'a> {
662 /// Creates a new `Stream` parser.
663 #[inline]
664 pub fn new(data: &'a [u8]) -> Self {
665 Stream { data, offset: 0 }
666 }
667
668 /// Creates a new `Stream` parser at offset.
669 ///
670 /// Returns `None` when `offset` is out of bounds.
671 #[inline]
672 pub fn new_at(data: &'a [u8], offset: usize) -> Option<Self> {
673 if offset <= data.len() {
674 Some(Stream { data, offset })
675 } else {
676 None
677 }
678 }
679
680 /// Checks that stream reached the end of the data.
681 #[inline]
682 pub fn at_end(&self) -> bool {
683 self.offset >= self.data.len()
684 }
685
686 /// Jumps to the end of the stream.
687 ///
688 /// Useful to indicate that we parsed all the data.
689 #[inline]
690 pub fn jump_to_end(&mut self) {
691 self.offset = self.data.len();
692 }
693
694 /// Returns the current offset.
695 #[inline]
696 pub fn offset(&self) -> usize {
697 self.offset
698 }
699
700 /// Returns the trailing data.
701 ///
702 /// Returns `None` when `Stream` is reached the end.
703 #[inline]
704 pub fn tail(&self) -> Option<&'a [u8]> {
705 self.data.get(self.offset..)
706 }
707
708 /// Advances by `FromData::SIZE`.
709 ///
710 /// Doesn't check bounds.
711 #[inline]
712 pub fn skip<T: FromData>(&mut self) {
713 self.advance(T::SIZE);
714 }
715
716 /// Advances by the specified `len`.
717 ///
718 /// Doesn't check bounds.
719 #[inline]
720 pub fn advance(&mut self, len: usize) {
721 self.offset += len;
722 }
723
724 /// Advances by the specified `len` and checks for bounds.
725 #[inline]
726 pub fn advance_checked(&mut self, len: usize) -> Option<()> {
727 if self.offset + len <= self.data.len() {
728 self.advance(len);
729 Some(())
730 } else {
731 None
732 }
733 }
734
735 /// Parses the type from the steam.
736 ///
737 /// Returns `None` when there is not enough data left in the stream
738 /// or the type parsing failed.
739 #[inline]
740 pub fn read<T: FromData>(&mut self) -> Option<T> {
741 self.read_bytes(T::SIZE).and_then(T::parse)
742 }
743
744 /// Parses the type from the steam at offset.
745 #[inline]
746 pub fn read_at<T: FromData>(data: &[u8], offset: usize) -> Option<T> {
747 data.get(offset..offset + T::SIZE).and_then(T::parse)
748 }
749
750 /// Reads N bytes from the stream.
751 #[inline]
752 pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
753 let v = self.data.get(self.offset..self.offset + len)?;
754 self.advance(len);
755 Some(v)
756 }
757
758 /// Reads the next `count` types as a slice.
759 #[inline]
760 pub fn read_array16<T: FromData>(&mut self, count: u16) -> Option<LazyArray16<'a, T>> {
761 let len = usize::from(count) * T::SIZE;
762 self.read_bytes(len).map(LazyArray16::new)
763 }
764
765 /// Reads the next `count` types as a slice.
766 #[inline]
767 pub fn read_array32<T: FromData>(&mut self, count: u32) -> Option<LazyArray32<'a, T>> {
768 let len = usize::num_from(count) * T::SIZE;
769 self.read_bytes(len).map(LazyArray32::new)
770 }
771
772 #[allow(dead_code)]
773 #[inline]
774 pub fn read_at_offset16(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
775 let offset = self.read::<Offset16>()?.to_usize();
776 data.get(offset..)
777 }
778}
779
780/// A common offset methods.
781pub trait Offset {
782 /// Converts the offset to `usize`.
783 fn to_usize(&self) -> usize;
784
785 /// Checks that offset is null.
786 fn is_null(&self) -> bool {
787 self.to_usize() == 0
788 }
789}
790
791/// A type-safe u16 offset.
792#[derive(Clone, Copy, Debug)]
793pub struct Offset16(pub u16);
794
795impl Offset for Offset16 {
796 #[inline]
797 fn to_usize(&self) -> usize {
798 usize::from(self.0)
799 }
800}
801
802impl FromData for Offset16 {
803 const SIZE: usize = 2;
804
805 #[inline]
806 fn parse(data: &[u8]) -> Option<Self> {
807 u16::parse(data).map(Offset16)
808 }
809}
810
811impl FromData for Option<Offset16> {
812 const SIZE: usize = Offset16::SIZE;
813
814 #[inline]
815 fn parse(data: &[u8]) -> Option<Self> {
816 let offset: Offset16 = Offset16::parse(data)?;
817 if offset.0 != 0 {
818 Some(Some(offset))
819 } else {
820 Some(None)
821 }
822 }
823}
824
825/// A type-safe u32 offset.
826#[derive(Clone, Copy, Debug)]
827pub struct Offset32(pub u32);
828
829impl Offset for Offset32 {
830 #[inline]
831 fn to_usize(&self) -> usize {
832 usize::num_from(self.0)
833 }
834}
835
836impl FromData for Offset32 {
837 const SIZE: usize = 4;
838
839 #[inline]
840 fn parse(data: &[u8]) -> Option<Self> {
841 u32::parse(data).map(Offset32)
842 }
843}
844
845impl FromData for Option<Offset32> {
846 const SIZE: usize = Offset32::SIZE;
847
848 #[inline]
849 fn parse(data: &[u8]) -> Option<Self> {
850 let offset: Offset32 = Offset32::parse(data)?;
851 if offset.0 != 0 {
852 Some(Some(offset))
853 } else {
854 Some(None)
855 }
856 }
857}
858
859#[inline]
860pub fn i16_bound(min: i16, val: i16, max: i16) -> i16 {
861 use core::cmp;
862 cmp::max(v1:min, v2:cmp::min(v1:max, v2:val))
863}
864
865#[inline]
866pub fn f32_bound(min: f32, val: f32, max: f32) -> f32 {
867 debug_assert!(min.is_finite());
868 debug_assert!(val.is_finite());
869 debug_assert!(max.is_finite());
870
871 if val > max {
872 return max;
873 } else if val < min {
874 return min;
875 }
876
877 val
878}
879