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}