linebender_resource_handle/
blob.rs

1// Copyright 2022 the Raw Resource Handle Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use core::fmt;
5use core::sync::atomic::Ordering;
6extern crate alloc;
7use alloc::boxed::Box;
8use alloc::sync::{Arc, Weak};
9use alloc::vec::Vec;
10
11#[cfg(not(target_has_atomic = "64"))]
12use core::sync::atomic::AtomicU32 as AtomicCounter;
13#[cfg(target_has_atomic = "64")]
14use core::sync::atomic::AtomicU64 as AtomicCounter;
15
16/// Shared data with an associated unique identifier.
17pub struct Blob<T> {
18    data: Arc<dyn AsRef<[T]> + Send + Sync>,
19    id: u64,
20}
21
22#[cfg(feature = "serde")]
23impl<T> serde::Serialize for Blob<T>
24where
25    [T]: serde_bytes::Serialize,
26{
27    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28    where
29        S: serde::ser::Serializer,
30    {
31        serde_bytes::serialize(self.data(), serializer)
32    }
33}
34
35#[cfg(feature = "serde")]
36impl<'de, T> serde::de::Deserialize<'de> for Blob<T>
37where
38    T: serde::de::Deserialize<'de> + Sync + Send + 'static,
39    Box<[u8]>: AsRef<[T]>,
40{
41    fn deserialize<D>(des: D) -> Result<Self, D::Error>
42    where
43        D: serde::de::Deserializer<'de>,
44    {
45        let byte_buf: serde_bytes::ByteBuf = serde_bytes::Deserialize::deserialize(des)?;
46        let boxed_slice: Box<[u8]> = byte_buf.into_boxed_slice();
47        Ok(Self::new(Arc::new(boxed_slice)))
48    }
49}
50
51impl<T> fmt::Debug for Blob<T> {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        f.debug_struct("Blob")
54            .field("id", &self.id)
55            .finish_non_exhaustive()
56    }
57}
58
59impl<T> PartialEq for Blob<T> {
60    fn eq(&self, other: &Self) -> bool {
61        self.id == other.id
62    }
63}
64
65impl<T> Clone for Blob<T> {
66    fn clone(&self) -> Self {
67        Self {
68            data: Arc::clone(&self.data),
69            id: self.id,
70        }
71    }
72}
73
74impl<T> AsRef<[T]> for Blob<T> {
75    fn as_ref(&self) -> &[T] {
76        self.data()
77    }
78}
79
80impl<T> From<Vec<T>> for Blob<T>
81where
82    T: 'static + Send + Sync,
83{
84    fn from(vec: Vec<T>) -> Self {
85        let boxed: Box<[T]> = vec.into();
86        Self::new(Arc::new(boxed))
87    }
88}
89
90static ID_COUNTER: AtomicCounter = AtomicCounter::new(0);
91
92impl<T> Blob<T> {
93    /// Creates a new blob from the given data and generates a unique
94    /// identifier.
95    pub fn new(data: Arc<dyn AsRef<[T]> + Send + Sync>) -> Self {
96        Self {
97            data,
98            #[allow(clippy::useless_conversion)] // Conversion is not useless on 32-bit platforms and is harmless on 64-bit platforms
99            // Overflow: We expect running this code on 32-bit targets to be rare enough in practise that we don't handle overflow.
100            // Impossible on 64-bit as counter is only ever incremented by 1.
101            id: ID_COUNTER.fetch_add(1, Ordering::Relaxed).into(),
102        }
103    }
104
105    /// Creates a new blob from the given data and identifier.
106    ///
107    /// Note that while this function is not unsafe, usage of this in combination
108    /// with `new` (or with identifiers that are not uniquely associated with the given data)
109    /// can lead to inconsistencies.
110    pub fn from_raw_parts(data: Arc<dyn AsRef<[T]> + Send + Sync>, id: u64) -> Self {
111        Self { data, id }
112    }
113
114    /// Consumes self and returns the inner components of the blob.
115    #[must_use]
116    pub fn into_raw_parts(self) -> (Arc<dyn AsRef<[T]> + Send + Sync>, u64) {
117        (self.data, self.id)
118    }
119
120    /// Returns the length of the data.
121    #[must_use]
122    pub fn len(&self) -> usize {
123        self.data().len()
124    }
125
126    /// Returns true if the blob is empty.
127    #[must_use]
128    pub fn is_empty(&self) -> bool {
129        self.len() == 0
130    }
131
132    /// Returns a reference to the underlying data.
133    #[must_use]
134    pub fn data(&self) -> &[T] {
135        self.data.as_ref().as_ref()
136    }
137
138    /// Returns the unique identifier associated with the data.
139    #[must_use]
140    pub fn id(&self) -> u64 {
141        self.id
142    }
143
144    /// Returns the number of existing strong pointers to this blob.
145    #[must_use]
146    pub fn strong_count(&self) -> usize {
147        Arc::strong_count(&self.data)
148    }
149
150    /// Downgrades the shared blob to a weak reference.
151    #[must_use]
152    pub fn downgrade(&self) -> WeakBlob<T> {
153        WeakBlob {
154            data: Arc::downgrade(&self.data),
155            id: self.id,
156        }
157    }
158}
159
160/// Weak reference to a shared [blob](Blob).
161#[derive(Debug)]
162pub struct WeakBlob<T> {
163    data: Weak<dyn AsRef<[T]> + Send + Sync>,
164    id: u64,
165}
166
167impl<T> Clone for WeakBlob<T> {
168    fn clone(&self) -> Self {
169        Self {
170            data: Weak::clone(&self.data),
171            id: self.id,
172        }
173    }
174}
175
176impl<T> WeakBlob<T> {
177    /// Returns the unique identifier associated with the data.
178    #[must_use]
179    pub fn id(&self) -> u64 {
180        self.id
181    }
182
183    /// Upgrades the weak reference. Returns `None` if the inner value has been
184    /// dropped.
185    #[must_use]
186    pub fn upgrade(&self) -> Option<Blob<T>> {
187        Some(Blob {
188            data: self.data.upgrade()?,
189            id: self.id,
190        })
191    }
192}