artichoke_backend/gc/
arena.rs1use std::borrow::Cow;
4use std::error;
5use std::fmt;
6use std::ops::{Deref, DerefMut};
7
8use spinoso_exception::Fatal;
9
10use crate::Artichoke;
11use crate::core::{ClassRegistry, TryConvertMut};
12use crate::error::{Error, RubyException};
13use crate::sys;
14
15#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
19pub struct ArenaSavepointError {
20 _private: (),
21}
22
23impl ArenaSavepointError {
24 #[must_use]
26 pub const fn new() -> Self {
27 Self { _private: () }
28 }
29}
30
31impl fmt::Display for ArenaSavepointError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.write_str("Failed to create internal garbage collection savepoint")
34 }
35}
36
37impl error::Error for ArenaSavepointError {}
38
39impl RubyException for ArenaSavepointError {
40 fn message(&self) -> Cow<'_, [u8]> {
41 Cow::Borrowed(b"Failed to create internal garbage collection savepoint")
42 }
43
44 fn name(&self) -> Cow<'_, str> {
45 "fatal".into()
46 }
47
48 fn vm_backtrace(&self, interp: &mut Artichoke) -> Option<Vec<Vec<u8>>> {
49 let _ = interp;
50 None
51 }
52
53 fn as_mrb_value(&self, interp: &mut Artichoke) -> Option<sys::mrb_value> {
54 let message = interp.try_convert_mut(self.message()).ok()?;
55 let value = interp.new_instance::<Fatal>(&[message]).ok().flatten()?;
56 Some(value.inner())
57 }
58}
59
60impl From<ArenaSavepointError> for Error {
61 fn from(exception: ArenaSavepointError) -> Self {
62 let err: Box<dyn RubyException> = Box::new(exception);
63 Self::from(err)
64 }
65}
66
67#[derive(Debug)]
85pub struct ArenaIndex<'a> {
86 index: i32,
87 interp: &'a mut Artichoke,
88}
89
90impl<'a> ArenaIndex<'a> {
91 pub fn new(interp: &'a mut Artichoke) -> Result<Self, ArenaSavepointError> {
93 unsafe {
94 interp
95 .with_ffi_boundary(|mrb| sys::mrb_sys_gc_arena_save(mrb))
96 .map(move |index| Self { index, interp })
97 .map_err(|_| ArenaSavepointError::new())
98 }
99 }
100
101 pub fn restore(self) {
103 drop(self);
104 }
105
106 #[inline]
111 pub fn interp(&mut self) -> &mut Artichoke {
112 self.interp
113 }
114}
115
116impl Deref for ArenaIndex<'_> {
117 type Target = Artichoke;
118
119 #[inline]
120 fn deref(&self) -> &Self::Target {
121 &*self.interp
122 }
123}
124
125impl DerefMut for ArenaIndex<'_> {
126 #[inline]
127 fn deref_mut(&mut self) -> &mut Self::Target {
128 self.interp
129 }
130}
131
132impl Drop for ArenaIndex<'_> {
133 fn drop(&mut self) {
134 let idx = self.index;
135 let _ignored = unsafe {
138 self.interp
139 .with_ffi_boundary(|mrb| sys::mrb_sys_gc_arena_restore(mrb, idx))
140 };
141 }
142}