/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerovec-0.11.9/src/ule/mod.rs
Line | Count | Source |
1 | | // This file is part of ICU4X. For terms of use, please see the file |
2 | | // called LICENSE at the top level of the ICU4X source tree |
3 | | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | | |
5 | | #![allow(clippy::upper_case_acronyms)] |
6 | | |
7 | | //! Traits over unaligned little-endian data (ULE, pronounced "yule"). |
8 | | //! |
9 | | //! The main traits for this module are [`ULE`], [`AsULE`] and, [`VarULE`]. |
10 | | //! |
11 | | //! See [the design doc](https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md) for details on how these traits |
12 | | //! works under the hood. |
13 | | mod chars; |
14 | | #[cfg(doc)] |
15 | | pub mod custom; |
16 | | mod encode; |
17 | | mod macros; |
18 | | mod multi; |
19 | | mod niche; |
20 | | mod option; |
21 | | mod plain; |
22 | | mod slices; |
23 | | #[cfg(test)] |
24 | | pub mod test_utils; |
25 | | |
26 | | pub mod tuple; |
27 | | pub mod tuplevar; |
28 | | pub mod vartuple; |
29 | | pub use chars::CharULE; |
30 | | #[cfg(feature = "alloc")] |
31 | | pub use encode::encode_varule_to_box; |
32 | | pub use encode::EncodeAsVarULE; |
33 | | pub use multi::MultiFieldsULE; |
34 | | pub use niche::{NicheBytes, NichedOption, NichedOptionULE}; |
35 | | pub use option::{OptionULE, OptionVarULE}; |
36 | | pub use plain::RawBytesULE; |
37 | | |
38 | | use core::{any, fmt, slice}; |
39 | | |
40 | | #[cfg(feature = "alloc")] |
41 | | use alloc::boxed::Box; |
42 | | |
43 | | /// Fixed-width, byte-aligned data that can be cast to and from a little-endian byte slice. |
44 | | /// |
45 | | /// If you need to implement this trait, consider using [`#[make_ule]`](crate::make_ule) or |
46 | | /// [`#[derive(ULE)]`](macro@ULE) instead. |
47 | | /// |
48 | | /// Types that are not fixed-width can implement [`VarULE`] instead. |
49 | | /// |
50 | | /// "ULE" stands for "Unaligned little-endian" |
51 | | /// |
52 | | /// # Safety |
53 | | /// |
54 | | /// Safety checklist for `ULE`: |
55 | | /// |
56 | | /// 1. The type *must not* include any uninitialized or padding bytes. |
57 | | /// 2. The type must have an alignment of 1 byte, or it is a ZST that is safe to construct. |
58 | | /// 3. The impl of [`ULE::validate_bytes()`] *must* return an error if the given byte slice |
59 | | /// would not represent a valid slice of this type. |
60 | | /// 4. The impl of [`ULE::validate_bytes()`] *must* return an error if the given byte slice |
61 | | /// cannot be used in its entirety (if its length is not a multiple of `size_of::<Self>()`). |
62 | | /// 5. All other methods *must* be left with their default impl, or else implemented according to |
63 | | /// their respective safety guidelines. |
64 | | /// 6. Acknowledge the following note about the equality invariant. |
65 | | /// |
66 | | /// If the ULE type is a struct only containing other ULE types (or other types which satisfy invariants 1 and 2, |
67 | | /// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`. |
68 | | /// |
69 | | /// # Equality invariant |
70 | | /// |
71 | | /// A non-safety invariant is that if `Self` implements `PartialEq`, the it *must* be logically |
72 | | /// equivalent to byte equality on [`Self::slice_as_bytes()`]. |
73 | | /// |
74 | | /// It may be necessary to introduce a "canonical form" of the ULE if logical equality does not |
75 | | /// equal byte equality. In such a case, [`Self::validate_bytes()`] should return an error |
76 | | /// for any values that are not in canonical form. For example, the decimal strings "1.23e4" and |
77 | | /// "12.3e3" are logically equal, but not byte-for-byte equal, so we could define a canonical form |
78 | | /// where only a single digit is allowed before `.`. |
79 | | /// |
80 | | /// Failure to follow this invariant will cause surprising behavior in `PartialEq`, which may |
81 | | /// result in unpredictable operations on `ZeroVec`, `VarZeroVec`, and `ZeroMap`. |
82 | | pub unsafe trait ULE |
83 | | where |
84 | | Self: Sized, |
85 | | Self: Copy + 'static, |
86 | | { |
87 | | /// Validates a byte slice, `&[u8]`. |
88 | | /// |
89 | | /// If `Self` is not well-defined for all possible bit values, the bytes should be validated. |
90 | | /// If the bytes can be transmuted, *in their entirety*, to a valid slice of `Self`, then `Ok` |
91 | | /// should be returned; otherwise, `Err` should be returned. |
92 | | fn validate_bytes(bytes: &[u8]) -> Result<(), UleError>; |
93 | | |
94 | | /// Parses a byte slice, `&[u8]`, and return it as `&[Self]` with the same lifetime. |
95 | | /// |
96 | | /// If `Self` is not well-defined for all possible bit values, the bytes should be validated, |
97 | | /// and an error should be returned in the same cases as [`Self::validate_bytes()`]. |
98 | | /// |
99 | | /// The default implementation executes [`Self::validate_bytes()`] followed by |
100 | | /// [`Self::slice_from_bytes_unchecked`]. |
101 | | /// |
102 | | /// Note: The following equality should hold: `bytes.len() % size_of::<Self>() == 0`. This |
103 | | /// means that the returned slice can span the entire byte slice. |
104 | 0 | fn parse_bytes_to_slice(bytes: &[u8]) -> Result<&[Self], UleError> { |
105 | 0 | Self::validate_bytes(bytes)?; |
106 | 0 | debug_assert_eq!(bytes.len() % size_of::<Self>(), 0); |
107 | 0 | Ok(unsafe { Self::slice_from_bytes_unchecked(bytes) }) |
108 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as zerovec::ule::ULE>::parse_bytes_to_slice Unexecuted instantiation: <u8 as zerovec::ule::ULE>::parse_bytes_to_slice Unexecuted instantiation: <_ as zerovec::ule::ULE>::parse_bytes_to_slice |
109 | | |
110 | | /// Takes a byte slice, `&[u8]`, and return it as `&[Self]` with the same lifetime, assuming |
111 | | /// that this byte slice has previously been run through [`Self::parse_bytes_to_slice()`] with |
112 | | /// success. |
113 | | /// |
114 | | /// The default implementation performs a pointer cast to the same region of memory. |
115 | | /// |
116 | | /// # Safety |
117 | | /// |
118 | | /// ## Callers |
119 | | /// |
120 | | /// Callers of this method must take care to ensure that `bytes` was previously passed through |
121 | | /// [`Self::validate_bytes()`] with success (and was not changed since then). |
122 | | /// |
123 | | /// ## Implementors |
124 | | /// |
125 | | /// Implementations of this method may call unsafe functions to cast the pointer to the correct |
126 | | /// type, assuming the "Callers" invariant above. |
127 | | /// |
128 | | /// Keep in mind that `&[Self]` and `&[u8]` may have different lengths. |
129 | | /// |
130 | | /// Safety checklist: |
131 | | /// |
132 | | /// 1. This method *must* return the same result as [`Self::parse_bytes_to_slice()`]. |
133 | | /// 2. This method *must* return a slice to the same region of memory as the argument. |
134 | | #[inline] |
135 | 0 | unsafe fn slice_from_bytes_unchecked(bytes: &[u8]) -> &[Self] { |
136 | 0 | let data = bytes.as_ptr(); |
137 | 0 | let len = bytes.len() / size_of::<Self>(); |
138 | 0 | debug_assert_eq!(bytes.len() % size_of::<Self>(), 0); |
139 | 0 | slice::from_raw_parts(data as *const Self, len) |
140 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as zerovec::ule::ULE>::slice_from_bytes_unchecked Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<3> as zerovec::ule::ULE>::slice_from_bytes_unchecked Unexecuted instantiation: <u8 as zerovec::ule::ULE>::slice_from_bytes_unchecked Unexecuted instantiation: <_ as zerovec::ule::ULE>::slice_from_bytes_unchecked |
141 | | |
142 | | /// Given `&[Self]`, returns a `&[u8]` with the same lifetime. |
143 | | /// |
144 | | /// The default implementation performs a pointer cast to the same region of memory. |
145 | | /// |
146 | | /// # Safety |
147 | | /// |
148 | | /// Implementations of this method should call potentially unsafe functions to cast the |
149 | | /// pointer to the correct type. |
150 | | /// |
151 | | /// Keep in mind that `&[Self]` and `&[u8]` may have different lengths. |
152 | | #[inline] |
153 | 0 | fn slice_as_bytes(slice: &[Self]) -> &[u8] { |
154 | 0 | unsafe { slice::from_raw_parts(slice as *const [Self] as *const u8, size_of_val(slice)) } |
155 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as zerovec::ule::ULE>::slice_as_bytes Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4> as zerovec::ule::ULE>::slice_as_bytes Unexecuted instantiation: <_ as zerovec::ule::ULE>::slice_as_bytes |
156 | | } |
157 | | |
158 | | /// A trait for any type that has a 1:1 mapping with an unaligned little-endian (ULE) type. |
159 | | /// |
160 | | /// If you need to implement this trait, consider using [`#[make_ule]`](crate::make_ule) instead. |
161 | | pub trait AsULE: Copy { |
162 | | /// The ULE type corresponding to `Self`. |
163 | | /// |
164 | | /// Types having infallible conversions from all bit values (Plain Old Data) can use |
165 | | /// `RawBytesULE` with the desired width; for example, `u32` uses `RawBytesULE<4>`. |
166 | | /// |
167 | | /// Types that are not well-defined for all bit values should implement a custom ULE. |
168 | | type ULE: ULE; |
169 | | |
170 | | /// Converts from `Self` to `Self::ULE`. |
171 | | /// |
172 | | /// This function may involve byte order swapping (native-endian to little-endian). |
173 | | /// |
174 | | /// For best performance, mark your implementation of this function `#[inline]`. |
175 | | fn to_unaligned(self) -> Self::ULE; |
176 | | |
177 | | /// Converts from `Self::ULE` to `Self`. |
178 | | /// |
179 | | /// This function may involve byte order swapping (little-endian to native-endian). |
180 | | /// |
181 | | /// For best performance, mark your implementation of this function `#[inline]`. |
182 | | /// |
183 | | /// # Safety |
184 | | /// |
185 | | /// This function is infallible because bit validation should have occurred when `Self::ULE` |
186 | | /// was first constructed. An implementation may therefore involve an `unsafe{}` block, like |
187 | | /// `from_bytes_unchecked()`. |
188 | | fn from_unaligned(unaligned: Self::ULE) -> Self; |
189 | | } |
190 | | |
191 | | /// A type whose byte sequence equals the byte sequence of its ULE type on |
192 | | /// little-endian platforms. |
193 | | /// |
194 | | /// This enables certain performance optimizations, such as |
195 | | /// [`ZeroVec::try_from_slice`](crate::ZeroVec::try_from_slice). |
196 | | /// |
197 | | /// # Implementation safety |
198 | | /// |
199 | | /// This trait is safe to implement if the type's ULE (as defined by `impl `[`AsULE`]` for T`) |
200 | | /// has an equal byte sequence as the type itself on little-endian platforms; i.e., one where |
201 | | /// `*const T` can be cast to a valid `*const T::ULE`. |
202 | | pub unsafe trait EqULE: AsULE {} |
203 | | |
204 | | /// A trait for a type where aligned slices can be cast to unaligned slices. |
205 | | /// |
206 | | /// Auto-implemented on all types implementing [`EqULE`]. |
207 | | pub trait SliceAsULE |
208 | | where |
209 | | Self: AsULE + Sized, |
210 | | { |
211 | | /// Converts from `&[Self]` to `&[Self::ULE]` if possible. |
212 | | /// |
213 | | /// In general, this function returns `Some` on little-endian and `None` on big-endian. |
214 | | fn slice_to_unaligned(slice: &[Self]) -> Option<&[Self::ULE]>; |
215 | | } |
216 | | |
217 | | #[cfg(target_endian = "little")] |
218 | | impl<T> SliceAsULE for T |
219 | | where |
220 | | T: EqULE, |
221 | | { |
222 | | #[inline] |
223 | 0 | fn slice_to_unaligned(slice: &[Self]) -> Option<&[Self::ULE]> { |
224 | | // This is safe because on little-endian platforms, the byte sequence of &[T] |
225 | | // is equivalent to the byte sequence of &[T::ULE] by the contract of EqULE, |
226 | | // and &[T::ULE] has equal or looser alignment than &[T]. |
227 | 0 | let ule_slice = |
228 | 0 | unsafe { slice::from_raw_parts(slice.as_ptr() as *const Self::ULE, slice.len()) }; |
229 | 0 | Some(ule_slice) |
230 | 0 | } |
231 | | } |
232 | | |
233 | | #[cfg(not(target_endian = "little"))] |
234 | | impl<T> SliceAsULE for T |
235 | | where |
236 | | T: EqULE, |
237 | | { |
238 | | #[inline] |
239 | | fn slice_to_unaligned(_: &[Self]) -> Option<&[Self::ULE]> { |
240 | | None |
241 | | } |
242 | | } |
243 | | |
244 | | /// Variable-width, byte-aligned data that can be cast to and from a little-endian byte slice. |
245 | | /// |
246 | | /// If you need to implement this trait, consider using [`#[make_varule]`](crate::make_varule) or |
247 | | /// [`#[derive(VarULE)]`](macro@VarULE) instead. |
248 | | /// |
249 | | /// This trait is for unsized types like `str` and `[T]`. For sized types use [`ULE`] instead. |
250 | | /// The [`custom`] module contains |
251 | | /// additional documentation on how this type can be implemented on custom types. |
252 | | /// |
253 | | /// If deserialization with `VarZeroVec` is desired is recommended to implement `Deserialize` for |
254 | | /// `Box<T>` (serde does not do this automatically for unsized `T`). |
255 | | /// |
256 | | /// For convenience it is typically desired to implement [`EncodeAsVarULE`] and [`ZeroFrom`](zerofrom::ZeroFrom) |
257 | | /// on some stack type to convert to and from the ULE type efficiently when necessary. |
258 | | /// |
259 | | /// # Safety |
260 | | /// |
261 | | /// Safety checklist for `VarULE`: |
262 | | /// |
263 | | /// 1. The type *must not* include any uninitialized or padding bytes. |
264 | | /// 2. The type must have an alignment of 1 byte. |
265 | | /// 3. The impl of [`VarULE::validate_bytes()`] *must* return an error if the given byte slice |
266 | | /// would not represent a valid slice of this type. |
267 | | /// 4. The impl of [`VarULE::validate_bytes()`] *must* return an error if the given byte slice |
268 | | /// cannot be used in its entirety. |
269 | | /// 5. The impl of [`VarULE::from_bytes_unchecked()`] must produce a reference to the same |
270 | | /// underlying data assuming that the given bytes previously passed validation. |
271 | | /// 6. All other methods *must* be left with their default impl, or else implemented according to |
272 | | /// their respective safety guidelines. |
273 | | /// 7. Acknowledge the following note about the equality invariant. |
274 | | /// 8. The type **must** be a unsized, slice like type. Specifically this trait requires that a fat |
275 | | /// pointer to this type is represented by the pointer to the first element and the number of elements. |
276 | | /// |
277 | | /// If the ULE type is a struct only containing other ULE/VarULE types (or other types which satisfy invariants 1 and 2, |
278 | | /// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`. |
279 | | /// |
280 | | /// # Equality invariant |
281 | | /// |
282 | | /// A non-safety invariant is that if `Self` implements `PartialEq`, the it *must* be logically |
283 | | /// equivalent to byte equality on [`Self::as_bytes()`]. |
284 | | /// |
285 | | /// It may be necessary to introduce a "canonical form" of the ULE if logical equality does not |
286 | | /// equal byte equality. In such a case, [`Self::validate_bytes()`] should return an error |
287 | | /// for any values that are not in canonical form. For example, the decimal strings "1.23e4" and |
288 | | /// "12.3e3" are logically equal, but not byte-for-byte equal, so we could define a canonical form |
289 | | /// where only a single digit is allowed before `.`. |
290 | | /// |
291 | | /// There may also be cases where a `VarULE` has muiltiple canonical forms, such as a faster |
292 | | /// version and a smaller version. The cleanest way to handle this case would be separate types. |
293 | | /// However, if this is not feasible, then the application should ensure that the data it is |
294 | | /// deserializing is in the expected form. For example, if the data is being loaded from an |
295 | | /// external source, then requests could carry information about the expected form of the data. |
296 | | /// |
297 | | /// Failure to follow this invariant will cause surprising behavior in `PartialEq`, which may |
298 | | /// result in unpredictable operations on `ZeroVec`, `VarZeroVec`, and `ZeroMap`. |
299 | | pub unsafe trait VarULE: 'static { |
300 | | /// Validates a byte slice, `&[u8]`. |
301 | | /// |
302 | | /// If `Self` is not well-defined for all possible bit values, the bytes should be validated. |
303 | | /// If the bytes can be transmuted, *in their entirety*, to a valid `&Self`, then `Ok` should |
304 | | /// be returned; otherwise, `Self::Error` should be returned. |
305 | | fn validate_bytes(_bytes: &[u8]) -> Result<(), UleError>; |
306 | | |
307 | | /// Parses a byte slice, `&[u8]`, and return it as `&Self` with the same lifetime. |
308 | | /// |
309 | | /// If `Self` is not well-defined for all possible bit values, the bytes should be validated, |
310 | | /// and an error should be returned in the same cases as [`Self::validate_bytes()`]. |
311 | | /// |
312 | | /// The default implementation executes [`Self::validate_bytes()`] followed by |
313 | | /// [`Self::from_bytes_unchecked`]. |
314 | | /// |
315 | | /// Note: The following equality should hold: `size_of_val(result) == size_of_val(bytes)`, |
316 | | /// where `result` is the successful return value of the method. This means that the return |
317 | | /// value spans the entire byte slice. |
318 | 0 | fn parse_bytes(bytes: &[u8]) -> Result<&Self, UleError> { |
319 | 0 | Self::validate_bytes(bytes)?; |
320 | 0 | let result = unsafe { Self::from_bytes_unchecked(bytes) }; |
321 | 0 | debug_assert_eq!(size_of_val(result), size_of_val(bytes)); |
322 | 0 | Ok(result) |
323 | 0 | } |
324 | | |
325 | | /// Takes a byte slice, `&[u8]`, and return it as `&Self` with the same lifetime, assuming |
326 | | /// that this byte slice has previously been run through [`Self::parse_bytes()`] with |
327 | | /// success. |
328 | | /// |
329 | | /// # Safety |
330 | | /// |
331 | | /// ## Callers |
332 | | /// |
333 | | /// Callers of this method must take care to ensure that `bytes` was previously passed through |
334 | | /// [`Self::validate_bytes()`] with success (and was not changed since then). |
335 | | /// |
336 | | /// ## Implementors |
337 | | /// |
338 | | /// Implementations of this method may call unsafe functions to cast the pointer to the correct |
339 | | /// type, assuming the "Callers" invariant above. |
340 | | /// |
341 | | /// Safety checklist: |
342 | | /// |
343 | | /// 1. This method *must* return the same result as [`Self::parse_bytes()`]. |
344 | | /// 2. This method *must* return a slice to the same region of memory as the argument. |
345 | | unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self; |
346 | | |
347 | | /// Given `&Self`, returns a `&[u8]` with the same lifetime. |
348 | | /// |
349 | | /// The default implementation performs a pointer cast to the same region of memory. |
350 | | /// |
351 | | /// # Safety |
352 | | /// |
353 | | /// Implementations of this method should call potentially unsafe functions to cast the |
354 | | /// pointer to the correct type. |
355 | | #[inline] |
356 | 0 | fn as_bytes(&self) -> &[u8] { |
357 | 0 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, size_of_val(self)) } |
358 | 0 | } Unexecuted instantiation: <icu_collections::codepointinvliststringlist::CodePointInversionListAndStringListULE as zerovec::ule::VarULE>::as_bytes Unexecuted instantiation: <icu_collections::codepointinvlist::cpinvlist::CodePointInversionListULE as zerovec::ule::VarULE>::as_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<potential_utf::uchar::PotentialCodePoint> as zerovec::ule::VarULE>::as_bytes Unexecuted instantiation: <_ as zerovec::ule::VarULE>::as_bytes |
359 | | |
360 | | /// Allocate on the heap as a `Box<T>` |
361 | | /// |
362 | | /// ✨ *Enabled with the `alloc` Cargo feature.* |
363 | | #[inline] |
364 | | #[cfg(feature = "alloc")] |
365 | | fn to_boxed(&self) -> Box<Self> { |
366 | | use alloc::borrow::ToOwned; |
367 | | let bytes = self.as_bytes().to_owned().into_boxed_slice(); |
368 | | // SAFETY: |
369 | | // - Self::from_bytes_unchecked is safe because the bytes came from self.as_bytes() which is valid. |
370 | | unsafe { cast_box(bytes) } |
371 | | } |
372 | | } |
373 | | |
374 | | // Proc macro reexports |
375 | | // |
376 | | // These exist so that our docs can use intra-doc links. |
377 | | // Due to quirks of how rustdoc does documentation on reexports, these must be in this module and not reexported from |
378 | | // a submodule |
379 | | |
380 | | /// Custom derive for [`ULE`]. |
381 | | /// |
382 | | /// This can be attached to [`Copy`] structs containing only [`ULE`] types. |
383 | | /// |
384 | | /// Most of the time, it is recommended one use [`#[make_ule]`](crate::make_ule) instead of defining |
385 | | /// a custom ULE type. |
386 | | #[cfg(feature = "derive")] |
387 | | pub use zerovec_derive::ULE; |
388 | | |
389 | | /// Custom derive for [`VarULE`] |
390 | | /// |
391 | | /// This can be attached to structs containing only [`ULE`] types with one [`VarULE`] type at the end. |
392 | | /// |
393 | | /// Most of the time, it is recommended one use [`#[make_varule]`](crate::make_varule) instead of defining |
394 | | /// a custom [`VarULE`] type. |
395 | | #[cfg(feature = "derive")] |
396 | | pub use zerovec_derive::VarULE; |
397 | | |
398 | | /// An error type to be used for decoding slices of ULE types |
399 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
400 | | #[non_exhaustive] |
401 | | pub enum UleError { |
402 | | /// Attempted to parse a buffer into a slice of the given ULE type but its |
403 | | /// length was not compatible. |
404 | | /// |
405 | | /// Typically created by a [`ULE`] impl via [`UleError::length()`]. |
406 | | /// |
407 | | /// [`ULE`]: crate::ule::ULE |
408 | | InvalidLength { ty: &'static str, len: usize }, |
409 | | /// The byte sequence provided for `ty` failed to parse correctly in the |
410 | | /// given ULE type. |
411 | | /// |
412 | | /// Typically created by a [`ULE`] impl via [`UleError::parse()`]. |
413 | | /// |
414 | | /// [`ULE`]: crate::ule::ULE |
415 | | ParseError { ty: &'static str }, |
416 | | } |
417 | | |
418 | | impl fmt::Display for UleError { |
419 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
420 | 0 | match *self { |
421 | 0 | UleError::InvalidLength { ty, len } => { |
422 | 0 | write!(f, "Invalid length {len} for slice of type {ty}") |
423 | | } |
424 | 0 | UleError::ParseError { ty } => { |
425 | 0 | write!(f, "Could not parse bytes to slice of type {ty}") |
426 | | } |
427 | | } |
428 | 0 | } |
429 | | } |
430 | | |
431 | | impl UleError { |
432 | | /// Construct a parse error for the given type |
433 | 0 | pub fn parse<T: ?Sized + 'static>() -> UleError { |
434 | 0 | UleError::ParseError { |
435 | 0 | ty: any::type_name::<T>(), |
436 | 0 | } |
437 | 0 | } Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_properties::enum_values::GeneralCategoryULE> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::subtags::Subtag> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::subtags::region::Region> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::subtags::script::Script> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::subtags::variant::Variant> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::subtags::language::Language> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::extensions::private::other::Subtag> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::extensions::unicode::subdivision::SubdivisionSuffix> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::extensions::unicode::key::Key> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::extensions::unicode::attribute::Attribute> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::extensions::transform::key::Key> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<icu_locale_core::preferences::extensions::unicode::keywords::currency::CurrencyType> Unexecuted instantiation: <zerovec::ule::UleError>::parse::<_> |
438 | | |
439 | | /// Construct an "invalid length" error for the given type and length |
440 | 0 | pub fn length<T: ?Sized + 'static>(len: usize) -> UleError { |
441 | 0 | UleError::InvalidLength { |
442 | 0 | ty: any::type_name::<T>(), |
443 | 0 | len, |
444 | 0 | } |
445 | 0 | } Unexecuted instantiation: <zerovec::ule::UleError>::length::<zerovec::ule::plain::RawBytesULE<2>> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::subtags::Subtag> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::subtags::region::Region> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::subtags::script::Script> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::subtags::variant::Variant> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::subtags::language::Language> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::extensions::private::other::Subtag> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::extensions::unicode::subdivision::SubdivisionSuffix> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::extensions::unicode::key::Key> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::extensions::unicode::attribute::Attribute> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::extensions::transform::key::Key> Unexecuted instantiation: <zerovec::ule::UleError>::length::<icu_locale_core::preferences::extensions::unicode::keywords::currency::CurrencyType> Unexecuted instantiation: <zerovec::ule::UleError>::length::<_> |
446 | | } |
447 | | |
448 | | impl core::error::Error for UleError {} |
449 | | |
450 | | #[cfg(feature = "alloc")] |
451 | | #[repr(C)] |
452 | | struct DstMetadata<Ptr> { |
453 | | ptr: Ptr, |
454 | | metadata: usize, |
455 | | } |
456 | | |
457 | | #[cfg(feature = "alloc")] |
458 | | /// Reconstructs a `Box<T>` from a `Box<[u8]>` while preserving unique pointer provenance |
459 | | /// and correctly resolving DST metadata. |
460 | | /// |
461 | | /// This is an internal helper used to safely convert a heap-allocated byte buffer |
462 | | /// into an owned `Box<T>` where `T` is an unsized `VarULE` type. |
463 | | /// |
464 | | /// ### Why this is needed |
465 | | /// |
466 | | /// Reconstructing a `Box<T>` is tricky because: |
467 | | /// 1. **Provenance**: If we derive the pointer from a temporary shared reference (e.g., `&[u8]`), |
468 | | /// Miri/Stacked Borrows will tag the pointer as `SharedReadOnly`. Reclaiming unique ownership |
469 | | /// and deallocating through a pointer with shared provenance is Undefined Behavior. To avoid this, |
470 | | /// we must derive the final pointer directly from `Box::into_raw` (which carries `Unique` provenance). |
471 | | /// 2. **DST Metadata**: Unsized types (like `VarTupleULE`) may have custom metadata that is *not* |
472 | | /// simply the byte length of the allocation. We must use `T::from_bytes_unchecked` to construct |
473 | | /// a reference with the correct metadata, and then combine that metadata with the unique thin |
474 | | /// pointer from `Box::into_raw` without clobbering the provenance. |
475 | | /// |
476 | | /// ### Safety |
477 | | /// |
478 | | /// - `T::from_bytes_unchecked` must be safe to call on the slice behind bytes |
479 | | pub(crate) unsafe fn cast_box<T: VarULE + ?Sized>(bytes: Box<[u8]>) -> Box<T> { |
480 | | use core::alloc::Layout; |
481 | | |
482 | | const { |
483 | | assert!(size_of::<&T>() == size_of::<DstMetadata<*const u8>>()); |
484 | | assert!(size_of::<&T>() == size_of::<DstMetadata<*mut u8>>()); |
485 | | let expected_layout = Layout::new::<&[u8]>(); |
486 | | let actual_layout = Layout::new::<&T>(); |
487 | | assert!(expected_layout.size() == actual_layout.size()); |
488 | | assert!(expected_layout.align() == actual_layout.align()); |
489 | | } |
490 | | let raw = Box::into_raw(bytes); |
491 | | // SAFETY: we just produced `raw`; it is valid |
492 | | let slice: &[u8] = unsafe { &*raw }; |
493 | | // SAFETY: caller guarantees `from_bytes_unchecked` is safe. |
494 | | let ref_t: &T = unsafe { T::from_bytes_unchecked(slice) }; |
495 | | // Extract metadata from ref_t. |
496 | | let DstMetadata { metadata, .. } = |
497 | | unsafe { core::mem::transmute_copy::<&T, DstMetadata<*const u8>>(&ref_t) }; |
498 | | |
499 | | // Construct *mut T from (raw_data_ptr, metadata). |
500 | | let ptr: *mut T = unsafe { |
501 | | core::mem::transmute_copy::<DstMetadata<*mut u8>, *mut T>(&DstMetadata { |
502 | | ptr: raw.cast::<u8>(), |
503 | | metadata, |
504 | | }) |
505 | | }; |
506 | | |
507 | | let expected_layout = Layout::for_value(slice); |
508 | | // SAFETY: ptr was reconstructed with the correct metadata and the unique pointer from Box::into_raw. |
509 | | let boxed = unsafe { Box::from_raw(ptr) }; |
510 | | assert_eq!(Layout::for_value(&*boxed), expected_layout); |
511 | | boxed |
512 | | } |