rune/runtime/shared.rs
1use core::fmt;
2use core::marker::PhantomData;
3use core::mem::{replace, ManuallyDrop};
4use core::ptr::{self, addr_of, NonNull};
5
6use crate::alloc;
7use crate::alloc::clone::TryClone;
8use crate::any::AnyMarker;
9use crate::compile::meta;
10use crate::{Any, Hash};
11
12use super::{
13 AnyObj, AnyObjData, AnyObjError, AnyObjErrorKind, AnyObjVtable, AnyTypeInfo, BorrowMut,
14 BorrowRef, FromValue, MaybeTypeOf, Mut, RawAnyGuard, Ref, RefVtable, RuntimeError, ToValue,
15 TypeHash, TypeInfo, TypeOf, Value,
16};
17
18/// A typed wrapper for a reference.
19///
20/// This is identical in layout to [`AnyObj`], but provides a statically
21/// type-checked container.
22///
23/// [`AnyObj`]: super::AnyObj
24pub struct Shared<T> {
25 /// The shared value.
26 shared: NonNull<AnyObjData>,
27 /// The statically known type of the value.
28 _marker: PhantomData<T>,
29}
30
31impl<T> Shared<T>
32where
33 T: Any,
34{
35 /// Construct a new typed shared value.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// use rune::Value;
41 /// use rune::runtime::Shared;
42 /// use rune::alloc::String;
43 ///
44 /// let string = String::try_from("Hello World")?;
45 /// let string = Shared::new(string)?;
46 /// let string = Value::from(string);
47 ///
48 /// let string = string.into_any_obj()?;
49 /// assert_eq!(string.borrow_ref::<String>()?.as_str(), "Hello World");
50 /// # Ok::<_, rune::support::Error>(())
51 /// ```
52 #[inline]
53 pub fn new(value: T) -> alloc::Result<Self> {
54 let any = AnyObj::new(value)?;
55 // SAFETY: We know that the value is valid.
56 unsafe { Ok(any.unsafe_into_shared()) }
57 }
58
59 /// Construct a new typed object.
60 ///
61 /// # Safety
62 ///
63 /// Caller must ensure that the type is of the value `T`.
64 #[inline]
65 pub(super) unsafe fn from_raw(shared: NonNull<AnyObjData<T>>) -> Self {
66 Self {
67 shared: shared.cast(),
68 _marker: PhantomData,
69 }
70 }
71
72 /// Coerce into a type-erased [`AnyObj`].
73 #[inline]
74 pub(crate) fn into_any_obj(self) -> AnyObj {
75 let this = ManuallyDrop::new(self);
76 // SAFETY: We know that the shared value is valid.
77 unsafe { AnyObj::from_raw(this.shared.cast()) }
78 }
79
80 /// Take the owned value of type `T`.
81 ///
82 /// This consumes any live references of the value and accessing them in the
83 /// future will result in an error.
84 ///
85 /// # Errors
86 ///
87 /// This errors if the underlying value is not owned.
88 pub fn take(self) -> Result<T, AnyObjError> {
89 let vtable = vtable(&self);
90
91 if !vtable.is_owned() {
92 return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
93 vtable.type_info(),
94 )));
95 }
96
97 // SAFETY: The appropriate type has been type checked for when the
98 // container was constructed.
99 unsafe {
100 self.shared.as_ref().access.try_take()?;
101 let data = vtable.as_ptr::<T>(self.shared);
102 Ok(data.read())
103 }
104 }
105
106 /// Downcast into an owned value of type [`Ref<T>`].
107 ///
108 /// # Errors
109 ///
110 /// This errors in case the underlying value is not owned, non-owned
111 /// references cannot be coerced into [`Ref<T>`].
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use rune::{Any, Value};
117 ///
118 /// #[derive(Any)]
119 /// struct Struct(u32);
120 ///
121 /// let value = Value::new(Struct(42))?;
122 /// let value = value.into_shared::<Struct>()?;
123 ///
124 /// let reference = value.clone().into_ref()?;
125 /// assert!(value.borrow_ref().is_ok());
126 /// assert_eq!(reference.0, 42);
127 /// # Ok::<_, rune::support::Error>(())
128 /// ```
129 pub fn into_ref(self) -> Result<Ref<T>, AnyObjError> {
130 let vtable = vtable(&self);
131
132 if !vtable.is_owned() {
133 return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
134 vtable.type_info(),
135 )));
136 }
137
138 // SAFETY: The appropriate type has been type checked for when the
139 // container was constructed.
140 unsafe {
141 self.shared.as_ref().access.try_shared()?;
142 let this = ManuallyDrop::new(self);
143 let data = vtable.as_ptr(this.shared);
144
145 let vtable = &RefVtable {
146 drop: |shared: NonNull<()>| {
147 let shared = shared.cast::<AnyObjData>();
148 shared.as_ref().access.release();
149 AnyObjData::dec(shared)
150 },
151 // The reference keeps the value alive, so it can be handed
152 // back: releasing the access and handing the count over is what
153 // dropping does, minus the count being given up.
154 into_value: Some(|shared: NonNull<()>| {
155 let shared = shared.cast::<AnyObjData>();
156 shared.as_ref().access.release();
157 Value::from(AnyObj::from_raw(shared))
158 }),
159 };
160
161 let guard = RawAnyGuard::new(this.shared.cast(), vtable);
162 Ok(Ref::new(data, guard))
163 }
164 }
165
166 /// Downcast into an owned value of type [`Mut<T>`].
167 ///
168 /// # Errors
169 ///
170 /// This errors in case the underlying value is not owned, non-owned
171 /// references cannot be coerced into [`Mut<T>`].
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use rune::{Any, Value};
177 ///
178 /// #[derive(Any)]
179 /// struct Struct(u32);
180 ///
181 /// let value = Value::new(Struct(42))?;
182 /// let value = value.into_shared::<Struct>()?;
183 ///
184 /// let mut mutable = value.clone().into_mut()?;
185 /// assert!(value.borrow_ref().is_err());
186 /// mutable.0 += 1;
187 /// drop(mutable);
188 ///
189 /// assert_eq!(value.borrow_ref()?.0, 43);
190 /// # Ok::<_, rune::support::Error>(())
191 /// ```
192 pub fn into_mut(self) -> Result<Mut<T>, AnyObjError> {
193 let vtable = vtable(&self);
194
195 if !vtable.is_owned() {
196 return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
197 vtable.type_info(),
198 )));
199 }
200
201 // SAFETY: The appropriate type has been type checked for when the
202 // container was constructed.
203 unsafe {
204 self.shared.as_ref().access.try_exclusive()?;
205 let this = ManuallyDrop::new(self);
206 let data = vtable.as_ptr(this.shared);
207
208 let vtable = &RefVtable {
209 drop: |shared: NonNull<()>| {
210 let shared = shared.cast::<AnyObjData>();
211 shared.as_ref().access.release();
212 AnyObjData::dec(shared)
213 },
214 // The reference keeps the value alive, so it can be handed
215 // back: releasing the access and handing the count over is what
216 // dropping does, minus the count being given up.
217 into_value: Some(|shared: NonNull<()>| {
218 let shared = shared.cast::<AnyObjData>();
219 shared.as_ref().access.release();
220 Value::from(AnyObj::from_raw(shared))
221 }),
222 };
223
224 let guard = RawAnyGuard::new(this.shared.cast(), vtable);
225 Ok(Mut::new(data, guard))
226 }
227 }
228
229 /// Borrow a shared reference to the value while checking for shared access.
230 ///
231 /// This prevents other exclusive accesses from being performed while the
232 /// guard returned from this function is live.
233 ///
234 /// # Examples
235 ///
236 /// ```
237 /// use rune::{Any, Value};
238 ///
239 /// #[derive(Any)]
240 /// struct Struct(u32);
241 ///
242 /// let value = Value::new(Struct(42))?;
243 /// let value = value.into_shared::<Struct>()?;
244 ///
245 /// let borrowed = value.borrow_ref()?;
246 /// assert!(value.borrow_ref().is_ok());
247 /// drop(borrowed);
248 /// assert!(value.borrow_ref().is_ok());
249 /// # Ok::<_, rune::support::Error>(())
250 /// ```
251 pub fn borrow_ref(&self) -> Result<BorrowRef<'_, T>, AnyObjError> {
252 let vtable = vtable(self);
253
254 // SAFETY: The appropriate type has been type checked for when the
255 // container was constructed.
256 unsafe {
257 let guard = self.shared.as_ref().access.shared()?;
258 let data = vtable.as_ptr(self.shared);
259 Ok(BorrowRef::new(data, guard.into_raw()))
260 }
261 }
262
263 /// Borrow an exclusive reference to the value.
264 ///
265 /// This prevents other accesses from being performed while the guard
266 /// returned from this function is live.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use rune::{Any, Value};
272 ///
273 /// #[derive(Any)]
274 /// struct Struct(u32);
275 ///
276 /// let value = Value::new(Struct(42))?;
277 /// let value = value.into_shared::<Struct>()?;
278 ///
279 /// let borrowed = value.borrow_mut()?;
280 /// assert!(value.borrow_ref().is_err());
281 /// drop(borrowed);
282 /// assert!(value.borrow_ref().is_ok());
283 /// # Ok::<_, rune::support::Error>(())
284 /// ```
285 pub fn borrow_mut(&self) -> Result<BorrowMut<'_, T>, AnyObjError> {
286 let vtable = vtable(self);
287
288 if !vtable.is_mutable() {
289 return Err(AnyObjError::new(AnyObjErrorKind::Cast(
290 T::ANY_TYPE_INFO,
291 vtable.type_info(),
292 )));
293 }
294
295 // SAFETY: The appropriate type has been type checked for when the
296 // container was constructed.
297 unsafe {
298 let guard = self.shared.as_ref().access.exclusive()?;
299 let data = vtable.as_ptr(self.shared);
300 Ok(BorrowMut::new(data, guard.into_raw()))
301 }
302 }
303
304 /// Test if the value is sharable.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use rune::{Any, Value};
310 ///
311 /// #[derive(Any)]
312 /// struct Struct(u32);
313 ///
314 /// let value = Value::new(Struct(42))?;
315 /// let value = value.into_shared::<Struct>()?;
316 ///
317 /// {
318 /// assert!(value.is_writable());
319 ///
320 /// let borrowed = value.borrow_mut()?;
321 /// assert!(!value.is_writable());
322 /// drop(borrowed);
323 /// assert!(value.is_writable());
324 /// }
325 ///
326 /// let foo = Struct(42);
327 ///
328 /// {
329 /// let (value, guard) = unsafe { Value::from_ref(&foo)? };
330 /// let value = value.into_shared::<Struct>()?;
331 /// assert!(value.is_readable());
332 /// assert!(!value.is_writable());
333 /// }
334 ///
335 /// let mut foo = Struct(42);
336 ///
337 /// {
338 /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? };
339 /// let value = value.into_shared::<Struct>()?;
340 /// assert!(value.is_readable());
341 /// assert!(value.is_writable());
342 /// }
343 /// # Ok::<_, rune::support::Error>(())
344 /// ```
345 pub fn is_readable(&self) -> bool {
346 // Safety: Since we have a reference to this shared, we know that the
347 // inner is available.
348 unsafe { self.shared.as_ref().access.is_shared() }
349 }
350
351 /// Test if a value is writable.
352 ///
353 /// # Examples
354 ///
355 /// ```
356 /// use rune::{Any, Value};
357 ///
358 /// #[derive(Any)]
359 /// struct Struct(u32);
360 ///
361 /// let value = Value::new(Struct(42))?;
362 /// let value = value.into_shared::<Struct>()?;
363 ///
364 /// {
365 /// assert!(value.is_writable());
366 ///
367 /// let borrowed = value.borrow_mut()?;
368 /// assert!(!value.is_writable());
369 /// drop(borrowed);
370 /// assert!(value.is_writable());
371 /// }
372 ///
373 /// let foo = Struct(42);
374 ///
375 /// {
376 /// let (value, guard) = unsafe { Value::from_ref(&foo)? };
377 /// let value = value.into_shared::<Struct>()?;
378 /// assert!(value.is_readable());
379 /// assert!(!value.is_writable());
380 /// }
381 ///
382 /// let mut foo = Struct(42);
383 ///
384 /// {
385 /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? };
386 /// let value = value.into_shared::<Struct>()?;
387 /// assert!(value.is_readable());
388 /// assert!(value.is_writable());
389 /// }
390 /// # Ok::<_, rune::support::Error>(())
391 /// ```
392 pub fn is_writable(&self) -> bool {
393 unsafe {
394 let shared = self.shared.as_ref();
395 shared.vtable.is_mutable() && shared.access.is_exclusive()
396 }
397 }
398
399 /// Debug format the current any type.
400 pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 vtable(self).debug(f)
402 }
403
404 /// Access the underlying type id for the data.
405 pub fn type_hash(&self) -> Hash {
406 vtable(self).type_hash()
407 }
408
409 /// Access full type info for the underlying type.
410 pub fn type_info(&self) -> TypeInfo {
411 vtable(self).type_info()
412 }
413}
414
415impl<T> fmt::Debug for Shared<T>
416where
417 T: Any,
418{
419 #[inline]
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 self.debug(f)
422 }
423}
424
425impl<T> Drop for Shared<T> {
426 fn drop(&mut self) {
427 // Safety: We know that the inner value is live in this instance.
428 unsafe {
429 AnyObjData::dec(self.shared);
430 }
431 }
432}
433
434#[inline]
435pub(super) fn vtable<T>(any: &Shared<T>) -> &'static AnyObjVtable {
436 unsafe { addr_of!((*any.shared.as_ptr()).vtable).read() }
437}
438
439impl<T> FromValue for Shared<T>
440where
441 T: AnyMarker,
442{
443 #[inline]
444 fn from_value(value: Value) -> Result<Self, RuntimeError> {
445 value.into_shared()
446 }
447}
448
449impl<T> ToValue for Shared<T>
450where
451 T: AnyMarker,
452{
453 #[inline]
454 fn to_value(self) -> Result<Value, RuntimeError> {
455 Ok(Value::from(self.into_any_obj()))
456 }
457}
458
459impl<T> MaybeTypeOf for Shared<T>
460where
461 T: MaybeTypeOf,
462{
463 #[inline]
464 fn maybe_type_of() -> alloc::Result<meta::DocType> {
465 T::maybe_type_of()
466 }
467}
468
469impl<T> TypeHash for Shared<T>
470where
471 T: TypeHash,
472{
473 const HASH: Hash = T::HASH;
474}
475
476impl<T> TypeOf for Shared<T>
477where
478 T: TypeOf,
479{
480 const PARAMETERS: Hash = T::PARAMETERS;
481 const STATIC_TYPE_INFO: AnyTypeInfo = T::STATIC_TYPE_INFO;
482}
483
484impl<T> Clone for Shared<T>
485where
486 T: Any,
487{
488 #[inline]
489 fn clone(&self) -> Self {
490 // SAFETY: We know that the inner value is live in this instance.
491 unsafe {
492 AnyObjData::inc(self.shared);
493 }
494
495 Self {
496 shared: self.shared,
497 _marker: PhantomData,
498 }
499 }
500
501 #[inline]
502 fn clone_from(&mut self, source: &Self) {
503 if ptr::eq(self.shared.as_ptr(), source.shared.as_ptr()) {
504 return;
505 }
506
507 let old = replace(&mut self.shared, source.shared);
508
509 // SAFETY: We know that the inner value is live in both instances.
510 unsafe {
511 AnyObjData::dec(old);
512 AnyObjData::inc(self.shared);
513 }
514 }
515}
516
517impl<T> TryClone for Shared<T>
518where
519 T: Any,
520{
521 #[inline]
522 fn try_clone(&self) -> alloc::Result<Self> {
523 Ok(self.clone())
524 }
525
526 #[inline]
527 fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> {
528 self.clone_from(source);
529 Ok(())
530 }
531}