use crate::r_api::Sexp;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ResourceKind {
Null,
Logical,
Integer,
Double,
Character,
LogicalVector,
IntegerVector,
DoubleVector,
CharacterVector,
Generic,
Dataframe,
}
pub struct ResourceState {
pub sexp: Option<Sexp>,
#[allow(dead_code)]
pub kind: ResourceKind,
}
pub struct RxResource {
pub id: u64,
pub state: Mutex<ResourceState>,
pub release_enqueued: AtomicBool,
}
unsafe impl Send for RxResource {}
unsafe impl Sync for RxResource {}
impl RxResource {
pub fn new(kind: ResourceKind) -> Self {
Self {
id: crate::owner::reserve_resource_id(),
state: Mutex::new(ResourceState { sexp: None, kind }),
release_enqueued: AtomicBool::new(false),
}
}
pub fn mark_release_enqueued(&self) -> bool {
self.release_enqueued.swap(true, Ordering::SeqCst)
}
}
impl rustler::Resource for RxResource {}
impl Drop for RxResource {
fn drop(&mut self) {
if self.mark_release_enqueued() {
return;
}
let Ok(mut state) = self.state.lock() else {
crate::owner::record_release_failure(
self.id,
"native R object resource mutex was poisoned during release",
);
return;
};
if let Some(sexp) = state.sexp.take() {
crate::owner::submit_release(sexp as usize, self.id);
} else {
crate::owner::record_release_skipped(
self.id,
"native resource had no R object to release",
);
}
}
}