mesh_loader/utils/
bytes.rs
1#[cfg(feature = "obj")]
2use std::{borrow::Cow, ffi::OsStr, path::Path, str};
3
4#[inline(always)] pub(crate) fn starts_with(mut s: &[u8], mut needle: &'static [u8]) -> bool {
8 if s.len() < needle.len() {
9 return false;
10 }
11 if needle.len() < 4 {
12 return s.starts_with(needle);
13 }
14 if needle.len() < 8 {
15 return u32::from_ne_bytes(needle[..4].try_into().unwrap())
17 == u32::from_ne_bytes(s[..4].try_into().unwrap())
18 && s[4..].starts_with(&needle[4..]);
19 }
20 if needle.len() < 12 {
21 return u64::from_ne_bytes(needle[..8].try_into().unwrap())
23 == u64::from_ne_bytes(s[..8].try_into().unwrap())
24 && s[8..].starts_with(&needle[8..]);
25 }
26 if needle.len() < 16 {
27 return u64::from_ne_bytes(needle[..8].try_into().unwrap())
29 == u64::from_ne_bytes(s[..8].try_into().unwrap())
30 && u32::from_ne_bytes(needle[8..12].try_into().unwrap())
31 == u32::from_ne_bytes(s[8..12].try_into().unwrap())
32 && s[12..].starts_with(&needle[12..]);
33 }
34 while needle.len() >= 8 {
36 if u64::from_ne_bytes(needle[..8].try_into().unwrap())
37 != u64::from_ne_bytes(s[..8].try_into().unwrap())
38 {
39 return false;
40 }
41 needle = &needle[8..];
42 s = &s[8..];
43 }
44 s.starts_with(needle)
45}
46
47#[cfg(any(feature = "collada", feature = "obj"))]
48#[inline]
49pub(crate) const fn memchr_naive(needle: u8, mut s: &[u8]) -> Option<usize> {
50 let start = s;
51 while let Some((&b, s_next)) = s.split_first() {
52 if b == needle {
53 return Some(start.len() - s.len());
54 }
55 s = s_next;
56 }
57 None
58}
59
60#[cfg(any(feature = "obj", feature = "stl"))]
61#[inline]
62pub(crate) const fn memchr_naive_table(
63 needle_mask: u8,
64 table: &[u8; 256],
65 mut s: &[u8],
66) -> Option<usize> {
67 let start = s;
68 while let Some((&b, s_next)) = s.split_first() {
69 if table[b as usize] & needle_mask != 0 {
70 return Some(start.len() - s.len());
71 }
72 s = s_next;
73 }
74 None
75}
76
77#[cfg(any(feature = "obj", feature = "stl"))]
78#[inline]
79pub(crate) const fn memrchr_naive(needle: u8, mut s: &[u8]) -> Option<usize> {
80 let start = s;
81 while let Some((&b, s_next)) = s.split_last() {
82 if b == needle {
83 return Some(start.len() - s.len());
84 }
85 s = s_next;
86 }
87 None
88}
89
90#[cfg(any(feature = "obj", feature = "stl"))]
91#[inline]
92pub(crate) const fn bytecount_naive(needle: u8, mut s: &[u8]) -> usize {
93 let mut n = 0;
94 while let Some((&b, s_next)) = s.split_first() {
95 n += (b == needle) as usize;
96 s = s_next;
97 }
98 n
99}
100
101#[cfg(feature = "obj")]
102#[allow(clippy::unnecessary_wraps)] pub(crate) fn os_str_from_bytes(bytes: &[u8]) -> Result<&OsStr, std::str::Utf8Error> {
104 #[cfg(any(unix, target_os = "wasi"))]
105 {
106 #[cfg(unix)]
107 use std::os::unix::ffi::OsStrExt as _;
108 #[cfg(target_os = "wasi")]
109 use std::os::wasi::ffi::OsStrExt as _;
110 Ok(OsStr::from_bytes(bytes))
111 }
112 #[cfg(not(any(unix, target_os = "wasi")))]
113 {
114 std::str::from_utf8(bytes).map(OsStr::new)
115 }
116}
117#[cfg(feature = "obj")]
118pub(crate) fn path_from_bytes(bytes: &[u8]) -> Result<&Path, std::str::Utf8Error> {
119 os_str_from_bytes(bytes).map(Path::new)
120}
121
122#[cfg(feature = "obj")]
124#[inline]
125pub(crate) fn from_utf8_lossy(mut bytes: &[u8]) -> Cow<'_, str> {
126 let mut base = String::new();
127 loop {
128 match str::from_utf8(bytes) {
129 Ok(s) => {
130 if base.is_empty() {
131 return s.into();
132 }
133 base.push_str(s);
134 return base.into();
135 }
136 Err(e) => {
137 let valid_up_to = e.valid_up_to();
138 let s = str::from_utf8(&bytes[..valid_up_to]).unwrap();
139 base.push_str(s);
140 base.push(char::REPLACEMENT_CHARACTER);
141 if let Some(error_len) = e.error_len() {
142 bytes = &bytes[valid_up_to + error_len..];
143 } else {
144 return base.into();
145 }
146 }
147 }
148 }
149}