/// A sized type that can be converted to a [`VarTupleULE`]. /// /// See the module for examples. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[allow(clippy::exhaustive_structs)] // well-defined type #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pubstruct VarTuple<A, B> { pub sized: A, pub variable: B,
}
/// A dynamically-sized type combining a sized and an unsized type. /// /// See the module for examples. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // well-defined type #[repr(C)] pubstruct VarTupleULE<A: AsULE, V: VarULE + ?Sized> { pub sized: A::ULE, pub variable: V,
}
// # Safety // // ## Representation // // The type `VarTupleULE` is align(1) because it is repr(C) and its fields // are all align(1), since they are themselves ULE and VarULE, which have // this same safety constraint. Further, there is no padding, because repr(C) // does not add padding when all fields are align(1). // // <https://doc.rust-lang.org/reference/type-layout.html#the-c-representation> // // Pointers to `VarTupleULE` are fat pointers with metadata equal to the // metadata of the inner DST field V. // // <https://doc.rust-lang.org/stable/std/ptr/trait.Pointee.html> // // ## Checklist // // Safety checklist for `VarULE`: // // 1. align(1): see "Representation" above. // 2. No padding: see "Representation" above. // 3. `validate_bytes` checks length and defers to the inner ULEs. // 4. `validate_bytes` checks length and defers to the inner ULEs. // 5. `from_bytes_unchecked` returns a fat pointer to the bytes. // 6. All other methods are left at their default impl. // 7. The two ULEs have byte equality, so this composition has byte equality. unsafeimpl<A, V> VarULE for VarTupleULE<A, V> where
A: AsULE + 'static,
V: VarULE + ?Sized,
{ fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> { let (sized_chunk, variable_chunk) = bytes
.split_at_checked(size_of::<A::ULE>())
.ok_or(UleError::length::<Self>(bytes.len()))?;
A::ULE::validate_bytes(sized_chunk)?;
V::validate_bytes(variable_chunk)?;
Ok(())
}
unsafefn from_bytes_unchecked(bytes: &[u8]) -> &Self { let (_sized_chunk, variable_chunk) = bytes.split_at_unchecked(size_of::<A::ULE>()); // Safety: variable_chunk is a valid V because of this function's precondition: bytes is a valid Self, // and a valid Self contains a valid V after the space needed for A::ULE. let variable_ref = V::from_bytes_unchecked(variable_chunk); let variable_ptr: *const V = variable_ref;
// Safety: The DST of VarTupleULE is a pointer to the `sized` element and has a metadata // equal to the metadata of the `variable` field (see "Representation" comments on the impl).
// Extract metadata from V's DST // Rust doesn't know that `&V` is a fat pointer so we have to use transmute_copy
assert_eq!(size_of::<*const V>(), size_of::<(*const u8, usize)>()); // Safety: We have asserted that the transmute Src and Dst are the same size. Furthermore, // DST pointers are a pointer and usize length metadata let (_v_ptr, metadata) = transmute_copy::<*const V, (*const u8, usize)>(&variable_ptr);
// Construct a new DST with the same metadata as V
assert_eq!(size_of::<*constSelf>(), size_of::<(*const u8, usize)>()); // Safety: Same as above but in the other direction. let composed_ptr =
transmute_copy::<(*const u8, usize), *constSelf>(&(bytes.as_ptr(), metadata));
&*(composed_ptr)
}
}
// # Safety // // encode_var_ule_len: returns the length of the two ULEs together. // // encode_var_ule_write: writes bytes by deferring to the inner ULE impls. unsafeimpl<A, B, V> EncodeAsVarULE<VarTupleULE<A, V>> for VarTuple<A, B> where
A: AsULE + 'static,
B: EncodeAsVarULE<V>,
V: VarULE + ?Sized,
{ fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R { // unnecessary if the other two are implemented
unreachable!()
}
#[cfg(feature = "serde")] impl<A, V> serde::Serialize for VarTupleULE<A, V> where
A: AsULE + 'static,
V: VarULE + ?Sized,
A: serde::Serialize,
V: serde::Serialize,
{ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: serde::Serializer,
{ if serializer.is_human_readable() { let this = VarTuple {
sized: A::from_unaligned(self.sized),
variable: &self.variable,
};
this.serialize(serializer)
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
#[cfg(feature = "serde")] impl<'a, 'de: 'a, A, V> serde::Deserialize<'de> for &'a VarTupleULE<A, V> where
A: AsULE + 'static,
V: VarULE + ?Sized,
A: serde::Deserialize<'de>,
{ fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> where
Des: serde::Deserializer<'de>,
{ if !deserializer.is_human_readable() { let bytes = <&[u8]>::deserialize(deserializer)?;
VarTupleULE::<A, V>::parse_bytes(bytes).map_err(serde::de::Error::custom)
} else {
Err(serde::de::Error::custom( "&VarTupleULE can only deserialize in zero-copy ways",
))
}
}
}
#[cfg(feature = "serde")] impl<'de, A, V> serde::Deserialize<'de> for alloc::boxed::Box<VarTupleULE<A, V>> where
A: AsULE + 'static,
V: VarULE + ?Sized,
A: serde::Deserialize<'de>,
alloc::boxed::Box<V>: serde::Deserialize<'de>,
{ fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error> where
Des: serde::Deserializer<'de>,
{ if deserializer.is_human_readable() { let this = VarTuple::<A, alloc::boxed::Box<V>>::deserialize(deserializer)?;
Ok(crate::ule::encode_varule_to_box(&this))
} else { // This branch should usually not be hit, since Cow-like use cases will hit the Deserialize impl for &'a TupleNVarULE instead.
let deserialized = <&VarTupleULE<A, V>>::deserialize(deserializer)?;
Ok(deserialized.to_boxed())
}
}
}
// Can't use inference due to https://github.com/rust-lang/rust/issues/130180 #[cfg(feature = "serde")] crate::ule::test_utils::assert_serde_roundtrips::<VarTupleULE<u16, str>>(&var_tuple_ule);
}
#[test] fn test_nested() { usecrate::{ZeroSlice, ZeroVec}; let var_tuple = VarTuple {
sized: 2000u16,
variable: VarTuple {
sized: '',
variable: ZeroVec::alloc_from_slice(b"ICU"),
},
}; let var_tuple_ule = super::encode_varule_to_box(&var_tuple);
assert_eq!(var_tuple_ule.sized.as_unsigned_int(), 2000u16);
assert_eq!(var_tuple_ule.variable.sized.to_char(), '');
assert_eq!(
&var_tuple_ule.variable.variable,
ZeroSlice::from_ule_slice(b"ICU")
); // Can't use inference due to https://github.com/rust-lang/rust/issues/130180 #[cfg(feature = "serde")] crate::ule::test_utils::assert_serde_roundtrips::<
VarTupleULE<u16, VarTupleULE<char, ZeroSlice<_>>>,
>(&var_tuple_ule);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.