rebound/value.rs
1//! Dynamically typed, lifetime safe values
2
3use crate::ty::CommonTypeInfo;
4use crate::{Error, Reflected, Type};
5
6use core::marker::PhantomData;
7use core::ptr::NonNull;
8use core::{fmt, mem};
9
10use craft_eraser::{ErasedBox, ErasedNonNull};
11
12#[derive(Debug)]
13enum ValueKind {
14 Owned(ErasedBox),
15 Borrowed(ErasedNonNull),
16 Moved,
17}
18
19/// Trait to represent a bound that a type may not outlives some given lifetime. Used to allow
20/// sound borrowing of non-static Values.
21///
22/// If this was allowed, one could create a value containing a reference with a lifetime of `'a`,
23/// then when they call `borrow`, the compiler would allow the creation of an output reference with
24/// a lifetime of `'static`, which would be immediately unsound.
25///
26/// # Safety
27///
28/// Any implementation must ensure that all generics (lifetimes or types) in the type being
29/// implemented on are correctly bounded to not outlive `'no`
30pub unsafe trait NotOutlives<'no> {}
31
32/// A Value represents a value with an erased type. It may be owned or borrowed.
33/// The Value will have at most the lifetime of the value it was created from.
34///
35/// An owned Value will safely drop the contained object when it dies, while a borrowed Value
36/// will not.
37///
38/// A Value may be borrowed out as a concrete type, though an attempt to do so
39/// as a type not the same as the input type will result in a failure at runtime.
40#[derive(Debug)]
41pub struct Value<'a> {
42 value: ValueKind,
43 ty: Type,
44 _phantom: PhantomData<&'a ()>,
45}
46
47#[allow(clippy::should_implement_trait)]
48impl<'a> Value<'a> {
49 /// Create a new owned Value from a pointer, with a lifetime no greater than that of the
50 /// provided type.
51 ///
52 /// # Safety
53 ///
54 /// Similar to [`Box::from_raw`], this function may result in a double-free if called more than
55 /// once with the same pointer. The pointer must also upheld any additional obligations on that
56 /// function.
57 pub unsafe fn from_ptr_owned<T: ?Sized + Reflected + 'a>(val: NonNull<T>) -> Value<'a> {
58 Value {
59 // SAFETY: Out safety requires the same guarantees
60 value: ValueKind::Owned(ErasedBox::from_raw(val)),
61 ty: Type::from::<T>(),
62 _phantom: PhantomData,
63 }
64 }
65
66 /// Create a new borrowed Value from a reference, with a lifetime no greater than that of the
67 /// provided reference.
68 pub fn from_ref<T: ?Sized + Reflected>(val: &T) -> Value<'_> {
69 Value {
70 value: ValueKind::Borrowed(ErasedNonNull::from(val)),
71 ty: Type::from::<T>(),
72 _phantom: PhantomData,
73 }
74 }
75
76 /// Get a pointer to the raw backing metadata of this `Value`. It is the user's responsibility to not allow
77 /// this pointer to outlive the lifetime of this `Value`.
78 pub fn raw_meta(&self) -> NonNull<()> {
79 match &self.value {
80 ValueKind::Owned(b) => b.raw_meta_ptr(),
81 ValueKind::Borrowed(p) => p.raw_meta_ptr(),
82 ValueKind::Moved => unreachable!(),
83 }
84 }
85
86 /// Get the raw backing pointer of this `Value`. It is the user's responsibility to not allow
87 /// this pointer to outlive the lifetime of this `Value`.
88 pub fn raw_ptr(&self) -> NonNull<()> {
89 match &self.value {
90 ValueKind::Owned(b) => b.raw_ptr(),
91 ValueKind::Borrowed(p) => p.raw_ptr(),
92 ValueKind::Moved => unreachable!(),
93 }
94 }
95
96 /// Get the [`Type`] of this Value
97 pub fn ty(&self) -> Type {
98 self.ty
99 }
100
101 /// Attempt to move the contained T out of this Value in a fallible manner. This method is
102 /// unsafe due to possible lifetime unsoundness, use [`Value::try_cast`] for a lifetime-safe
103 /// variant.
104 ///
105 /// # Errors
106 ///
107 /// - This will fail if the Value is Borrowed with an [`Error::BorrowedValue`]
108 /// - This will fail if the T isn't the same as the type of this value with [`Error::WrongType`]
109 ///
110 /// # Safety
111 ///
112 /// If this Value contains data which may not live forever, this function does not ensure that
113 /// the provided T does *not* outlive `'a`. As such, it is the user's responsibility to not move
114 /// data out of this value in a way which gives it a lifetime longer than its original.
115 pub unsafe fn try_cast_unsafe<T: Reflected>(mut self) -> Result<T, (Self, Error)> {
116 let value = mem::replace(&mut self.value, ValueKind::Moved);
117
118 if let ValueKind::Owned(b) = value {
119 if Type::from::<T>() == self.ty {
120 Ok(*b.reify_box::<T>())
121 } else {
122 self.value = ValueKind::Owned(b);
123 let ty = self.ty;
124 Err((self, Error::wrong_type(Type::from::<T>(), ty)))
125 }
126 } else {
127 self.value = value;
128 Err((self, Error::BorrowedValue))
129 }
130 }
131
132 /// Attempt to move the contained T out of this Value, panicking on failure. This will panic
133 /// in all the cases that [`Value::try_cast_unsafe`] would return an Err value.
134 ///
135 /// # Panics
136 ///
137 /// If this value contains some type other than `T`, or if this is a borrowed value and as
138 /// such cannot be moved out of
139 ///
140 /// # Safety
141 ///
142 /// See [`Value::try_cast_unsafe`]
143 pub unsafe fn cast_unsafe<T: Reflected>(self) -> T {
144 self.try_cast_unsafe()
145 .unwrap_or_else(|_| panic!("Couldn't cast Value into type {}", T::name()))
146 }
147
148 /// Attempt to move the contained T out of this Value in a fallible manner.
149 ///
150 /// # Errors
151 ///
152 /// - This will fail if the Value is Borrowed with an [`Error::BorrowedValue`]
153 /// - This will fail if the T isn't the same as the type of this value with [`Error::WrongType`]
154 pub fn try_cast<T: Reflected + NotOutlives<'a>>(self) -> Result<T, (Self, Error)> {
155 // SAFETY: Lifetimes are guaranteed safe by the `NotOutlives` bound
156 unsafe { self.try_cast_unsafe() }
157 }
158
159 /// Attempt to move the contained T out of this Value, panicking on failure. This will panic
160 /// in all the cases that [`Value::try_cast`] would return an Err value.
161 ///
162 /// # Panics
163 ///
164 /// If this value contains some type other than `T`, or if this is a borrowed value and as
165 /// such cannot be moved out of
166 ///
167 pub fn cast<T: Reflected + NotOutlives<'a>>(self) -> T {
168 self.try_cast()
169 .unwrap_or_else(|_| panic!("Couldn't cast Value into type {}", T::name()))
170 }
171
172 // Should the returned references live for 'a? No. Why?
173 // Assume an owned `Value<'static>` with ty of i32. A borrow out may live forever, however,
174 // the Value will destroy the contained data when it goes out of scope. This means a user
175 // could safely borrow a value, and then have it become invalid.
176
177 /// Attempt to immutable borrow the T contained in this Value in a fallible manner.
178 ///
179 /// This will fail if the T isn't the same as the type of this value with [`Error::WrongType`]
180 ///
181 /// # Safety
182 ///
183 /// See [`Value::try_cast_unsafe`]
184 pub unsafe fn try_borrow_unsafe<T: ?Sized + Reflected>(&self) -> Result<&T, Error> {
185 if Type::from::<T>() == self.ty() {
186 let ptr =
187 NonNull::<T>::from_raw_parts(self.raw_ptr(), *self.raw_meta().cast().as_ref());
188 Ok(ptr.as_ref())
189 } else {
190 Err(Error::wrong_type(Type::from::<T>(), self.ty()))
191 }
192 }
193
194 /// Attempt to immutably borrow the T contained in this value, panicking on failure.
195 ///
196 /// # Panics
197 ///
198 /// In all cases that [`Value::try_borrow_unsafe`] would return an Err, if this value contains
199 /// some type other than `T`
200 ///
201 /// # Safety
202 ///
203 /// See [`Value::try_cast_unsafe`]
204 pub unsafe fn borrow_unsafe<T: ?Sized + Reflected>(&self) -> &T {
205 self.try_borrow_unsafe()
206 .unwrap_or_else(|_| panic!("Couldn't borrow Value as type {}", T::name()))
207 }
208
209 /// Attempt to immutably borrow the T contained by this Value in a fallible manner.
210 ///
211 /// This will fail if the T isn't the same as the type of this value with [`Error::WrongType`]
212 ///
213 /// # Examples
214 ///
215 /// Successful usage
216 /// ```
217 /// # use rebound::Value;
218 /// let int = Value::from(1);
219 /// assert!(int.try_borrow::<i32>().is_ok());
220 /// ```
221 ///
222 /// Example failure
223 /// ```
224 /// # use rebound::Value;
225 /// let int = Value::from(1);
226 /// assert!(int.try_borrow::<&str>().is_err());
227 /// ```
228 pub fn try_borrow<'b, T: ?Sized + Reflected + NotOutlives<'a>>(
229 &'b self,
230 ) -> Result<&'b T, Error> {
231 // SAFETY: Lifetimes are guaranteed safe by the `NotOutlives` bound
232 unsafe { self.try_borrow_unsafe() }
233 }
234
235 /// Attempt to immutably borrow the T contained in this value, panicking on failure. This will
236 /// panic in all the cases that [`Value::try_borrow`] would return an Err value.
237 ///
238 /// # Panics
239 ///
240 /// In all cases that [`Value::try_borrow`] would return an Err, if this value contains some
241 /// type other than `T`
242 ///
243 /// # Example
244 ///
245 /// Successful usage
246 /// ```
247 /// # use rebound::Value;
248 /// let bool = Value::from(true);
249 /// let _ = bool.borrow::<bool>();
250 /// ```
251 ///
252 /// Example failure
253 /// ```should_panic
254 /// # use rebound::Value;
255 /// let bool = Value::from(true);
256 /// let _ = bool.borrow::<char>();
257 /// ```
258 pub fn borrow<'b, T: ?Sized + Reflected + NotOutlives<'a>>(&'b self) -> &'b T {
259 self.try_borrow()
260 .unwrap_or_else(|_| panic!("Couldn't borrow Value as type {}", T::name()))
261 }
262
263 /// Attempt to mutably borrow the T contained by this Value in a fallible manner.
264 ///
265 /// This will fail if the T isn't the same as the type of this Value with [`Error::WrongType`]
266 ///
267 /// # Safety
268 ///
269 /// See [`Value::try_cast_unsafe`]
270 pub unsafe fn try_borrow_unsafe_mut<T: ?Sized + Reflected>(&mut self) -> Result<&mut T, Error> {
271 if Type::from::<T>() == self.ty() {
272 let mut ptr =
273 NonNull::<T>::from_raw_parts(self.raw_ptr(), *self.raw_meta().cast().as_ref());
274 Ok(ptr.as_mut())
275 } else {
276 Err(Error::wrong_type(Type::from::<T>(), self.ty()))
277 }
278 }
279
280 /// Attempt to mutably borrow the T contained in this value, panicking on failure. This will
281 /// panic in all the cases that [`Value::try_borrow_mut`] would return an Err value.
282 ///
283 /// # Panics
284 ///
285 /// In all cases that [`Value::try_borrow_unsafe_mut`] would return an Err, if this value
286 /// contains some type other than `T`
287 ///
288 /// # Safety
289 ///
290 /// See [`Value::try_cast_unsafe`]
291 pub unsafe fn borrow_unsafe_mut<T: ?Sized + Reflected>(&mut self) -> &mut T {
292 self.try_borrow_unsafe_mut()
293 .unwrap_or_else(|_| panic!("Couldn't mutably borrow Value as type {}", T::name()))
294 }
295
296 /// Attempt to mutably borrow the T contained by this Value in a fallible manner.
297 ///
298 /// This will fail if the T isn't the same as the type of this Value with [`Error::WrongType`]
299 ///
300 /// # Example
301 ///
302 /// Successful usage
303 /// ```
304 /// # use rebound::Value;
305 /// let mut char = Value::from('a');
306 /// let c = char.try_borrow_mut::<char>()
307 /// .unwrap();
308 /// *c = 'b';
309 /// ```
310 ///
311 /// Example failure
312 /// ```should_panic
313 /// # use rebound::Value;
314 /// let mut char = Value::from('a');
315 /// let c = char.try_borrow_mut::<i32>()
316 /// .unwrap();
317 /// *c = 2;
318 ///
319 /// ```
320 pub fn try_borrow_mut<'b, T: ?Sized + Reflected + NotOutlives<'a>>(
321 &'b mut self,
322 ) -> Result<&'b mut T, Error> {
323 // SAFETY: Lifetimes are guaranteed safe by the `NotOutlives` bound
324 unsafe { self.try_borrow_unsafe_mut() }
325 }
326
327 /// Attempt to mutably borrow the T contained in this value, panicking on failure. This will
328 /// panic in all the cases that [`Value::try_borrow_mut`] would return an Err value.
329 ///
330 /// # Panics
331 ///
332 /// In all cases that [`Value::try_borrow_mut`] would return an Err, if this value
333 /// contains some type other than `T`
334 ///
335 /// # Example
336 ///
337 /// Successful usage
338 /// ```
339 /// # use rebound::Value;
340 /// let mut str = Value::from("a string");
341 /// let _ = str.borrow_mut::<&str>();
342 /// ```
343 ///
344 /// Example failure
345 /// ```should_panic
346 /// # use rebound::Value;
347 /// let mut str = Value::from("a string");
348 /// let _ = str.borrow_mut::<&i32>();
349 /// ```
350 pub fn borrow_mut<'b, T: ?Sized + Reflected + NotOutlives<'a>>(&'b mut self) -> &'b mut T {
351 self.try_borrow_mut()
352 .unwrap_or_else(|_| panic!("Couldn't mutably borrow Value as type {}", T::name()))
353 }
354
355 /// If this Value is not a reference Type, get a Value containing an immutable reference to
356 /// the data contained within this Value. A convenience function for operations that expect a
357 /// reference to data you own.
358 pub fn as_ref(&self) -> Result<Value<'_>, Error> {
359 self.ty.as_ref(self)
360 }
361
362 /// If this Value is not a reference Type, get a Value containing a mutable reference to the
363 /// data contained within this Value. A convenience function for operations that expect a
364 /// mutable reference to data you own.
365 pub fn as_mut(&mut self) -> Result<Value<'_>, Error> {
366 let ty = self.ty;
367 ty.as_mut(self)
368 }
369}
370
371impl<'a> fmt::Pointer for Value<'a> {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 fmt::Pointer::fmt(&self.raw_ptr(), f)
374 }
375}
376
377impl<'a, T: Reflected + 'a> From<T> for Value<'a> {
378 default fn from(val: T) -> Value<'a> {
379 Value {
380 value: ValueKind::Owned(ErasedBox::new(val)),
381 ty: Type::from::<T>(),
382 _phantom: PhantomData,
383 }
384 }
385}