1use core::mem::{size_of, transmute_copy};
53use zerofrom::ZeroFrom;
54
55#[cfg(feature = "alloc")]
56use alloc::{borrow::ToOwned, boxed::Box};
57
58use super::{AsULE, EncodeAsVarULE, UleError, VarULE, ULE};
59
60#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::fmt::Debug, B: ::core::fmt::Debug> ::core::fmt::Debug for
VarTuple<A, B> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "VarTuple",
"sized", &self.sized, "variable", &&self.variable)
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::PartialEq, B: ::core::cmp::PartialEq>
::core::cmp::PartialEq for VarTuple<A, B> {
#[inline]
fn eq(&self, other: &VarTuple<A, B>) -> bool {
self.sized == other.sized && self.variable == other.variable
}
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::Eq, B: ::core::cmp::Eq> ::core::cmp::Eq for
VarTuple<A, B> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<A>;
let _: ::core::cmp::AssertParamIsEq<B>;
}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::PartialOrd, B: ::core::cmp::PartialOrd>
::core::cmp::PartialOrd for VarTuple<A, B> {
#[inline]
fn partial_cmp(&self, other: &VarTuple<A, B>)
-> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.sized, &other.sized)
{
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
::core::cmp::PartialOrd::partial_cmp(&self.variable,
&other.variable),
cmp => cmp,
}
}
}PartialOrd, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::Ord, B: ::core::cmp::Ord> ::core::cmp::Ord for
VarTuple<A, B> {
#[inline]
fn cmp(&self, other: &VarTuple<A, B>) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.sized, &other.sized) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.variable, &other.variable),
cmp => cmp,
}
}
}Ord, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::clone::Clone, B: ::core::clone::Clone> ::core::clone::Clone
for VarTuple<A, B> {
#[inline]
fn clone(&self) -> VarTuple<A, B> {
VarTuple {
sized: ::core::clone::Clone::clone(&self.sized),
variable: ::core::clone::Clone::clone(&self.variable),
}
}
}Clone)]
64#[allow(clippy::exhaustive_structs)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66pub struct VarTuple<A, B> {
67 pub sized: A,
68 pub variable: B,
69}
70
71#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::fmt::Debug + AsULE, V: ::core::fmt::Debug + VarULE + ?Sized>
::core::fmt::Debug for VarTupleULE<A, V> where A::ULE: ::core::fmt::Debug
{
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "VarTupleULE",
"sized", &self.sized, "variable", &&self.variable)
}
}Debug, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::PartialEq + AsULE, V: ::core::cmp::PartialEq + VarULE +
?Sized> ::core::cmp::PartialEq for VarTupleULE<A, V> where
A::ULE: ::core::cmp::PartialEq {
#[inline]
fn eq(&self, other: &VarTupleULE<A, V>) -> bool {
self.sized == other.sized && self.variable == other.variable
}
}PartialEq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::Eq + AsULE, V: ::core::cmp::Eq + VarULE + ?Sized>
::core::cmp::Eq for VarTupleULE<A, V> where A::ULE: ::core::cmp::Eq {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<A::ULE>;
let _: ::core::cmp::AssertParamIsEq<V>;
}
}Eq, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::PartialOrd + AsULE, V: ::core::cmp::PartialOrd + VarULE +
?Sized> ::core::cmp::PartialOrd for VarTupleULE<A, V> where
A::ULE: ::core::cmp::PartialOrd {
#[inline]
fn partial_cmp(&self, other: &VarTupleULE<A, V>)
-> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.sized, &other.sized)
{
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
::core::cmp::PartialOrd::partial_cmp(&self.variable,
&other.variable),
cmp => cmp,
}
}
}PartialOrd, #[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::cmp::Ord + AsULE, V: ::core::cmp::Ord + VarULE + ?Sized>
::core::cmp::Ord for VarTupleULE<A, V> where A::ULE: ::core::cmp::Ord {
#[inline]
fn cmp(&self, other: &VarTupleULE<A, V>) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.sized, &other.sized) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.variable, &other.variable),
cmp => cmp,
}
}
}Ord)]
75#[allow(clippy::exhaustive_structs)] #[repr(C)]
77pub struct VarTupleULE<A: AsULE, V: VarULE + ?Sized> {
78 pub sized: A::ULE,
79 pub variable: V,
80}
81
82unsafe impl<A, V> VarULE for VarTupleULE<A, V>
110where
111 A: AsULE + 'static,
112 V: VarULE + ?Sized,
113{
114 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
115 let (sized_chunk, variable_chunk) = bytes
116 .split_at_checked(size_of::<A::ULE>())
117 .ok_or_else(|| UleError::length::<Self>(bytes.len()))?;
118 A::ULE::validate_bytes(sized_chunk)?;
119 V::validate_bytes(variable_chunk)?;
120 Ok(())
121 }
122
123 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
124 let (_sized_chunk, variable_chunk) = bytes.split_at_unchecked(size_of::<A::ULE>());
125 let variable_ref = V::from_bytes_unchecked(variable_chunk);
128 let variable_ptr: *const V = variable_ref;
129
130 match (&size_of::<*const V>(), &size_of::<(*const u8, usize)>()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(size_of::<*const V>(), size_of::<(*const u8, usize)>());
139 let (_v_ptr, metadata) = transmute_copy::<*const V, (*const u8, usize)>(&variable_ptr);
142
143 match (&size_of::<*const Self>(), &size_of::<(*const u8, usize)>()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(size_of::<*const Self>(), size_of::<(*const u8, usize)>());
145 let composed_ptr =
147 transmute_copy::<(*const u8, usize), *const Self>(&(bytes.as_ptr(), metadata));
148 &*(composed_ptr)
149 }
150}
151
152unsafe impl<A, B, V> EncodeAsVarULE<VarTupleULE<A, V>> for VarTuple<A, B>
158where
159 A: AsULE + 'static,
160 B: EncodeAsVarULE<V>,
161 V: VarULE + ?Sized,
162{
163 fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
164 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
166 }
167
168 #[inline]
169 fn encode_var_ule_len(&self) -> usize {
170 size_of::<A::ULE>() + self.variable.encode_var_ule_len()
171 }
172
173 #[inline]
174 fn encode_var_ule_write(&self, dst: &mut [u8]) {
175 let (sized_chunk, variable_chunk) = dst.split_at_mut(size_of::<A::ULE>());
177 sized_chunk.clone_from_slice([self.sized.to_unaligned()].as_bytes());
178 self.variable.encode_var_ule_write(variable_chunk);
179 }
180}
181
182#[cfg(feature = "alloc")]
183impl<A, V> ToOwned for VarTupleULE<A, V>
184where
185 A: AsULE + 'static,
186 V: VarULE + ?Sized,
187{
188 type Owned = Box<Self>;
189 fn to_owned(&self) -> Self::Owned {
190 crate::ule::encode_varule_to_box(self)
191 }
192}
193
194impl<'a, A, B, V> ZeroFrom<'a, VarTupleULE<A, V>> for VarTuple<A, B>
195where
196 A: AsULE + 'static,
197 V: VarULE + ?Sized,
198 B: ZeroFrom<'a, V>,
199{
200 fn zero_from(other: &'a VarTupleULE<A, V>) -> Self {
201 VarTuple {
202 sized: AsULE::from_unaligned(other.sized),
203 variable: B::zero_from(&other.variable),
204 }
205 }
206}
207
208#[cfg(feature = "serde")]
209impl<A, V> serde::Serialize for VarTupleULE<A, V>
210where
211 A: AsULE + 'static,
212 V: VarULE + ?Sized,
213 A: serde::Serialize,
214 V: serde::Serialize,
215{
216 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
217 where
218 S: serde::Serializer,
219 {
220 if serializer.is_human_readable() {
221 let this = VarTuple {
222 sized: A::from_unaligned(self.sized),
223 variable: &self.variable,
224 };
225 this.serialize(serializer)
226 } else {
227 serializer.serialize_bytes(self.as_bytes())
228 }
229 }
230}
231
232#[cfg(feature = "serde")]
233impl<'a, 'de: 'a, A, V> serde::Deserialize<'de> for &'a VarTupleULE<A, V>
234where
235 A: AsULE + 'static,
236 V: VarULE + ?Sized,
237 A: serde::Deserialize<'de>,
238{
239 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
240 where
241 Des: serde::Deserializer<'de>,
242 {
243 if !deserializer.is_human_readable() {
244 let bytes = <&[u8]>::deserialize(deserializer)?;
245 VarTupleULE::<A, V>::parse_bytes(bytes).map_err(serde::de::Error::custom)
246 } else {
247 Err(serde::de::Error::custom(
248 "&VarTupleULE can only deserialize in zero-copy ways",
249 ))
250 }
251 }
252}
253
254#[cfg(all(feature = "serde", feature = "alloc"))]
255impl<'de, A, V> serde::Deserialize<'de> for Box<VarTupleULE<A, V>>
256where
257 A: AsULE + 'static,
258 V: VarULE + ?Sized,
259 A: serde::Deserialize<'de>,
260 Box<V>: serde::Deserialize<'de>,
261{
262 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
263 where
264 Des: serde::Deserializer<'de>,
265 {
266 if deserializer.is_human_readable() {
267 let this = VarTuple::<A, Box<V>>::deserialize(deserializer)?;
268 Ok(crate::ule::encode_varule_to_box(&this))
269 } else {
270 let deserialized = <&VarTupleULE<A, V>>::deserialize(deserializer)?;
273 Ok(deserialized.to_boxed())
274 }
275 }
276}
277
278#[test]
279fn test_simple() {
280 let var_tuple = VarTuple {
281 sized: 1500u16,
282 variable: "hello",
283 };
284 let var_tuple_ule = super::encode_varule_to_box(&var_tuple);
285 assert_eq!(var_tuple_ule.sized.as_unsigned_int(), 1500);
286 assert_eq!(&var_tuple_ule.variable, "hello");
287
288 #[cfg(feature = "serde")]
290 crate::ule::test_utils::assert_serde_roundtrips::<VarTupleULE<u16, str>>(&var_tuple_ule);
291}
292
293#[test]
294fn test_nested() {
295 use crate::{ZeroSlice, ZeroVec};
296 let var_tuple = VarTuple {
297 sized: 2000u16,
298 variable: VarTuple {
299 sized: '🦙',
300 variable: ZeroVec::alloc_from_slice(b"ICU"),
301 },
302 };
303 let var_tuple_ule = super::encode_varule_to_box(&var_tuple);
304 assert_eq!(var_tuple_ule.sized.as_unsigned_int(), 2000u16);
305 assert_eq!(var_tuple_ule.variable.sized.to_char(), '🦙');
306 assert_eq!(
307 &var_tuple_ule.variable.variable,
308 ZeroSlice::from_ule_slice(b"ICU")
309 );
310 #[cfg(feature = "serde")]
312 crate::ule::test_utils::assert_serde_roundtrips::<
313 VarTupleULE<u16, VarTupleULE<char, ZeroSlice<_>>>,
314 >(&var_tuple_ule);
315}