1use crate::ule::{EncodeAsVarULE, UleError, VarULE};
6#[cfg(feature = "alloc")]
7use alloc::boxed::Box;
8use core::fmt;
9use core::marker::PhantomData;
10#[cfg(feature = "alloc")]
11use core::mem::ManuallyDrop;
12use core::ops::Deref;
13use core::ptr::NonNull;
14use zerofrom::ZeroFrom;
15
16pub struct VarZeroCow<'a, V: ?Sized> {
34 raw: RawVarZeroCow,
37 marker1: PhantomData<&'a V>,
38 #[cfg(feature = "alloc")]
39 marker2: PhantomData<Box<V>>,
40}
41
42struct RawVarZeroCow {
47 buf: NonNull<[u8]>,
55 #[cfg(feature = "alloc")]
57 owned: bool,
58 }
61
62#[cfg(feature = "alloc")]
63impl Drop for RawVarZeroCow {
64 fn drop(&mut self) {
65 if self.owned {
67 unsafe {
68 let _ = Box::<[u8]>::from_raw(self.buf.as_ptr());
71 }
72 }
73 }
74}
75
76unsafe impl Send for RawVarZeroCow {}
78unsafe impl Sync for RawVarZeroCow {}
79
80impl Clone for RawVarZeroCow {
81 fn clone(&self) -> Self {
82 #[cfg(feature = "alloc")]
83 if self.is_owned() {
84 let b: Box<[u8]> = self.as_bytes().into();
86 let b = ManuallyDrop::new(b);
87 let buf: NonNull<[u8]> = (&**b).into();
88 return Self {
89 buf,
93 owned: true,
94 };
95 }
96 Self {
98 buf: self.buf,
102 #[cfg(feature = "alloc")]
103 owned: false,
104 }
105 }
106}
107
108impl<'a, V: ?Sized> Clone for VarZeroCow<'a, V> {
109 fn clone(&self) -> Self {
110 let raw = self.raw.clone();
111 unsafe { Self::from_raw(raw) }
114 }
115}
116
117impl<'a, V: VarULE + ?Sized> VarZeroCow<'a, V> {
118 pub fn parse_bytes(bytes: &'a [u8]) -> Result<Self, UleError> {
120 let val = V::parse_bytes(bytes)?;
121 Ok(Self::new_borrowed(val))
122 }
123
124 #[cfg(feature = "alloc")]
128 pub fn parse_owned_bytes(bytes: Box<[u8]>) -> Result<Self, UleError> {
129 V::validate_bytes(&bytes)?;
130 let bytes = ManuallyDrop::new(bytes);
131 let buf: NonNull<[u8]> = (&**bytes).into();
132 let raw = RawVarZeroCow {
133 buf,
137 owned: true,
138 };
139 Ok(Self {
140 raw,
141 marker1: PhantomData,
142 #[cfg(feature = "alloc")]
143 marker2: PhantomData,
144 })
145 }
146
147 pub const unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> Self {
154 unsafe {
155 let buf: NonNull<[u8]> = NonNull::new_unchecked(bytes as *const [u8] as *mut [u8]);
157 let raw = RawVarZeroCow {
158 buf,
162 #[cfg(feature = "alloc")]
163 owned: false,
164 };
165 Self::from_raw(raw)
167 }
168 }
169
170 #[cfg(feature = "alloc")]
176 pub fn from_encodeable<E: EncodeAsVarULE<V>>(encodeable: &E) -> Self {
177 let b = crate::ule::encode_varule_to_box(encodeable);
178 Self::new_owned(b)
179 }
180
181 pub fn new_borrowed(val: &'a V) -> Self {
183 unsafe {
184 Self::from_bytes_unchecked(val.as_bytes())
186 }
187 }
188
189 #[cfg(feature = "alloc")]
193 pub fn new_owned(val: Box<V>) -> Self {
194 let raw_box: *mut V = Box::into_raw(val);
195 let raw_ref: &V = unsafe { &*raw_box };
197 let slice_ref: &[u8] = raw_ref.as_bytes();
198 let buf = unsafe {
201 NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
202 raw_box.cast::<u8>(),
203 slice_ref.len(),
204 ))
205 };
206 let raw = RawVarZeroCow {
207 buf,
211 #[cfg(feature = "alloc")]
212 owned: true,
213 };
214 unsafe { Self::from_raw(raw) }
216 }
217}
218
219impl<'a, V: ?Sized> VarZeroCow<'a, V> {
220 pub fn is_owned(&self) -> bool {
222 self.raw.is_owned()
223 }
224
225 pub fn as_bytes(&self) -> &[u8] {
230 self.raw.as_bytes()
232 }
233
234 const unsafe fn from_raw(raw: RawVarZeroCow) -> Self {
236 Self {
237 raw,
239 marker1: PhantomData,
240 #[cfg(feature = "alloc")]
241 marker2: PhantomData,
242 }
243 }
244}
245
246impl RawVarZeroCow {
247 #[inline]
249 pub fn is_owned(&self) -> bool {
250 #[cfg(feature = "alloc")]
251 return self.owned;
252 #[cfg(not(feature = "alloc"))]
253 return false;
254 }
255
256 #[inline]
258 pub fn as_bytes(&self) -> &[u8] {
259 unsafe { self.buf.as_ref() }
261 }
262}
263
264impl<'a, V: VarULE + ?Sized> Deref for VarZeroCow<'a, V> {
265 type Target = V;
266 fn deref(&self) -> &V {
267 unsafe { V::from_bytes_unchecked(self.as_bytes()) }
269 }
270}
271
272impl<'a, V: VarULE + ?Sized> From<&'a V> for VarZeroCow<'a, V> {
273 fn from(other: &'a V) -> Self {
274 Self::new_borrowed(other)
275 }
276}
277
278#[cfg(feature = "alloc")]
279impl<'a, V: VarULE + ?Sized> From<Box<V>> for VarZeroCow<'a, V> {
280 fn from(other: Box<V>) -> Self {
281 Self::new_owned(other)
282 }
283}
284
285impl<'a, V: VarULE + ?Sized + fmt::Debug> fmt::Debug for VarZeroCow<'a, V> {
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
287 self.deref().fmt(f)
288 }
289}
290
291impl<'a, V: VarULE + ?Sized + PartialEq> PartialEq for VarZeroCow<'a, V> {
293 fn eq(&self, other: &Self) -> bool {
294 self.deref().eq(other.deref())
295 }
296}
297
298impl<'a, V: VarULE + ?Sized + Eq> Eq for VarZeroCow<'a, V> {}
299
300impl<'a, V: VarULE + ?Sized + PartialOrd> PartialOrd for VarZeroCow<'a, V> {
301 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
302 self.deref().partial_cmp(other.deref())
303 }
304}
305
306impl<'a, V: VarULE + ?Sized + Ord> Ord for VarZeroCow<'a, V> {
307 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
308 self.deref().cmp(other.deref())
309 }
310}
311
312unsafe impl<'a, V: VarULE + ?Sized> EncodeAsVarULE<V> for VarZeroCow<'a, V> {
318 fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
319 unreachable!()
321 }
322
323 #[inline]
324 fn encode_var_ule_len(&self) -> usize {
325 self.as_bytes().len()
326 }
327
328 #[inline]
329 fn encode_var_ule_write(&self, dst: &mut [u8]) {
330 dst.copy_from_slice(self.as_bytes())
331 }
332}
333
334#[cfg(feature = "serde")]
335impl<'a, V: VarULE + ?Sized + serde::Serialize> serde::Serialize for VarZeroCow<'a, V> {
336 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
337 where
338 S: serde::Serializer,
339 {
340 if serializer.is_human_readable() {
341 <V as serde::Serialize>::serialize(self.deref(), serializer)
342 } else {
343 serializer.serialize_bytes(self.as_bytes())
344 }
345 }
346}
347
348#[cfg(all(feature = "serde", feature = "alloc"))]
349impl<'a, 'de: 'a, V: VarULE + ?Sized> serde::Deserialize<'de> for VarZeroCow<'a, V>
350where
351 Box<V>: serde::Deserialize<'de>,
352{
353 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
354 where
355 Des: serde::Deserializer<'de>,
356 {
357 if deserializer.is_human_readable() {
358 let b = Box::<V>::deserialize(deserializer)?;
359 Ok(Self::new_owned(b))
360 } else {
361 let bytes = <&[u8]>::deserialize(deserializer)?;
362 Self::parse_bytes(bytes).map_err(serde::de::Error::custom)
363 }
364 }
365}
366
367#[cfg(feature = "databake")]
368impl<'a, V: VarULE + ?Sized> databake::Bake for VarZeroCow<'a, V> {
369 fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream {
370 env.insert("zerovec");
371 let bytes = self.as_bytes().bake(env);
372 databake::quote! {
373 unsafe {
375 zerovec::VarZeroCow::from_bytes_unchecked(#bytes)
376 }
377 }
378 }
379}
380
381#[cfg(feature = "databake")]
382impl<'a, V: VarULE + ?Sized> databake::BakeSize for VarZeroCow<'a, V> {
383 fn borrows_size(&self) -> usize {
384 self.as_bytes().len()
385 }
386}
387
388impl<'a, V: VarULE + ?Sized> ZeroFrom<'a, V> for VarZeroCow<'a, V> {
389 #[inline]
390 fn zero_from(other: &'a V) -> Self {
391 Self::new_borrowed(other)
392 }
393}
394
395impl<'a, 'b, V: VarULE + ?Sized> ZeroFrom<'a, VarZeroCow<'b, V>> for VarZeroCow<'a, V> {
396 #[inline]
397 fn zero_from(other: &'a VarZeroCow<'b, V>) -> Self {
398 Self::new_borrowed(other)
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::VarZeroCow;
405 use crate::ule::tuplevar::Tuple3VarULE;
406 use crate::vecs::VarZeroSlice;
407 #[test]
408 fn test_cow_roundtrip() {
409 type Messy = Tuple3VarULE<str, [u8], VarZeroSlice<str>>;
410 let vec = vec!["one", "two", "three"];
411 let messy: VarZeroCow<Messy> =
412 VarZeroCow::from_encodeable(&("hello", &b"g\xFF\xFFdbye"[..], vec));
413
414 assert_eq!(messy.a(), "hello");
415 assert_eq!(messy.b(), b"g\xFF\xFFdbye");
416 assert_eq!(&messy.c()[1], "two");
417
418 #[cfg(feature = "serde")]
419 {
420 let bincode = bincode::serialize(&messy).unwrap();
421 let deserialized: VarZeroCow<Messy> = bincode::deserialize(&bincode).unwrap();
422 assert_eq!(
423 messy, deserialized,
424 "Single element roundtrips with bincode"
425 );
426 assert!(!deserialized.is_owned());
427
428 let json = serde_json::to_string(&messy).unwrap();
429 let deserialized: VarZeroCow<Messy> = serde_json::from_str(&json).unwrap();
430 assert_eq!(messy, deserialized, "Single element roundtrips with serde");
431 }
432 }
433
434 struct TwoCows<'a> {
435 cow1: VarZeroCow<'a, str>,
436 cow2: VarZeroCow<'a, str>,
437 }
438
439 #[test]
440 fn test_eyepatch_works() {
441 let mut two = TwoCows {
443 cow1: VarZeroCow::new_borrowed("hello"),
444 cow2: VarZeroCow::new_owned("world".into()),
445 };
446 let three = VarZeroCow::new_borrowed(&*two.cow2);
447 two.cow1 = three;
448
449 }
454}