use std::ops::{Deref, Range};
use rb_sys::{
rb_gc_adjust_memory_usage, rb_gc_count, rb_gc_disable, rb_gc_enable, rb_gc_mark,
rb_gc_mark_locations, rb_gc_register_address, rb_gc_register_mark_object, rb_gc_start,
rb_gc_stat, rb_gc_unregister_address, VALUE,
};
#[cfg(ruby_gte_2_7)]
use rb_sys::{rb_gc_location, rb_gc_mark_movable};
use crate::{
error::{protect, Error},
r_hash::RHash,
symbol::Symbol,
value::{ReprValue, Value, QNIL},
};
#[cfg(target_pointer_width = "64")]
type DiffSize = i64;
#[cfg(target_pointer_width = "32")]
type DiffSize = i32;
pub fn mark<T>(value: T)
where
T: Deref<Target = Value>,
{
unsafe { rb_gc_mark(value.as_rb_value()) };
}
pub fn mark_slice<T>(values: &[T])
where
T: ReprValue,
{
let Range { start, end } = values.as_ptr_range();
unsafe {
rb_gc_mark_locations(
start as *const VALUE,
end as *const VALUE,
)
}
}
#[cfg(any(ruby_gte_2_7, docsrs))]
#[cfg_attr(docsrs, doc(cfg(ruby_gte_2_7)))]
pub fn mark_movable<T>(value: T)
where
T: Deref<Target = Value>,
{
unsafe { rb_gc_mark_movable(value.as_rb_value()) };
}
#[cfg(any(ruby_gte_2_7, docsrs))]
#[cfg_attr(docsrs, doc(cfg(ruby_gte_2_7)))]
pub fn location<T>(value: T) -> T
where
T: ReprValue,
{
unsafe { T::from_value_unchecked(Value::new(rb_gc_location(value.to_value().as_rb_value()))) }
}
pub fn register_mark_object<T>(value: T)
where
T: ReprValue,
{
unsafe { rb_gc_register_mark_object(value.to_value().as_rb_value()) }
}
pub fn register_address<T>(valref: &T)
where
T: ReprValue,
{
unsafe { rb_gc_register_address(valref as *const _ as *mut VALUE) }
}
pub fn unregister_address<T>(valref: &T)
where
T: ReprValue,
{
unsafe { rb_gc_unregister_address(valref as *const _ as *mut VALUE) }
}
pub fn disable() -> bool {
unsafe { Value::new(rb_gc_disable()).to_bool() }
}
pub fn enable() -> bool {
unsafe { Value::new(rb_gc_enable()).to_bool() }
}
pub fn start() {
unsafe { rb_gc_start() };
}
pub fn adjust_memory_usage(diff: DiffSize) {
unsafe { rb_gc_adjust_memory_usage(diff) };
}
pub fn count() -> usize {
unsafe { rb_gc_count() as usize }
}
pub fn stat<T>(key: T) -> Result<usize, Error>
where
T: Into<Symbol>,
{
let sym = key.into();
let mut res = 0;
protect(|| {
res = unsafe { rb_gc_stat(sym.as_rb_value()) as usize };
QNIL
})?;
Ok(res)
}
pub fn all_stats() -> RHash {
let res = RHash::new();
unsafe { rb_gc_stat(res.as_rb_value()) };
res
}